webpack.js.org icon indicating copy to clipboard operation
webpack.js.org copied to clipboard

Document why tree shaking is not performed on async chunks

Open jakub-g opened this issue 7 years ago • 7 comments

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.

jakub-g avatar Dec 03 '18 10:12 jakub-g

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.

sokra avatar Dec 03 '18 12:12 sokra

Makes sense, thanks for explanations! 👍

jakub-g avatar Dec 03 '18 12:12 jakub-g

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?

penx avatar Apr 24 '20 14:04 penx

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')

Airkro avatar Jul 30 '20 01:07 Airkro

can a comment annotation be supported? like:

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

toddwong avatar Dec 12 '20 15:12 toddwong

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

sokra avatar Dec 12 '20 18:12 sokra

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

Marvin1003 avatar Mar 08 '22 09:03 Marvin1003