Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using the whitelist option with Babel's external-helpers

I'm trying to use Rollup with Babel's external-helpers. It works, but it's dropping a bunch of babel helpers which I don't even need, for example asyncGenerator.

The docs show a whitelist option but I can't get it to work

rollup.rollup({
    entry: 'src/buttonDropdown.es6',
    plugins: [
        babel({
            presets: ['react', ['es2015', { modules: false }], 'stage-2'],
            plugins: [['external-helpers', { whitelist: ['asyncGenerator'] }]]
        })
    ]
})

The above has no effect: all Babel helpers are still dropped into my resulting bundle.

What is the correct way of using this feature, and is there a full list of which helpers' names the whitelist array takes?

Or is there some other Rollup plugin I should be using with Rollup to automatically "tree shake" the babel external helpers.

like image 529
Adam Rackis Avatar asked Mar 10 '23 22:03

Adam Rackis


2 Answers

As I have found in this particular issue in the GitHub page.

The Babel member Hzoo suggests that

Right now the intention of the preset is to allow people to use it without customization - if you want to modify it then you'll have to just define plugins yourself or make your own preset.

But still if you want to exclude a specific plugin from the default preset then here are some steps. As suggested by Krucher you can create a fork to the undesirable plugin in the following way

  • First one is by forking technique

    "babel": {
    "presets": [
      "es2015"
    ],
    "disablePlugins": [
        "babel-plugin-transform-es2015-modules-commonjs"
    ]
    

    }

But if two or more people want to include the es2015-with-commonjs then it would be a problem.For that you have to define your own preset or extend the preset of that module.

  • The second method would involve the tree-shaking as shown in this article done by Dr. Axel Rauschmayer. According to the article webpack2 is used with the Babel6. This helps in removal of the unwanted imports that might have been used anywhere in the project in two ways

    1. First, all ES6 module files are combined into a single bundle file. In that file, exports that were not imported anywhere are not exported, anymore.
    2. Second, the bundle is minified, while eliminating dead code. Therefore, entities that are neither exported nor used inside their modules do not appear in the minified bundle. Without the first step, dead code elimination would never remove exports (registering an export keeps it alive).

Other details can be found in the article.

Simple implemetation is referred as here.

  • The third method involves creating your own preset for the particular module.

Creating aplugin and greating your own preset can be implemented according to the documentation here

Also as an extra tip you should also use babel-plugin-transforn-runtime If any of your modules have an external dependancy,the bundle as a whole will have the same external dependancy whether or not you actually used it which may have some side-effects.

There are also a lot of issues with tree shaking of rollup.js as seen in this article

Also as shown in the presets documentation

Enabled by default

These plugins have no effect anymore, as a newer babylon version enabled them by default

- async-functions (since babylon 6.9.1)
- exponentiation-operator (since babylon 6.9.1)
- trailing-function-commas (since babylon 6.9.1)**

Also the concept of whitelisting and blacklisting the plugins has benn brilliantly explained by loganfsmyth here in this thread.

you can pass a whitelist option to specify specific transformations to run, or a blacklist to specific transformations to disable.

You cannot blacklist specific plugins, but you may list only the plugins you want, excluding the ones you do not wish to run.

Update :

According to this article here is an important update -

"The --external-helpers option is now a plugin. To avoid repeated inclusion of Babel’s helper functions, you’ll now need to install and apply the babel-plugin-transform-runtime package, and then require the babel-runtime package within your code (yes, even if you’re using the polyfill)."

Hope this may solve your problem

Hope it may help you.

like image 28
Pritish Vaidya Avatar answered Mar 20 '23 14:03

Pritish Vaidya


Problem

The babel-plugin-external-helpers plugin is not responsible for injecting those dependencies in the final bundle. The only thing it controls is that how the generated code will access those functions. For example:

classCallCheck(this, Foo);
// or
babelHelpers.classCallCheck(this, Foo);

It is needed so all rollup-plugin-babel needs to do is to inject babelHelpers in every module.

The documentation is misleading, the whitelist options is not on the external-helpers plugin. It's on the completely separate module and command line tool called babel-external-helpers, which is actually responsible for generating babelHelpers.

It's rollup-plugin-babel what is injecting babelHelpers. And does it using a trick to modularize the final code. It calls babel-external-helpers to generate the helpers, and ignores the whitelist parameter. See my issue requesting to expose an option.

This approach is correct, because rollup will tree-shake the unused helper functions. However some of the helpers (like asyncGenerator) are written in a way that is hard to detect if the initialization has any side effects, thus preventing removal during tree-shaking.

Workaround

I forked rollup-plugin-babel and created a PR which exposes the whitelist option of building babelHelpers in the plugin's options. It can be used this way:

require("rollup").rollup({
  entry: "./src/main.js",
  plugins: [
    require("rollup-plugin-babel")({
      "presets": [["es2015", { "modules": false }]],
      "plugins": ["external-helpers"],
      "externalHelpersWhitelist": ['classCallCheck', 'inherits', 'possibleConstructorReturn']
    })
  ]
}).then(bundle => {
  var result = bundle.generate({
    format: 'iife'
  });
  require("fs").writeFileSync("./dist/bundle.js", result.code);
}).then(null, err => console.error(err));

Note that I didn't publish distribution version on npm, you will have to clone the git repo and build it using rollup -c.

Solution

In my opinion the right solution would be to somehow detect or tell rollup that those exports are pure, so can be removed by tree shaking. I will start a discussion about it on github after doing some research.

like image 70
Tamas Hegedus Avatar answered Mar 20 '23 12:03

Tamas Hegedus