Skip to content
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

Cannot set core-js version for helper-only transformation in @babel/tranform-runtime #9903

Closed
haoqunjiang opened this issue Apr 26, 2019 · 10 comments
Labels
i: enhancement outdated A closed issue/PR that is archived due to age. Recommended to make a new issue

Comments

@haoqunjiang
Copy link
Contributor

Feature Request

Is your feature request related to a problem? Please describe.

Basically we are trying to resolve this issue in @vue/babel-preset-app:

#6628
How can we write ES20xx and ship the smallest amount of code (for a given target environment)?

To be more specific, this item:

  • To achieve that we need to combine @babel/preset-env with @babel/transform-runtime, and the latter one is only used to do helper transformation.
  • The default runtime has a blocking issue though, see 'Symbol' is undefined problem in ie11 #7597
  • So to circumvent it we have to use @babel/runtime-corejs2. I know it's not the best solution but it's an acceptable compromise/tradeoff in practice.
  • Before beta.56 we were able to disable polyfills option while still referring the helper functions to @babel/runtime-corejs2.
  • But after this commit, polyfills option is removed because it is now the default behavior.
  • An unintended consequence is that we can no longer point helpers to any other runtime package without introducing core-js polyfills along with it.

Describe the solution you'd like

Bring back the polyfills option, allowing the user to opt-out it while still being able to specify a core-js version for helpers.

Describe alternatives you've considered
N/A

Teachability, Documentation, Adoption, Migration Strategy
N/A

@babel-bot
Copy link
Collaborator

Hey @sodatea! We really appreciate you taking the time to report an issue. The collaborators
on this project attempt to help as many people as possible, but we're a limited number of volunteers,
so it's possible this won't be addressed swiftly.

If you need any help, or just have general Babel or JavaScript questions, we have a vibrant Slack
community
that typically always has someone willing to help. You can sign-up here
for an invite.

@nicolo-ribaudo
Copy link
Member

As a workaround, you can use https://github.com/tleunen/babel-plugin-module-resolver to alias @babel/runtime -> @babel/runtime-corejs2

@nicolo-ribaudo
Copy link
Member

@sodatea I have been thinking about this issue today, and I think that the proper solution would be to transpile @babel/runtime's helpers using @babel/plugin-transform-runtime itself.
This is tricky, because we should aboud transpiling everything else except for polyfills, to avoid injecting references to themselves inside the helpers.
A working config might look like this:

module.exports = {
  overrides: [{
    // Use exclude or include, but be sure not to transpile those two packages
    exclude: ["@babel/runtime", "core-js"],

    // Your normal config
    presets: ["@babel/preset-env"],
    plugins: ["@babel/plugin-transform-runtime"]
  }, {
    include: "@babel/runtime",
    
    plugins: [
      ["@babel/plugin-transform-runtime", {
        "helpers": false,
        "corejs": 3
      }]
    ]
  }]
};

haoqunjiang added a commit to haoqunjiang/vue-cli that referenced this issue Oct 30, 2019
As recommended in babel/babel#9903.
Get rid of the module-resolver plugin, may fix vuejs#3928.
Seems to have fixed vuejs#4742 as well.
haoqunjiang added a commit to vuejs/vue-cli that referenced this issue Nov 4, 2019
* refactor: use babel overrides to transpile babel runtime helpers

As recommended in babel/babel#9903.
Get rid of the module-resolver plugin, may fix #3928.
Seems to have fixed #4742 as well.

There may be a small breaking change: as we now use `excludes` & `includes`, babel requires `filename` option to be present (introduced in https://github.com/babel/babel/pull/10181/files). So users who call `babel.transformSync` directly may encounter an error.

However, as we explicitly stated that this preset is only used for Vue CLI internally, I don't expect too many such use cases there. And the error messages are clear enough.
Considering the benefits that this PR brings, I think it's an acceptable tradeoff.


 test: update tests for babel

* test: fix windows tests

* test: remove unused variables

* fix: fix scope package paths on Windows

* test: wait some time in router tests in case dom hasn't updated in time
@micopiira
Copy link

micopiira commented Feb 7, 2020

I can't believe how hard was to find this. I found here from @vue/babel-preset-app source code.

Basically all I want to do is to:

  • Include only necessary polyfills for target environment using @babel/preset-env
  • Transform the babel helpers into imports using @babel/plugin-transform-runtime

The problem is that the babel helpers themselves need polyfills when targeting IE 11 for example.

Thanks to this issue & @vue/babel-preset-app source code I somehow managed to get this to work using following configuration:

// babel.config.js
module.exports = {
  sourceType: 'unambiguous',
  overrides: [{
    exclude: [/@babel[\/|\\\\]runtime/],
    presets: [['@babel/preset-env', { useBuiltIns: 'usage', corejs: 3 }]],
    plugins: [
      ['@babel/plugin-transform-runtime', { version: '^7.8.4' }]
    ]
  },
  {
    include: [/@babel[\/|\\\\]runtime/],
    presets: [
      ['@babel/preset-env', {
        useBuiltIns: 'usage',
        corejs: 3
      }]
    ]
  }
  ]
};
// webpack.config.js
module.exports = {
  entry: './src/index.js',
  mode: 'development',
  module: {
    rules: [
      {
        test: /\.m?js$/,
        use: 'babel-loader',
        exclude: file => /node_modules/.test(file) && !/@babel[\/|\\\\]runtime/.test(file)
      }
    ]
  }
};

PLEASE let me know if you know of a better way to achieve this.

@nicolo-ribaudo
Copy link
Member

nicolo-ribaudo commented Feb 7, 2020

Your config looks fine to me: if a dependency (@babel/runtime) uses modern features not supported by your target envs, it should be transpiled.

There were a few problems when transpiling the typeof.js helper from @babel/runtime, but they have been fixed in v7.8.4.

As a personal note, I find this config more explicit:

module.exports = {
  sourceType: 'unambiguous',
  presets: [
    ['@babel/preset-env', {
      useBuiltIns: 'usage',
      corejs: 3
    }]
  ],
  overrides: [{
    exclude: [/@babel[\/|\\\\]runtime/],
    plugins: [
      ['@babel/plugin-transform-runtime', { version: '^7.8.4' }]
    ]
  }]
};

It does the same thing as your config, but makes it explicit that @babel/preset-env is actually applied to every file.

Also, starting from v7.8.4 it's probably safe to transpile @babel/runtime with itself. If it works, this config might be enough:

module.exports = {
  sourceType: 'unambiguous',
  presets: [
    ['@babel/preset-env', {
      useBuiltIns: 'usage',
      corejs: 3
    }]
  ],
  plugins: [
    ['@babel/plugin-transform-runtime', { version: '^7.8.4' }]
  ]
};

@micopiira
Copy link

@nicolo-ribaudo Alright, thanks for your insights!

I also noticed that when setting useESModules: true on plugin-transform-runtime you can leave the sourceType: 'unambiguous' out. useESModules: true seems to produce a slightly larger bundle than just using sourceType: 'unambiguous' . Which one should I use? Or both?

@nicolo-ribaudo
Copy link
Member

useESModules: true should provide a smaller output when using Rollup because it handles ES modules better than CJS.
Webpack 5 might have the same benefit because it concatenates ES modules.

However, if you don't use native ES modules it shouldn't make too much a difference anyway.

@micopiira
Copy link

sourceType @babel/plugin-transform-runtime useESModules result
module FALSE errors
module TRUE 157KiB
unambiguous FALSE 154KiB
unambiguous TRUE 159KiB

Did some tests.. I'm using webpack 4. sourceType: 'unambiguous' + useEsModules: true seems to include both helpers/.js and helpers/esm/.js.

So you should probably use sourceType: 'module' + useESModules: true OR sourceType: 'unambiguous' + useESModules: false

@micopiira
Copy link

micopiira commented Feb 7, 2020

@nicolo-ribaudo I did not have any dependencies other than babel/webpack related. See here https://github.com/micopiira/babel-webpack-test

But using sourceType: 'module' + useESModules: true OR sourceType: 'unambiguous' + useESModules: false the helpers are only included once. Only combination of sourceType: 'unambiguous' + useEsModules: true includes them twice.

@nicolo-ribaudo
Copy link
Member

I'm closing this issue, since it's possible to transpile @babel/runtime with @babel/preset-env to add polyfills.

@github-actions github-actions bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label Jun 13, 2020
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 13, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
i: enhancement outdated A closed issue/PR that is archived due to age. Recommended to make a new issue
Projects
None yet
Development

No branches or pull requests

4 participants