parcel-bundler / parcel

The zero configuration build tool for the web. πŸ“¦πŸš€
https://parceljs.org
MIT License
43.5k stars 2.27k forks source link

Module splitting #4319

Open surma opened 4 years ago

surma commented 4 years ago

πŸ™‹ feature request

Sometimes, the same module is imported by multiple entry points, but they use completely disjoint parts of that module. In theory, the module could be split, minimizing the amount of code loaded for each entry point.

Parcel actually (kinda) does this for small modules. I assume because there is some DCE happening after bundling.

πŸ’» Examples

entry-1.js

import { foo } from './objects.js';
console.log(foo);

entry-2.js

import { bar } from './objects.js';
console.log(bar);

entry-3.js

import { bar } from './objects.js';
console.log(bar, '!');

objects.js

export const foo = { name: 'foo' };
export const bar = { name: 'bar' };

In an example with big modules, objects.js gets chunked out to its own file but contains both exports. It does not get split into two modules.

mischnic commented 4 years ago

I assume because there is some DCE happening after bundling.

Literal AST tree shaking happens after bundling, before that the only DCE that happens is exclusion of reexported assets that are not imported (only for packages with sideEffects: false - e.g. lodash-es).

The question is: how should Parcel know that splitting up a bundle with disjoint imports is better than a regular shared bundle.

surma commented 4 years ago

The question is: how should Parcel know that splitting up a bundle with disjoint imports is better than a regular shared bundle.

Let me put this the other way around: When is is not better? Loading unused code is always worse than not loading it, isn’t it?

mischnic commented 4 years ago

At the bundling stage, we have no idea how well a module will treeshake:

// a.js (will become a bundle)
import {isObject} from "lodash";
// ...

// b.js (will become a bundle)
import {last} from "lodash";
// ...

One might say here: "you're only using one function in each bundle, let's just create two separate bundles". But in reality, Parcel can't treeshake anything here because of how lodash/index.js is structured. So you'd end up downloading all of lodash twice.

With lodash-es, it would work perfectly.