11

Project setup:

  • Vuejs 3
    • Webpack 4
    • Babel
    • TS

We created the project using vue-cli and add the dependency to the library.

We then imported a project (Vue Currency Input v2.0.0) that uses optional chaining. But we get the following error while executing the serve script:

error  in ./node_modules/vue-currency-input/dist/index.esm.js

Module parse failed: Unexpected token (265:36)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|     getMinValue() {
|         let min = this.toFloat(-Number.MAX_SAFE_INTEGER);
>         if (this.options.valueRange?.min !== undefined) {
|             min = Math.max(this.options.valueRange?.min, this.toFloat(-Number.MAX_SAFE_INTEGER));
|         }

I read that Webpack 4 doesn't support optional chaining by default. So, we added the Babel plugin for optional chaining. This is our babel.config.js file:

module.exports = {
  presets: ["@vue/cli-plugin-babel/preset"],
  plugins: ["@babel/plugin-proposal-optional-chaining"],
};

(But, if I am correct, this plugin is now enable by default in the babel-preset. So this modification might be useless ^^)

One thing that I don't understand is that we can use optional chaining in the .vue files.

I created a SandBox with all the files: SandBox

How could I solve this error?

Ludovic Mouline
  • 163
  • 1
  • 6

4 Answers4

10

I was able to overcome this issue using @babel/plugin-proposal-optional-chaining, but for me the only way I could get Webpack to use the Babel plugin was to shove the babel-loader configuration through the Webpack options in vue.config.js. Here is a minimal vue.config.js:

const path = require('path');
module.exports = {
  chainWebpack: config => {
    config.module
      .rule('supportChaining')
      .test(/\.js$/)
        .include
          .add(path.resolve('node_modules/PROBLEM_MODULE'))
          .end()
      .use('babel-loader')
        .loader('babel-loader')
        .tap(options => ({ ...options, 
          plugins : ['@babel/plugin-proposal-optional-chaining']
        }))
        .end()
    }
};

NB replace "PROBLEM_MODULE" in the above with the module where you have the problem.

Surprisingly I did not need to install @babel/plugin-proposal-optional-chaining with NPM. I did a go/no-go test with an app scaffolded with @vue/cli 4.5.13, in my case without typescript. I imported the NPM module that has been causing my grief (@vime/vue-next 5.0.31 BTW), ran the serve script and got the Unexpected token error on a line containing optional chaining. I then plunked the above vue.config.js into the project root and ran the serve script again, this time with no errors.

My point is it appears this problem can be addressed without polluting one's development environment very much.

The Vue forums are in denial about this problem, claiming Vue 3 supports optional chaining. Apparently not, however, in node modules. A post in this thread by atflick on 2/26/2021 was a big help.

Tim Rutter
  • 4,549
  • 3
  • 23
  • 47
JJJSchmidt
  • 820
  • 6
  • 13
  • Many thanks @JJJSchmidt :) It solves my problem better than what I found :) – Ludovic Mouline Jun 21 '21 at 06:48
  • Glad I could help. In a larger project, it helps to focus the loader to work on only offending module(s). I edited the answer to add an `.include` statement to achieve this. I found the babel loader is slow and stumbles on large node modules. Being specific about the target avoids this problem. – JJJSchmidt Jun 23 '21 at 17:02
  • @JJJSchmidt this solution worked for me as well. Cheers! Though I don't understand why **babel.config.js** optional chaining plugin doesn't work: // My babel.config.js: `module.exports = { presets: [ '@vue/cli-plugin-babel/preset' ], plugins: ['@babel/plugin-proposal-optional-chaining'] }` – Pavan J Aug 24 '21 at 13:39
  • 1
    of all the suggestions, this one worked for me with vue@3 and pdfjs-dist. Just remember to replace `'node_modules/PROBLEM_MODULE'` with `"node_modules/pdfjs-dist"` – DerekC Jan 24 '22 at 12:14
  • @DerekC you can also point to the legacy version within the package. the documentation doesn't let you know that you can do ```import * as pdfjs from 'pdfjs-dist/legacy/build/pdf.js'``` instead of ```import * as pdfjs from 'pdfjs-dist'``` the former doesn't have any modern syntax – Da Rod Feb 09 '22 at 16:58
  • thanks @JJJSchmidt! It helped solving same problem in Vue 2 project without TS. Though wondering why setting optional chaining plugin in babel.config did not work – Pavel Gurecki May 11 '22 at 16:32
2

Had same issue with Vue 2 without typescript.

To fix this you need to force babel preset to include optional chaining rule:

presets: [
    [
      '@vue/cli-plugin-babel/preset',
      {
        include: ['@babel/plugin-proposal-optional-chaining'],
      },
    ],
  ],

Can also be achieved by setting old browser target in browserslist config.

Most importantly, you need to add your failing module to transpileDependencies in vue.config.js:

module.exports = {
  ...
  transpileDependencies: ['vue-currency-input],
}

This is required, because babel by default will exclude all node_modules from transpilation (mentioned in vue cli docs), thus no configured plugins will be applied.

Pavel Gurecki
  • 1,091
  • 9
  • 14
0

I had a similar problem. I'm using nuxt but my .babelrc file looks like the below, and got it working for me.

{
  "presets": [
    ["@babel/preset-env"]
  ],
  "plugins":[
    ["@babel/plugin-transform-runtime",
        {
          "regenerator": true
        }
    ]
  ],
  "env": {
    "test": {
      "plugins": [
        ["transform-regenerator", {
            "regenerator": true
        }],
        "@babel/plugin-transform-runtime"
        ],
      "presets": [
        ["@babel/preset-env", {
            "useBuiltIns": false
        }]
      ]
    }
  }
}
Dharman
  • 30,962
  • 25
  • 85
  • 135
RuNpiXelruN
  • 1,850
  • 2
  • 17
  • 23
  • `if (this.options.valueRange?.min !== undefined)` is not the same as `if (!!this.options.valueRange?.min)`. The latter obviously will be false for 0. And `!!` is unneeded in `if` – Estus Flask Jun 17 '21 at 09:53
  • I just tried your solution but I still got the same issue :/ – Ludovic Mouline Jun 17 '21 at 15:12
  • Could you offer some additional explanation please? Did you need to add both the plugin and the preset? How did setting those options e.g. `"regenerator: true` cause the compiler to deal with optional chaining without the `Unexpected token` error? – JJJSchmidt Jun 18 '21 at 20:07
0

I managed to fix the solution by adding these lines to package.json:

...
"scripts": {
   "preinstall": "npx npm-force-resolutions",
   ...
},
"resolutions": {
  "acorn": "8.0.1"
},
...
Ludovic Mouline
  • 163
  • 1
  • 6