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/lazy-entry-eliminated-importers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'vite-plugin-solid': patch
---

Reclassify emitted lazy facade chunks even when their importers are eliminated from the final bundle. Emitted chunk references are now retained so lazy facades can be identified without relying on a surviving `dynamicImports` edge.
3 changes: 1 addition & 2 deletions examples/vite-8/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { onSettled } from "solid-js";
import { CounterProvider, useCounter } from "./CounterContext";

const title = 'Counter';
import { title } from './UnusedLazyImporter';

function Count() {
const counter = useCounter();
Expand Down
3 changes: 3 additions & 0 deletions examples/vite-8/src/UnusedLazy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function UnusedLazy() {
return <p>This lazy component should be removed from the application.</p>;
}
9 changes: 9 additions & 0 deletions examples/vite-8/src/UnusedLazyImporter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { lazy } from 'solid-js';

export const title = 'Counter';

export class UnusedLazyImporter {
mount() {
return lazy(() => import('./UnusedLazy'));
}
}
31 changes: 29 additions & 2 deletions examples/vite-8/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,33 @@ import solidPlugin from 'vite-plugin-solid';

export default defineConfig({
plugins: [
solidPlugin({ compiler: 'native' }),
{
name: 'simulate-eliminated-lazy-importer',
enforce: 'pre',
generateBundle(_options, bundle) {
for (const output of Object.values(bundle)) {
if (output.type === 'chunk') {
output.dynamicImports = [];
}
}
},
},
solidPlugin({ compiler: 'native', ssr: true }),
{
name: 'assert-single-entry',
enforce: 'post',
generateBundle(_options, bundle) {
const entries = Object.values(bundle).filter(
(output) => output.type === 'chunk' && output.isEntry,
);
if (entries.length !== 1) {
throw new Error(
`Expected one entry chunk, received: ${entries
.map((entry) => entry.fileName)
.join(', ')}`,
);
}
},
},
],
});
});
25 changes: 23 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,10 @@ export default function solidPlugin(options: Partial<Options> = {}): Plugin[] {
// Driven from moduleParsed so it covers every lazy() target, including
// import.meta.glob entries that never pass through the moduleUrl transform.
const emittedLazyChunks = new Set<string>();
// Keep the emitted references because a lazy module's importer may be
// removed from the final bundle, leaving no dynamic-import edge to identify
// its facade chunk during generateBundle.
const emittedLazyChunkRefs: string[] = [];

// Whether the current hook invocation belongs to a client (browser) build.
// Builder-mode builds (e.g. SolidStart's nitro plugin) run the client and
Expand Down Expand Up @@ -557,7 +561,9 @@ export default function solidPlugin(options: Partial<Options> = {}): Plugin[] {
if (!/\.[mc]?[tj]sx?$/i.test(cleanId)) continue;
if (emittedLazyChunks.has(depId)) continue;
emittedLazyChunks.add(depId);
this.emitFile({ type: 'chunk', id: depId, preserveSignature: 'exports-only' });
emittedLazyChunkRefs.push(
this.emitFile({ type: 'chunk', id: depId, preserveSignature: 'exports-only' }),
);
}
},

Expand Down Expand Up @@ -623,7 +629,22 @@ export default function solidPlugin(options: Partial<Options> = {}): Plugin[] {
// serialized manifest read back later) so downstream plugins inspecting
// the bundle don't mistake them for application entries. Must precede
// the client asset map build, which keys off dynamic entries.
if (options.ssr) normalizeEmittedLazyEntries(bundle);
if (options.ssr) {
for (const ref of emittedLazyChunkRefs) {
let fileName: string;
try {
fileName = this.getFileName(ref);
} catch {
// Ignore references retained from a previous watch build.
continue;
}
const chunk = bundle[fileName];
if (!chunk || chunk.type !== 'chunk') continue;
chunk.isEntry = false;
chunk.isDynamicEntry = true;
}
normalizeEmittedLazyEntries(bundle);
}
substituteClientManifest(bundle, buildClientAssetMap(bundle, projectRoot, base));
},

Expand Down
Loading