vue-cli: transpileDependencies make commonjs modules conflict with webpack module model

Version

3.0.0-rc.1

Reproduction link

https://gitlab.com/MiausF2E/f2e-todos-cli-demo

Steps to reproduce

  1. comment out process.env.VUE_CLI_BABEL_TRANSPILE_MODULES = true in babel.config.js
  2. yarn serve and take a look in browser console

What is expected?

no error.

What is actually happening?

es6 import conflict with commonjs declaration


I had discussed in #1248, but it seems no response if I don’t file an issue.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 3
  • Comments: 17 (7 by maintainers)

Commits related to this issue

Most upvoted comments

I came across something similar in a topic on forum.vuejs.org and took another look. I think I found the underlying issue with the help of this issue in the webpack repo:

https://github.com/webpack/webpack/issues/4039

The problem

  • We include a commonjs module from node_modules in vue-cli’s transpileDependencies option because it contains code we have to transpile
  • This module contains code that requires a polyfill
  • babel-preset env will inject an import statement into that module for the polyfill
  • because of that, the module is now in strict mode
  • …and in strict mode, exports is readonly.

So we end up with the error:

Cannot assign to read only property 'exports' of object '#<Object>'

Possible Workarounds

useBuiltIns: 'entry'

One workaround is to switch from useBuiltIns: 'usage' (the default for @vue/babel-preset-app ) to useBuiltIns: 'entry'

module.exports = {
  presets: [
    ['@vue/app', {
      useBuiltIns: 'entry'
    }]
  ],

…and add the import '@babel/polyfill' that this setting requires to the top of main.js. The obvious downside is that we probably end up with unnecessary polyfills in our bundle, increasing its size Plus, this workaround doesn’t prevent all edge cases: If the module in question contains code that will make babel insert a helper from transform-runtime (i.e. helpers for class syntax), those will also be injected import statements, again switching the module into strict mode

modules: 'commonjs'

this one is untested, just read about it

By default, our babel preset doesn’t transpile ES6 modules to commonjs, because webpack >=2 understands those and they enable webpack to do tree shaking.

But if we tell babel to transpile all modules to commonjs, we never enter strict mode, so that should also prevent this error.

Can we really fix this?

I don’t think there’s much we can do except maybe document this edge case including possible workarounds, and offer a warning that under some rare circumstances, even that won’t work.

Other ideas?

Yeah, a warning block under transpileDependencies and in the polyfills section would help. Essentially, transpileDependencies would only work for deps with ES module formats.

Also note that:

  • Transpiling all dependencies is bad, because it’s going to be extremely slow.
  • Transpiling everything into CommonJS is also bad, because it breaks tree-shaking and makes your bundle huge.

transpileDependencies is primarily designed for dependencies that ship plain ES2015 code.

babel.config.js

module.exports = {
  presets: [
    ['@vue/app']
  ],
  sourceType: 'unambiguous' // heuristic for every module
}

@yyx990803 @LinusBorg in my project, it’s useful. more

using transpileDependencies option, it’s very likely to transpile module which has already been transpiled. e.g.

  transpileDependencies: [
    'need_transpile_module'
  ],

need_transpile_module/node_module which has already been transpiled will be processed by babel-loader in vue cli, because RegExp is used to decide if module need to transiple

https://github.com/vuejs/vue-cli/blob/0bfc4b684fb48cdb27a5b5102023eec7c7cae8c8/packages/%40vue/cli-plugin-babel/index.js#L4

I tried to write complex regexp to solve it. recently I found sourceType: 'unambiguous' in babel option can solve this problem

https://github.com/babel/babel/issues/9187#issuecomment-447704595

Are these related to this issue? @LinusBorg I think it is necessary to remind people who use transpileDependencies option.

Ok, ran the production and can verify the behaviour. Not sure why that happens / how to handle it right now.

Sidenote: there are actually two things to consider:

1. When not transpiling to commonjs, you can’t use import on a commonjs module.

so this statement;

import prettyMs from 'pretty-ms'

has to be changed to

const prettyMs = require('pretty-ms')

That allows it to compile correctly, but is not the heart of the issue

2. When requiring this module and transpiling, we get this error in the browser:

image

There is an open issue from early 2017 in the webpack repo about this error here, but it’s not clear to me what the status on this is and if it’s really / still a bug, an incompatibility or something resolvable in userland.