Skip to content

Document why tree shaking is not performed on async chunks #2684

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

Open
jakub-g opened this issue Dec 3, 2018 · 7 comments
Open

Document why tree shaking is not performed on async chunks #2684

jakub-g opened this issue Dec 3, 2018 · 7 comments

Comments

@jakub-g
Copy link
Contributor

jakub-g commented Dec 3, 2018

Feature to document

Tree shaking aka dead code elimination

Details

According to this comment, tree shaking is not supported for async chunks, but there's no mention of this in the tree shaking guide.

Additional information

I've read this comment from @sokra but it's quite terse and since the OP deleted his repo, it's not clear to me: does webpack always disable tree shaking for async chunks, or only in case when there are 2+ async chunks which share the same module, say foo.js? Are there any other gotchas to know about?

I can send a patch but I need to understand this better.

@sokra
Copy link
Member

sokra commented Dec 3, 2018

According to this comment, tree shaking is not supported for async chunks

One can't say this in general.

Here are two cases were tree-shaking may not work as expected from user perspective, but there are reasons why it works this way:

import()

import("./a") disables tree-shaking for (and only for) exports of module ./a. Why? Because the returned promise resolves to the namespace object for module a from which all exports can be accessed. webpack doesn't know which export is used and has to include all of them.

Note that tree-shaking is only disabled for exports of module a and will still work for module referenced from module a. When module references only a single exports of module b this will work as expected.

modules in multiple async chunks with difference exports used.

Assuming a module X is used from module A and B. Module A only uses export D and module B only used export E.
In this case module X is generated with both export D and E.
This is true even if module A is only in chunk Y and module B is only in chunk Z. In this case chunk Y and chunk Z may contain the source code of module X.
One might think chunk Y could contain module X with only export D and chunk Z could contain module X with only export E, but this is not correct in most cases.
The reason for this is that webpack can't assume that only chunk Y OR chunk Z is loaded. It has to assume that is can happen that chunk Y AND chunk Z are loaded at the same time. In this case there has to be only a single instance of module X and module X has to be only evaluated/executed as single time. If chunk Y and Z would contain different source code of module X we can't enter a state where module X is only executed as single time and contains both exports. That's why all chunks has to include the same source code for module X.

Note that here one can't say that tree-shaking is disabled. It's more like all used exports of the whole application are merged. So in our scenario module X could contain another export F which would be dropped as unused.

@jakub-g
Copy link
Contributor Author

jakub-g commented Dec 3, 2018

Makes sense, thanks for explanations! 👍

@penx
Copy link

penx commented Apr 24, 2020

So, in your example above, if module B doesn't exist and module A looks like this:

module-A.js

import('./module-X').then(({ exportD }) => ...);

If module-X is only being used by module-A, could a feature be added to webpack to statically analyse this and remove exportE?

@Airkro
Copy link

Airkro commented Jul 30, 2020

How about this pattern:

// page-1.js      define everything in same file

export const route = {
	path: '/page-1',
	...other
};

export function Component(){
	return h('div')
}
// route.js
import { route } from './page-1.js'; // tree shake, route only

const router = [
	{
		...route,
		// tree shake, Component only
		component: import('./page-1.js').then(({ Component }) => Component);	
	}
]

or top-level-await:

const { Component } = await import('./page-1.js')

@toddwong
Copy link

toddwong commented Dec 12, 2020

can a comment annotation be supported? like:

import(/* webpackOnlyImport: A0 */'./A').then(({ A0 }) => ...);

@sokra
Copy link
Member

sokra commented Dec 12, 2020

Yes that was added in the meantime. It's called /* webpackExports: "AO" */

@Marvin1003
Copy link

Is there any workaround to get this working in webpack 4?

jy95 added a commit to jy95/jy95.github.io that referenced this issue Oct 9, 2022
jy95 added a commit to jy95/jy95.github.io that referenced this issue Oct 9, 2022
* chore: npm outdated

* chore: update notistack

* chore: update webpack

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* perf: less bytes for platform icons

* chore: remove constants

* perf: remove useless function

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* chore: add sizes

* chore: refactor

* perf: remove useless props spread operation

* perf: remove dummy workaround

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* chore: npm outdated

* perf: add webpackExports for await import

webpack/webpack.js.org#2684

* chore: npm outdated

* chore: revert to notistack 2.0.5

* chore: revert previous commit

* chore: update package.json
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants