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

Minimize bundle size with tree-shaking #8

Closed
pYr0x opened this Issue Dec 12, 2016 · 8 comments

Comments

Projects
None yet
3 participants
@pYr0x

pYr0x commented Dec 12, 2016

tldr; Update steal-tools build process to support tree shaking.

The RFC for this proposal was discussed on a recent live stream (1:16). It was also discussed on a previous live stream (38:52) and contributors meeting (1:05:29).

The Problem

When using 3rd party libraries you often are only using a portion of the functionality they provide. For example, if you are using a utility library that looks like:

hidash

export function intersection() {
  ...
}

export function flatten() {
  ...
}

But you are only using one of these utility functions like so:

import { flatten } from "hidash";

Even though you are only using one of the utility functions, your bundle will contain all of the code from this library's module.

The Solution

Tree shaking is a technique popularized by rollup that detects this unused code and "shakes" it away (and any code it depends on that is also not used elsewhere).

The other popular bundlers now support tree-shaking. We can piggyback on the libraries already created by others to support it as well.

  • rollup is used internally by WebPack and the SystemJS Builder to treeshake ES modules
  • common-shake is a utility that works with ASTs to tree-shake CommonJS code. As far as I know, no bundler currently uses this under the hood.

Tasks

  • - Research how these libraries are used by bundlers to do treeshaking. I would think that they need access to the entire dependency graph, so we might need to plug this in as a transform that happens after transpile runs in steal-tools.
  • - Create a couple of tests to show this working with ES and CommonJS modules.
  • - Measure: I think presenting to the user how much wasted code was removed by using this technique will be a big benefit.
@matthewp

This comment has been minimized.

Member

matthewp commented Dec 12, 2016

For those unaware, the idea behind tree-shaking is that if you know which exports are used for a module, you can remove the code that is unused. For example:

foo.js

export function a(){}

export function b(){}

bar.js

import { a } from './foo';

Based on the fact that bar.js only uses a, we can remove the code for b (and any code that only b uses).

@matthewp

This comment has been minimized.

Member

matthewp commented Dec 12, 2016

Note that this is much harder for CommonJS because its exports are dynamic, not static like in ES modules. As your link shows, it might be possible with configuration. Steal could support some configuration so that you identify what exports are being used for a dependency, and based on that we would know what code could be removed. It would be quite a burden to maintain that though.

@pYr0x

This comment has been minimized.

pYr0x commented Dec 12, 2016

So you are thinking to only support es2015?

@matthewp

This comment has been minimized.

Member

matthewp commented Dec 12, 2016

Not necessarily. Some CommonJS modules are very static (most probably), it's only the truly dynamic ones that would be impossible to tree shake like:

var foo = require('./foo');

var fn = foo[Math.random()];

In the above we cannot statically determine what of foo's exports are being used, so we have to leave it completely alone. In some other cases we might be able to. But certainly CJS would be much harder, so we'd probably want to do ES modules first.

Regardless I think we can talk about it, and write up an RFC, that is high-level enough that it could be implemented for any format.

The high levels are we should be able to describe what imports a module uses and what exports it exports. Given this metadata we could do some stuff, probably in transpile to remove the unused parts.

@frank-dspeed

This comment has been minimized.

frank-dspeed commented Mar 2, 2017

@matthewp can't we simply https://github.com/google/traceur-compiler and then use es6 for tree shake as rollup does? with the lock file aka registry in rollup context? this would allow to exempt flag real dynamic objects and have also a method for detect if something realy is a dynamic object that gets exported?

@matthewp

This comment has been minimized.

Member

matthewp commented Aug 30, 2017

Update: we're thinking of making this a feature of StealJS 2.0. Both ES and CommonJS tree shaking.

@justinbmeyer justinbmeyer referenced this issue Nov 2, 2017

Closed

Epoch 1 Survey Questions #77

24 of 24 tasks complete
@matthewp

This comment has been minimized.

Member

matthewp commented Nov 29, 2017

This has been written up as an RFC here: #20 . Please comment on the design there and I'll continue to iterate.

See also this repository which goes over a bit more detail in the design and why this algorithm/approach was chosen.

@matthewp

This comment has been minimized.

Member

matthewp commented Jun 15, 2018

This is in steal@pre now.

@matthewp matthewp closed this Jun 15, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment