-
-
Notifications
You must be signed in to change notification settings - Fork 8.7k
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
dynamic import of modules containing same import statements sometimes result in duplicate code generation #13768
Comments
9128254029 |
Which one? |
Yes this might happen as long the shared potion is smaller than 20kb. In this case the optimizer allows duplication to save a request (to the shared chunk). It usually doesn't know that your two
This piece of code isn't super optimal anyway, since it will need two round trips to load both apps. At least you should change it to To solve it you can create a new file Note: webpack might be able to understand |
Thanks @sokra. First ThingYeah I understand your point. After doing the changes you suggested, all node_modules library imports of app and app2 are put down in one chunk: /*!
* Bootstrap v5.0.2 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
...
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
...
/** @license React v17.0.2
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
...
/** @license React v17.0.2
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
...
/** @license React v17.0.2
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
...
/** @license React v0.20.2
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
... But this code: import(/* webpackExports: ["default"] */"./app").then(({default:App})=>{
import(/* webpackExports: ["default"] */"./app2").then(({default:render})=>{ I did it intentionally. Why? Well imagine this scenario: // Import parent dynamically
import("./parent-component").then(({default:ParentComponent})=>{
// After a button click load child dynamically
import("./components/child-component").then(({default:ChildComponent})=>{ Here we cannot put both the components in same file. Is'nt?
So here I guess we might have to change something in webpack configeration that it do not produce shared code at all. Imagine we have a 4 chunks: app, app2, app-lib-code, app2-lib-code So there is a compromise between bandwidth and request. So your suggestion works well if user has a device with good bandwidth. But if he do not then will it not be better to download less code as possible and reuse a chunk. Second ThingAlso one more thing as you can see clearly. Bootstrap, React, React-Dom ..., all endup in single file. Ofcourse these modules do also have their own dependencies. Like bootstrap have dependency on popperjs. And I can see their dependency code in the chunk generated. I saw popperjs code, scheduler code (which is dependency of react-dom I guess), object-assign code (dependency of react), jsx-runtime code (dependency of react). So something like: import { Modal } from 'bootstrap'; will produce this: ... // <-- popperjs code (internal bootstrap dependency)
/*!
* Bootstrap v5.0.2 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
... // <-- bootstap.js code and something like: import React from 'react'; will produce this: /*
object-assign
(c) Sindre Sorhus
@license MIT
*/
... // <-- object-assign code
/** @license React v17.0.2
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
... Can we have a webpack configeration where we have separate chunks for react, react-dom, bootstrap etc? So for eg. if we have somefile.js: // somefile.js
import { Modal } from 'bootstrap';
import React from 'react';
import ReactDOM from 'react-dom'; that can produce four different chunks like:
And of course bootstrap.chunk.js will have its code as well as its internal dependency code (popperjs). Similarly for react and react-dom. Now lets say we have one more file say another.js that has this code: // another.js
import{ useEffect, useState } from 'react';
...
... // jsx code Now the other code in this file use jsx also. Now if previous file (somefile.js) did not have jsx code then react.chunk.js should not have included code for jsx-runtime since webpack did tree shaking. But now this file wants jsx-runtime to be available. Now there is two options:
That's a lot I added. If I am wrong somewhere comments will be helpful. And of course solutions will be great 😉. |
Hi I saw that by using reducing minSize property value we can generate extra chunk without inlining/duplicating it whereever necessary: https://webpack.js.org/plugins/split-chunks-plugin/#splitchunksminsize vendorsAsync: {
test: /[\\/]node_modules[\\/]/,
chunks: 'async',
minSize: 1024,
}, Here I used 1KB size (too small 😜) to prevent duplication. Only 1KB size code wil be inlined I guess now. IKB is. Here are the new chunks (you can see now react dependency has a separate chunk now named - 893.0150aab2b3e6d3935707.js ):
|
Bug report
What is the current behavior?
If we have two modules say A and B. A and B imports react.
During dynamic import of these two module I found react code to be duplicated.
If the current behavior is a bug, please provide the steps to reproduce.
This is the repo link.
This is the source and public.
![image](https://user-images.githubusercontent.com/38173563/125198276-e45d2b80-e27e-11eb-8d10-31077b1b7964.png)
These are the build assets:
src/app.js
chunksrc/app2.js
(showing comments only..):src/app2.js
chunksrc/app.js
(showing comments only..):src/index.js
. It is a entry module.src/index.js
code is included in it. It is a entry module.src/index.js
.As one can see these two chunks: 601.05cbbc0a1fa75c999014.js & 589.7d374a5468098e334db1.js has code in common:
What is the expected behavior?
Webpack should be able to check that if it has generated chunk for library say React, Bootstrap, React-dom etc then it should not generate code again if it founds that library has been imported inside a dynamically imported module.
Other relevant information:
webpack version: ^5.44.0
Node.js version: 14.17.3
Operating System: Windows 10
Additional tools:
The text was updated successfully, but these errors were encountered: