Skip to content
Open
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/eight-months-camp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@solidjs/start": patch
---

Fixed CSS from shared chunks not being collected via the chunk name.
5 changes: 5 additions & 0 deletions apps/fixtures/css/src/components/sharedChunk/lazy1.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import "../../styles/sharedChunk.css";

export default () => {
return <></>;
};
3 changes: 3 additions & 0 deletions apps/fixtures/css/src/components/sharedChunk/lazy2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default () => {
return <></>;
};
13 changes: 13 additions & 0 deletions apps/fixtures/css/src/components/test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,19 @@ export const CommonTests = (props: { routeModuleClass?: string }) => (
</>
}
/>
<Test
component="SharedChunk"
file="sharedChunk.css"
class="sharedChunk"
integration="import"
lazy
comment={
<>
Tests if CSS from shared chunks is server rendered properly. Rollup occasionally combines
modules into such shared chunks.
</>
}
/>
</>
);

Expand Down
6 changes: 6 additions & 0 deletions apps/fixtures/css/src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ const LazyLinkTmp = lazy(() => import("../components/lazyLinkTmp"));
const entries = import.meta.glob("../components/lazyG*.tsx");
const LazyGlob = lazy(Object.values(entries)[0] as any);

const SharedChunk = lazy(() => import("../components/sharedChunk/lazy1"));
// Do not remove this.
// Rollup only creates a shared chunk if there are atleast two modules.
lazy(() => import("../components/sharedChunk/lazy2"));

const getData = query(async () => {
"use server";
await new Promise(res => setTimeout(res, 1000));
Expand All @@ -35,6 +40,7 @@ export default function Home() {
<Show when={!data()}>
<LazyLinkTmp />
</Show>
<SharedChunk />

<Layout title="CSS Tests">
<CommonTests routeModuleClass={classes["route"]} />
Expand Down
3 changes: 3 additions & 0 deletions apps/fixtures/css/src/styles/sharedChunk.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.sharedChunk {
background-color: var(--color-success);
}
18 changes: 18 additions & 0 deletions apps/fixtures/css/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,22 @@ import { solidStart } from "../../../packages/start/src/config";

export default defineConfig({
plugins: [solidStart(), nitroV2Plugin(), tailwindcss()],
build: {
rollupOptions: {
output: {
/**
* Creates a shared chunk with two components. Needed for the "SharedChunk" test!
* The vite manifest behaves differently for such shared chunks.
* More info: packages/start/src/config/lazy.ts
*
* TODO: When switching to Rolldown, migrate this to advancedChunks
* https://vite.dev/guide/rolldown.html#manualchunks-to-advancedchunks
*/
manualChunks(id) {
if (!id.includes("src/components/sharedChunk")) return;
return "shared";
},
},
},
},
});
37 changes: 34 additions & 3 deletions packages/start/src/config/lazy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,43 @@ const fileEndingRegex = /(ts|js)x(\?.*)?$/;

const lazy = (): PluginOption => {
const cwd = process.cwd().replaceAll(osSep, sep);

/**
* Maps module ids to their client-specific shared chunk names.
* Modules in shared chunks need to find their assets via the chunk name, instead of their module id.
*
* Vite includes assets of such modules in the manifest via the chunk name:
* https://github.com/vitejs/vite/blob/4be37a8389c67873880f826b01fe40137e1c29a7/packages/vite/src/node/plugins/manifest.ts#L179
* https://github.com/vitejs/vite/blob/4be37a8389c67873880f826b01fe40137e1c29a7/packages/vite/src/node/plugins/manifest.ts#L319
*
* Rollup occassionally creates shared chunks automatically,
* but they can also be manually created by the user via:
* https://rollupjs.org/configuration-options/#output-manualchunks
*
* More infos on Rollup's logic:
* https://github.com/rollup/rollup/issues/3772#issuecomment-689955168
*/
const sharedChunkNames: Record<string, string> = {};

return {
name: "solid-lazy-css",
enforce: "pre",
applyToEnvironment(env) {
return env.name === VITE_ENVIRONMENTS.server;
generateBundle(_, bundle) {
if (this.environment.name !== VITE_ENVIRONMENTS.client) return;

for (const chunk of Object.values(bundle)) {
if (chunk.type !== "chunk" || !chunk.isDynamicEntry || chunk.facadeModuleId) continue;

// Has to follow Vites implementation:
// https://github.com/vitejs/vite/blob/4be37a8389c67873880f826b01fe40137e1c29a7/packages/vite/src/node/plugins/manifest.ts#L179
const chunkName = `_${basename(chunk.fileName)}`;
for (const id of chunk.moduleIds) {
sharedChunkNames[id] = chunkName;
}
}
},
async transform(src, id) {
if (this.environment.name !== VITE_ENVIRONMENTS.server) return;
if (!id.match(fileEndingRegex)) return;

// The transformed files either import "lazy" or css files
Expand All @@ -66,7 +96,8 @@ const lazy = (): PluginOption => {
const hasDefaultExport = src.indexOf("export default") !== -1;
if (hasDefaultExport) {
const localId = relative(cwd, id);
plugins.push(idTransform(localId));
const chunkName = sharedChunkNames[id];
plugins.push(idTransform(chunkName ?? localId));
}

const hasLazy = src.indexOf("lazy(") !== -1;
Expand Down
Loading