-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
Allow parallel type change bundles to be reused by async siblings #9504
Conversation
I think the issue here is actually earlier. During the initial traversal, we eagerly create bundles for type changes. This will happen when we visit the dependency between async.js and common.css. However that happens before we have collected ancestry information, so we don't know that common.css will actually already be available so that type change bundle is not necessary. |
Do you think this only happens in situations where the two |
@AGawrys I pushed a fix which actually simplifies the whole bundling algorithm a bit as well. Basically, instead of considering type changes as bundle roots and eagerly creating bundles during the first pass (which we have to merge together later), we can delay creating type change bundles until the very end when we are placing assets into bundles. This way we already know all of the ancestry information and can produce more optimal output. If a reachable root for an asset is of a different type, we lazily create sibling bundles of that type (one per bundle group) and reuse them if they already exist (similar to shared bundles). For shared bundles we ensure that all assets are of the same type by adding the type to the unique key. This allows us to remove the type change merging step completely, and rely on shared bundles to handle that. For the most part, the output is the same. However, type change merging previously did not respect the One other difference is that type change bundles could previously be shared between different targets unlike other types of bundles. Actually we created two separate bundles in the ideal graph, but they happened to have the same Let me know if I missed something that would require type changes to be handled early! |
type: 'css', | ||
assets: ['index.module.css'], | ||
type: 'js', | ||
assets: ['a.module.css', 'b.module.css', 'index.module.css'], | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these changes are due to turning on "minBundleSize": 0
}, | ||
{ | ||
type: 'js', | ||
assets: ['esmodule-helpers.js', 'index.js'], | ||
}, | ||
{name: 'Foo.css', type: 'css', assets: ['foo.css']}, | ||
{name: 'entry.css', type: 'css', assets: ['foo.css', 'main.css']}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this was actually a similar case to the one I originally described in the description. foo.css doesn't need to be duplicated because it's already loaded in a parallel bundle
{ | ||
type: 'css', | ||
assets: ['a.module.css'], | ||
}, | ||
{ | ||
type: 'html', | ||
assets: ['searchfield.html'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
above changes are also due to "minBundleSize"
@@ -856,7 +876,7 @@ describe('monorepos', function () { | |||
), | |||
'utf8', | |||
); | |||
assert(contents.includes('import "./pkg-b.cjs.css"')); | |||
assert(contents.includes('import "./pkg-b.module.css"')); | |||
}); | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changes in this file are due to css bundles no longer being reused between different targets, so there is now both a CJS and ESM version
@@ -1137,6 +1137,7 @@ export default class BundleGraph { | |||
? firstAsset | |||
: // Otherwise, find the first asset that belongs to this bundle. | |||
assets.find(asset => this.bundleHasAsset(bundle, asset)) || | |||
assets.find(a => a.type === bundle.type) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixes a separate bug that was exposed by these changes: resolving a dependency to an asset should try to resolve to an asset of the same type as the bundle it's in. without this, there was a crash in the JS packager that resolved an dependency to a CSS asset.
What happens in this test case: See this comment for more context. It is basically a scenario where merging the type bundles causes over fetching, but not merging results in two css bundles for an entry bundle group. |
This makes a lot of sense to me, I always thought we should use ancestry & reachableRoots to determine type change asset placement 🤷
I guess what about naming? I think with the previous implementation we let type bundles have a
That was probably an oversight, I think not sharing between targets generally makes more sense Only question I'm left with is about the over-fetching scenario I commented about above, but that was never handled properly anyway so I don't mind approving this. ✔️ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once this is merged, I can go back into the contrib docs I wrote for the bundler and update the steps/ test cases. LGTM 👍
This is the output: [
{
name: 'entry.js',
type: 'js',
assets: [ 'bundle-url.js', 'cacheLoader.js', 'entry.js', 'js-loader.js' ]
},
{
name: 'Foo.4de85387.js',
type: 'js',
assets: [ 'esmodule-helpers.js', 'index.js' ]
},
{
name: 'index-sib.361c9295.js',
type: 'js',
assets: [ 'index-sib.js' ]
},
{ name: 'entry.css', type: 'css', assets: [ 'foo.css', 'main.css' ] }
] So, Let me know what you think we should do with this one. For now I'll merge this and we can follow up if we want to update that test. |
This is a test for an "issue" (a potential optimization) in the bundler for discussion and eventual fix. As shown in the asset graph below, there's an entry HTML file, with a parallel dependency on a CSS file and a JS file. The CSS file in turn depends on another common CSS file. The JS file has an asynchronous dependency on another JS file, which also imports the common CSS file.
Currently, this results in common.css being broken out into a separate shared bundle, even though it would already be loaded due to the parallel dependency from the HTML file when async.js loads. In other words, I think it should be considered a reachable ancestor from async.js. This does not happen if all of the files are JS files, so I think the type change is throwing it off somehow. @AGawrys any ideas?