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
Option to turn off the "avoiding the waterfall" feature #3062
Comments
I see your point, but I'm not yet sure how useful this actually is, considering there appears to be a single browser that supports As for the deep chunk dependency info, I do not see why adding additional information is needed as this can be aggregated easily by traversing the chunks (and I would also know "how deep" the dependency actually is if I am interested). Considering this is something that would be done in a dedicated plugin anyway, I would prefer to avoid the additional interface if possible.
If that happens, that sounds like a bad implementation of the spec to me (or a problem with the spec, but I hope not). Such a scenario will already happen if a file has many dependencies that again all depend on a third file, e.g. a shared library. I really hope this library will not be processed again once for each import but there is some flag saying "a, we are already working on that". |
Another thing I keep wondering about, totally unrelated to your request but related to what you wrote: Does it really make sense to preload dynamic dependencies? The danger I see is that when the browser is busy pre-loading dynamic dependencies, it may be stealing bandwidth from dependencies I actually need right away to load dependencies I may not need at all and certainly not immediately. Or is the intended course to add the script tags for dynamic dependencies dynamically at some point? |
This was my thought as well when I first learned about the O(n^2) issue, but I was assured by the Chrome engineers who implemented modules that using
I don't think the entire module is processed again, I think it's just that the #internal-module-script-graph-fetching-procedure algorithm needs to be run each time. Re: having a flag indicating that algorithm is being run, I believe the overhead of adding such a flag (queuing a task after completion, etc.) would be similar to the overhead of running the algorithm itself (but that's just my guess, I'd have to ask about that). I'll admit, I'm not sure as to the degree of extra processing this introduces; it could be that the performance impact is only noticeable if the graph is huge. I'm happy to dig further into it though if you'd like.
As a general rule, I don't think it does. The problem is lots of developers use dynamic import as a means of code splitting, e.g. splitting out route-specific code. So in cases where your server is responding with HTML for a specific route, it might make sense to preload those route-specific chunks. For cases where the dynamic import is conditional based on user-interaction, I don't think it makes sense to preload the resource. Or at minimum, you'd:
|
Update: I followed up with some of the Chrome engineers to get to the bottom of the O(n^2) issue with import statements, and it turns out what I was initially told was not fully correct. To summarize the main takeaways of our conversation:
I do still think an option to turn the feature off would be nice (it makes the files smaller if you're already implementing |
Unsafe ‘waterfall avoidance’ hoisting has led to three bugs for us in six months. Each time it was that modules (without side effects of their own) were being hoisted above modules with important side effects (polyfills, etc). We also get no benefit from this. The modules in question have always already been sent with http2 server push or are available in the service worker cache. It would be great if we could disable this. (If anyone has immediate advice, something they know I can do to force this import hoisting to respect side effect ordering, I’d be forever grateful.) |
I just spent the last couple of days trying to figure out why my rollup builds with My scenario is that I am attempting to use rollup to shake an ESM module graph and convert it to a different format (AMD) before handing it off to an existing bundler, in order to facilitate migrating to a pure-ESM development flow. Unfortunately, due to the behavior of this "feature", my resulting modules contain much more code than they did originally (due to all the extraneous imports), which makes the approach a non-starter due to inflating the resulting bundles. The modules will end up being bundled into the same file anyway, so the extra imports just result in requirejs doing significant unnecessary work. I would very much appreciate being able to turn this function of rollup off via config, or if there is a hook I can use to remove imports of side-effect free modules categorically via plugin? |
Fix at #3353. There should be some comments form my side, though:
I am nearly 100% sure that this has nothing to do with import hoisting. Import hoisting does not affect the execution order at all. The problem is instead that Rollup does not guarantee exact execution order when either external dependencies or code-splitting involved. I am quite sure, though, that #3354 will improve the situation for you. I added an FAQ section to explain how to add polyfills and why there could be issues: https://github.com/rollup/rollup/pull/3353/files#diff-4c58bec2df8beef1009c4ed8f417566eR66-R98 The solution (add it to each static entry first) will work once #3354 is released. Also have a look at the example in the description of #3354 to understand the issue better.
I am sorry to tell you that |
@lukastaegert Thanks! It’s definitely possible (and, given what you said, apparently very likely) that I was too quick to identify the incorrect ordering behavior as hoisting. IIRC when I wrote that it was after a few hours of There are no external deps in play in our case, but we do have a bunch of dynamic imports — which in turn import modules that are imported by other chunks. It looked very much like the polyfill example in #3354. Thanks immensely for identifying and fixing the actual issue. |
Feature Use Case
I recently started noticing a lot of import statements in my built modules that don't actually import any symbols. Here's an example:
When I started looking into why, I realized this is actually intended to be a feature: "avoiding the waterfall"
At first I thought this was really cool, but then, based on some stuff I learned from some Chrome engineers who implemented modules, I realized this probably isn't a good practice. What developers should really be using to avoid the waterfall is
modulepreload
(which works for both static and dynamic imports, viaLink
headers).The problem with using "real" imports to preload a bunch of modules is, when fetching them, the spec says to run the
#internal-module-script-graph-fetching-procedure
algorithm, and when usingmodulepreload
, the spec says to run the#fetch-a-single-module-script
algorithm. The former algorithm will also fetch sub-dependencies, while the later algorithm will only fetch the single module.The problem with running the
#internal-module-script-graph-fetching-procedure
algorithm on a bunch of modules that likely have common sub-dependencies is you'll end up processing many of those sub-dependencies more than once, so the processing time ends up being O(n^2) rather than O(n) formodulepreload
.Feature Proposal
While the current approach is probably better than a completely unoptimized load (without
modulepreload
), it's worse than an optimized load (because of the O(n^2) issue mentioned and the fact that the file sizes are larger than they need to be).As a result, I propose Rollup add an option to turn off this feature (it's something
modulepreload
plugins could turn off automatically for users of their plugins).As long as
ChunkInfo.imports
contains the complete (deep) graph of all imports needed for a particular entry chunk, it should be easy enough for developers to generate their ownmodulepreload
lists. However, if removing the imports-as-modulepreload statements from the final output also means they're removed from theChunkInfo.imports
object, I'd also suggest adding another property (perhapsimportsDeep
) to theChunkInfo
object, so it continues to be easy to generate amodulepreload
list from thebundle
object.What do you think?
The text was updated successfully, but these errors were encountered: