Open use opened 3 years ago
The extra chunk can exist because of common dependencies of your entrypoints including src/js/theme.js
and the dynamic-imported ones.
Let me give you a minimal example:
// a.js
import { d } from "./c.js"
console.log('a', d)
import("./b.js")
// b.js
import { c } from "./c.js"
console.log('b', c)
// c.js
export const c = 1
export const d = 2
As you can see both a.js and b.js depend on c.js, turns out c.js is a common chunk. So:
// esbuild a.js --bundle --format=esm --splitting --outdir=dist --analyze
dist/a.js 100b 100.0%
└ a.js 58b 58.0%
dist/b-63JZQOHX.js 73b 100.0%
└ b.js 21b 28.8%
dist/chunk-XF7GIIAF.js 52b 100.0% // <- see, it doesn't has a name
└ c.js 22b 42.3%
The output code is almost the same as the input ones. Now you may know how esbuild's code splitting works.
Code splitting splits on any shared code, either statically or dynamically imported. This is documented here: https://esbuild.github.io/api/#splitting. This behavior is intended. It both reduces downloaded code when moving between entry points on different pages and fixes correctness issues due to duplicate module instantiation if multiple entry points are included in the same page (either static or dynamic).
In my situation I only ever have 1 entry point. With these chunks being splitted, every page has 5 "extra" chunks which get downloaded. I'm working with the assumption that I should avoid extra requests within reason, but also avoid downloading + parsing unneeded code (hence why I am using splitting).
Maybe there's a different way I should structure things?
Or am I overvaluing the downsides of downloading e.g. 5 extra small chunks?
While the implementation seems very efficient, it slightly misses the point: reducing load times. The few kb saved by splitting everything up into multiple chunks make up less of an impact than the sequential import of said chunks, which is inevitable using ESM imports; The browser can't parallelize the downloads. The usual application has one entry, with peripheral content like async components, pages or widgets. Coming from Rollup, this is how developers are used to the concept.
While the implementation seems very efficient, it slightly misses the point: reducing load times. The few kb saved by splitting everything up into multiple chunks make up less of an impact than the sequential import of said chunks
+1. By default esbuild seems to chunk even the slightest amount of data.
Webpack has a default specific set of criteria on when it chunks - it prefers bigger chunks because it's actually counterintuitive to create lots of mini chunks when they are small because the additional HTTP overhead outweighs simply inlining that chunk.
I would love for esbuild to provide more control over when it decides to chunk. E.g. only chunk for files larger than 5KB, chunk together if they are in node_modules
, etc.
Overall this issue relates to: #207 - being able to configure when chunking occurs, much like Webpacks splitChunks
config.
+1 for having some way to disable static chunks, e.g. split only on dynamic imports, even sacrificing the correctness of the import order and code size.
With a not-too-complex real-world application, we're getting tons of tiny chunks:
Seems like an issue to us too... Our build produces 91 chunks, about 50% of those are 1kb or smaller
Figma is also trying to migrate to a splitting solution, and we are also producing a lot of chunks (I think in testing, we are at 20 critical chunks). For every dynamic import we add, we increase the number of emitted chunks by a large amount. I suspect it will get even worse as we add more dynamic imports, because the number of permutations increases.
I think adding at least a minChunkSize
would go a long way here, even if the browser ends up having to download slightly more code. Is addressing this on the roadmap at all?
Hello,
I'm 100% sure this is something I'm doing wrong but I was wondering if someone can point me in the right direction?
I'm coming from a webpack config, if that helps.
Here is my esbuild command:
I'm using codesplitting so I can dynamically load chunks when they're needed. I'm using the dynamic import() function. This actually works great. Those chunks look like this in the --analyze output:
However, I'm also getting "unintended" chunks. I am not loading them dynamically in any way that I'm aware of - they're being imported with plain old static import. The outputted chunks look like the following. Notably, the chunks have no real name in the prefix.
I guess my expectation is that when I use static import, the bundler would inline those modules rather than splitting and dynamically loading them. And I can't figure out why these statically loaded modules are being split into chunks.