Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/tidy-bags-listen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@solidjs/start": patch
---

Prefix production entry scripts, stylesheets, modulepreloads, and serialized manifest paths with Vite's configured base URL.
82 changes: 82 additions & 0 deletions packages/start/src/server/manifest/prod-ssr-manifest.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { beforeEach, describe, expect, it, vi } from "vitest";

vi.mock("solid-start:client-vite-manifest", () => ({
clientViteManifest: {
"src/entry-client.tsx": {
file: "_build/assets/entry-client.js",
css: ["_build/assets/entry-client.css"],
imports: ["_shared.js"],
isEntry: true,
},
"_shared.js": {
file: "_build/assets/shared.js",
},
},
}));

vi.stubEnv("START_CLIENT_ENTRY", "./src/entry-client.tsx");

const { getSsrProdManifest } = await import("./prod-ssr-manifest.ts");

describe("getSsrProdManifest", () => {
beforeEach(() => {
vi.stubEnv("BASE_URL", "/foo/");
});

it("prefixes entry paths with the Vite base", () => {
expect(getSsrProdManifest().path("./src/entry-client.tsx")).toBe(
"/foo/_build/assets/entry-client.js",
);
});

it("prefixes stylesheet and modulepreload URLs with the Vite base", async () => {
const assets = await getSsrProdManifest().getAssets("./src/entry-client.tsx");

expect(assets).toEqual([
{
tag: "link",
attrs: {
href: "/foo/_build/assets/entry-client.css",
key: "_build/assets/entry-client.css",
rel: "stylesheet",
},
},
{
tag: "link",
attrs: {
href: "/foo/_build/assets/shared.js",
key: "_build/assets/shared.js",
rel: "modulepreload",
},
},
{
tag: "link",
attrs: {
href: "/foo/_build/assets/entry-client.js",
key: "_build/assets/entry-client.js",
rel: "modulepreload",
},
},
]);
});

it("prefixes serialized manifest paths with the Vite base", async () => {
await expect(getSsrProdManifest().json()).resolves.toMatchObject({
"src/entry-client.tsx": {
output: "/foo/_build/assets/entry-client.js",
},
});
});

it("preserves root-based URLs when the Vite base is root", async () => {
vi.stubEnv("BASE_URL", "/");
const manifest = getSsrProdManifest();

expect(manifest.path("./src/entry-client.tsx")).toBe("/_build/assets/entry-client.js");
await expect(manifest.getAssets("./src/entry-client.tsx")).resolves.toMatchObject([
{ attrs: { href: "/_build/assets/entry-client.css" } },
{ attrs: { href: "/_build/assets/shared.js" } },
{ attrs: { href: "/_build/assets/entry-client.js" } },
]);
});
});
6 changes: 3 additions & 3 deletions packages/start/src/server/manifest/prod-ssr-manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function getSsrProdManifest() {
const viteManifestEntry = clientViteManifest[id /*import.meta.env.START_CLIENT_ENTRY*/];
if (!viteManifestEntry) throw new Error(`No entry found in vite manifest for '${id}'`);

return join("/", viteManifestEntry.file);
return join(import.meta.env.BASE_URL, viteManifestEntry.file);
},
async getAssets(id) {
if (id.startsWith("./")) id = id.slice(2);
Expand All @@ -29,7 +29,7 @@ export function getSsrProdManifest() {

for (const entryKey of entryKeys) {
json[entryKey] = {
output: join("/", viteManifest[entryKey]!.file),
output: join(import.meta.env.BASE_URL, viteManifest[entryKey]!.file),
assets: await this.getAssets(entryKey),
};
}
Expand All @@ -54,7 +54,7 @@ function createHtmlTagsForAssets(assets: string[]) {
.map<Asset>(asset => ({
tag: "link",
attrs: {
href: "/" + asset,
href: join(import.meta.env.BASE_URL, asset),
key: asset,
...(asset.endsWith(".css") ? { rel: "stylesheet" } : { rel: "modulepreload" }),
},
Expand Down
Loading