-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
Which component is affected?
Qwik Runtime
Describe the bug
Running a client build for a qwik app in 1.16 (or 2.0.0-beta-7) results in an incorrect q-manifest which results in an inaccurate bundle-graph. This is because Rollup's generateChunks merges static node_modules into manualChunks bundles aliases.
Reproduction
https://github.com/maiieul/qwik-overpreloading-inaccurate-bundle-graph-static-imports-graph
Steps to reproduce
Run build.client look at the "alert.tsx_Description_component_MExiH8uFvn4.js" component in the q-manifest. It includes the orgins for a lot of node_modules (e.g tailwind-merge, css-tree, etc.). Those are imported by @qwik-ui/utils which the Alert component is importing. The problem is that when rollup sees this, it merges the @qwik-ui/utils node_modules into the "alert.tsx_Description_component_MExiH8uFvn4.js" bundle, even though the node_modules in question are also used in other bundles, resulting in those other bundles importing "alert.tsx_Description_component_MExiH8uFvn4.js" and its static+dynamic dependencies.
Tip: you can run the debugger build.client from within vscode to see this in action.
System Info
🙈Potential solutions
We can solve this in two ways:
1) fix Rollup
The problem comes from generateChunks -> getChunkAssignments -> getChunkDefinitionsFromManualChunks -> addStaticDependenciesToManualChunk -> if (!(dependency instanceof ExternalModule || modulesInManualChunks.has(dependency))) modulesToHandle.add(dependency).
We can fix it by removing the addStaticDependenciesToManualChunk logic.
2) Improve our manualChunks logic
The current manualChunks logic will take related QRL segments outputs from the optimizer, and merge them together:
const { pathId } = parseId(id);
const segment = segments.get(normalizePath(pathId));
if (segment) {
const { hash } = segment;
const chunkName = (opts.entryStrategy as SmartEntryStrategy).manual?.[hash] || segment.entry;
if (chunkName) {
return chunkName;
}
}This not only works for the app's QRL segments, but also for node_modules QRL segments (e.g. import { Accordion } from "@qwik-ui/headless"; will contain many segments.
This means that for the remaining non QRL ids and node_modules ids, we can safely return them into separate bundles and group node_modules by name, taking into account their size.
Solution 2 gives us more control, but we might end up bundling together bundles that were explicitly set to be separate by a library, or create multiple bundles for code that will always be used together.
Edit: updated solution 1.