-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature] Code splitting on async import() statements. #16
Comments
This is definitely something I plan to get to because I want to be able to use it myself. Right now |
@evanw do you have any kind of roadmap somewhere for esbuild? I am particularly interested in this feature, and would be cool to know where it is in terms of planning. Cheers. |
This would be awesome to have! |
I don't have a specific date but I'm currently focused on a rewrite of the bundler to enable code splitting, tree shaking, ES6 module export, and a few other features. I have to do these together because they are all interrelated. I've done the R&D prototype to prove it out and I've settled on an approach. I'm currently working on doing the rewrite for real on a local branch. There's still a lot left to do to not break features I've added in the meantime (stdin/stdout support, transform API, etc) so it'll take a while. I have a lot of test failures to work through :) I was worried about the performance hit because the graph analysis algorithms inherently reduce parallelism, but some early performance measurements seem to indicate that it won't slow it down that much, if any. I hope to ship this sometime in the next few weeks. We'll see how it goes! |
Damn! You're the man. This is the only thing I am missing to start using it in production, in smaller projects for starters, and see how it goes. PS: Have tested a couple locally, without code splitting, and everything worked flawlessly, even in one with a fairly large codebase using react and typescript. 👍 |
Hello here, |
It's mostly working already. The chunk splitting analysis has already landed. All that's left is to bind imports and exports across chunks. I'm working on that in a branch and this will be my main focus soon. |
I just released version 0.5.15 with an experimental version of code splitting. See the release notes for details. It's still a work in progress but it's far enough along now that it's ready for feedback. Please try it out and let me know what you think. |
Excellent news! Thank you for all your hard work on this Evan. Code splitting was vital for us. Does this code splitting feature split css imports into seperate files and add at runtime? Simple CSS support is the next main thing we are eaglerly looking forward to. |
You and me both! CSS support is currently the next major feature I want to implement after code splitting. That’s tracked by a separate issue, however: #20. |
Works really well in initial testing. We will test more complicated setups (rush repo, nested pnpm deps) more fully in the next weeks |
That's great to hear! Thanks so much for trying it out. |
I have a small progress update on code splitting. From the release notes for the upcoming release (not out yet):
|
@evanw Thanks a lot for this detailed write-up ! This is the kind of information required for using a tool such as this. |
Another code splitting update: I finally got around to implementing per-chunk symbol renaming, which I view as required for the code splitting feature. I've made several attempts at this in the past but I haven't landed them because I don't want to severely regress performance (or memory usage, which I've started to also pay attention to). I finally figured out a good algorithm for doing per-chunk symbol renaming that's fast and parallelizable while not using too much memory. It's actually two algorithms, one when minifying and a different one when not minifying. From the release notes:
|
@evanw it would be very interesting if you could expand somewhere on the exact symbol naming technique you converged on here. I'm sure it will make sense looking at the outputs too though of course. |
I just wrote up some documentation about the parallel symbol minification algorithm here. The non-minified symbol renaming algorithm isn't described in the docs yet but it's pretty simple. Just rename symbols to avoid collisions by appending an increasing number to the name until there's no longer a collision. Each symbol will need to check for collisions in all parent scopes. Symbols in top-level scopes must be renamed in serial but symbols in nested scopes can be renamed in parallel. |
@evanw Do you plan on supporting code splitting with other formats apart from esm? |
If the file contents are included in the hash, does that imply that circular references cannot be built (since each file contains a reference to another)? Or is the hash calculated before rewriting the imported filenames? |
Yes, code splitting currently generates an acyclic module graph. The current automatic code splitting algorithm makes sure that a) a given piece of code only ever lives in one chunk and b) a given entry point doesn't import any code that it won't use. This means it generates one chunk for each unique overlap of entry points. So if there are three entry points A, B, and C, that means there could potentially be up to 7 chunks: A, B C, A+B, A+C, B+C, and A+B+C. The chunk for A would only include code accessible by A but not by B or by C, the chunk A+B includes all code accessible by A and B but not by C, and the chunk A+B+C is for all code that is used by all entry points. Because of this structure, cyclic imports are not ever generated by construction. Two chunks wouldn't ever need to import each other because if they do reference each other, they would be considered a connected component in the graph and would have been written out as part of the same chunk. This automatic algorithm was a good experiment but it has some drawbacks. The main drawback is just that it's automatic. Many people want to have control over the algorithm in various ways. With many entry points, I'm sure you can see how the current algorithm can potentially generate a lot of chunks due to the combinatorial explosion of overlaps. People familiar with ESM have said that this is fine since the browser can handle a lot of chunk files (>100). Other people are turned off by the idea of having lots of generated chunks and have been requesting manual control over chunk files. Potentially people are just more used to fewer chunks from Webpack setups with manual chunk generation and lack of HTTP/2. I'm not sure what to think about the trade-offs between these approaches because I haven't done extensive performance analysis myself. To implement manual chunk assignment you would two things:
That's where my thinking is at the moment. I'm currently in the design phase for the next version of code splitting. The next iteration should hopefully finish the code splitting feature. I want to address the current known import ordering bug, get code splitting working for the Edit: part of why I'm posting this is that I'm curious what people think about the path embedding approach vs. the import map approach. |
@pablo-mayrgundter You need to use a newer target which supports dynamic import ( |
@evanw i have a different use-case from above, i have this dynamic import
problem is that esbuild is bundling all the icons into the index.js file rather than keeping them in a separate file. is it possible to say this should stay as it is. |
Trying to track down a recent update on "Code splitting is still a work in progress. It currently only works with the esm output format. There is also a known ordering issue with import statements across code splitting chunks." Is a fix for these issues planned? |
I switched to code splitting on dynamic imports but now I've come across a strange bug, has anyone seen this before? const { parse } = await import('css-what')
parse(selector)
I don't think this is a bug with |
@mattfysh If you're using node.js to run this code, then this is because node.js ignores the import {parse} from "css-what/lib/es/index.js" If you're using esbuild to bundle the code with For package authors: If you really want users to use the native ESM way to use your package, at least do this: "exports": {
"node": {
"import": "./dist/index.mjs",
"require": "./dist/index.js"
},
"default": "./dist/index.mjs"
} More details at doc: how-conditions-work. |
thanks @hyrious - the fix for my case was to use the |
Is there any way to control the code-splitting to only look at async/dynamic imports? |
If you bundle each entry point separately, then entry points won’t share any code. |
Not sure I fully understand that, but I tried setting up separate entry points for a couple of my dynamic And if I try to use |
cjs can also use |
One important caveat is that if you're importing entry points dynamically, you need to make sure that they are marked as external. For example, if
You would need to make sure that your |
Is this still WIP? |
Initially meant to be posted here #1341 In my case, I needed to bundle dependencies and chunk them, while keeping the output files separate (not one big bundle). All that works except that only Definitely not ideal, I can live with it. export const esmSplitCodeToCjs: esbuild.Plugin = {
name: 'esmSplitCodeToCjs',
setup(build) {
build.onEnd(async (result) => {
const outFiles = Object.keys(result.metafile?.outputs ?? {})
const jsFiles = outFiles.filter((f) => f.endsWith('js'))
await esbuild.build({
outdir: build.initialOptions.outdir,
entryPoints: jsFiles,
allowOverwrite: true,
format: 'cjs',
logLevel: 'error',
})
})
},
} |
I have the same issue. It splits |
@evanw whats the current status on enabling code splitting with |
@evanw whats the current status on enabling code splitting with cjs format? |
Use tsup IMO this issue can be closes as not planned |
Safari added full ES module support with Safari 11, released sep 2017. When the issue was opened in 2020, safari 10.x probably was inside the support matrix for quite a few users (it still was for us. way too many iMac users back then stuck on that version reporting issues) But shouldn't almost everyone be able to switch to ES Modules in their pipelines by now? I'd think there are much more interesting issues in esbuild to solve than 'backporting' split support to CJS |
Support code splitting on dynamic import() statements, and additionally split/join on shared bundles for shared dependency models.
The text was updated successfully, but these errors were encountered: