简体   繁体   中英

Babel: can't get “@babel/plugin-transform-destructuring” plugin to work

I'm trying to load my ReactJS web app in iOS 10 Safari on a relatively old iPad (I use webpack and babel-loader, and serve it using webpack-dev-server).

I'm getting the following Syntax error:

SyntaxError: Unexpected token '...'. Expected a property name.

(The page loads fine on all devices/browsers I've tried so far.)

The error is caused by this line of transpiled code:

eval("\\nconst publicIp = __webpack_require__(/*! public-ip */ \\"./node_modules/public-ip/browser.js\\");\\n\\nconst isOnline = async options => {\\n\\toptions = {\\n\\t\\ttimeout: 5000,\\n\\t\\tversion: 'v4',\\n\\t\\t...options\\n\\t};\\n\\n\\ttry {\\n\\t\\tawait publicIp[options.version](options);\\n\\t\\treturn true;\\n\\t} catch (_) {\\n\\t\\treturn false;\\n\\t}\\n};\\n\\nmodule.exports = isOnline;\\n// TODO: Remove this for the next major release\\nmodule.exports.default = isOnline;\\n\\n\\n//# sourceURL=webpack:///./node_modules/is-online/browser.js?");

where we can observe as seen in the source https://github.com/sindresorhus/is-online/blob/master/browser.js :

const isOnline = async options => {
    options = {
        timeout: 5000,
        version: 'v4',
        ...options
    };

    // ...
};

Looks to me like object destructuring using the ... spread operator is not supported. The code is from a npm module I'm using called "is-online".

I tried adding the "@babel/plugin-transform-destructuring" plugin to .babelrc to see if it could solve this. Everything compiled but this part of code was identical, so it still produced the same error.

I found this Twitter conversation describes the same problem and also with Safari, yet he managed to solve it because he "needed to also activate the transform plugin for it: transform-object-rest-spread":

https://twitter.com/beberlei/status/984083670012256258

So I tried it and it didn't work.

Then I stepped up my plugins game in .babelrc and after searching for similar cases online, trying different configs, updating babel using npx babel-upgrade , deleting and reinstalling node_modules and putting the plugins direclty into module.rules[0].options.plugins I gave up on it with:

// .babelrc

{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react"
    ],
    "plugins": [
        "@babel/plugin-transform-spread",
        "@babel/plugin-transform-destructuring",
        "@babel/plugin-transform-parameters",
        "@babel/plugin-proposal-object-rest-spread",
    ]
}

...but it still gives the error. It also tried to put "@babel/plugin-transform-runtime" in there: same.

My webpack config as of right now:

// webpack.dev.js

const path = require("path");
const webpack = require("webpack");

const TerserPlugin = require('terser-webpack-plugin');

module.exports = [

    // App

    {

        mode: 'development',

        entry: {
            app: "./src/index.js"
        },

        module: {
            rules: [
                {
                    test: /\.(js|jsx)$/,
                    exclude: /(node_modules|bower_components)/,
                    loader: "babel-loader",
                    options: {
                        presets: ["@babel/env"],
                    }
                },
                {
                    test: /\.css$/,
                    use: ["style-loader", "css-loader", "postcss-loader"]
                },
                {
                    test: /\.(png|svg|jpg|gif)$/,
                    use: [
                        'file-loader'
                    ]
                }
            ]
        },

        resolve: { extensions: ["*", ".js", ".jsx"] },

        output: {
            filename: "app-v0.9.6.js",
            path: path.resolve(__dirname, "public/dist/"),
            publicPath: "/dist/"
        },

        plugins: [new webpack.HotModuleReplacementPlugin()],

        devServer: {
            host: '0.0.0.0',
            disableHostCheck: true,
            port: 80,
            contentBase: path.join(__dirname, "public/"),
            publicPath: "http://localhost:3000/dist/",
            hotOnly: true
        },

// Fixes Safari 10-11 bugs
// Has nothing to do with this question: already tried to comment this out
        optimization: {
            minimizer: [new TerserPlugin({
                terserOptions: {
                    safari10: true,
                },
            })],
        },
    },

    // Library

    {

        mode: 'development',

       // ... 
       // another output that's exposed as a global variable (library)

    }
];

Here are the dev dependencies:

// package.json

...

  "devDependencies": {
    "@babel/cli": "^7.5.5",
    "@babel/core": "^7.5.5",
    "@babel/plugin-proposal-object-rest-spread": "^7.0.0",
    "@babel/plugin-transform-destructuring": "^7.0.0",
    "@babel/plugin-transform-parameters": "^7.0.0",
    "@babel/plugin-transform-runtime": "^7.5.5",
    "@babel/plugin-transform-spread": "^7.0.0",
    "@babel/preset-env": "^7.0.0",
    "@babel/preset-react": "^7.0.0",
    "babel-loader": "^8.0.6",
    "babel-preset-env": "^1.7.0",
    "css-loader": "^3.2.0",
    "file-loader": "^4.2.0",
    "html-webpack-plugin": "^3.2.0",
    "postcss-loader": "^3.0.0",
    "style-loader": "^0.23.1",
    "webpack": "^4.39.1",
    "webpack-cli": "^3.3.6",
    "webpack-dev-server": "^3.8.0",
    "webpack-merge": "^4.2.1"
  },

...

If someone knows how to configure it correctly I'd be very grateful.

So as you understood, uses of the “ES2018 spread syntax in object literal” (aka ellipsis) from a module you imported are leaking into your transpiled bundle, thereby upsetting the most pitiful browsers. Which happens because:

Webpack is set to ignore your node_modules , so is-online does not get transpiled.

Here's a practical solution for you -- modify the exclude rule of your webpack.config.js as follows:

exclude: /(node_modules\/(?!is-online)|bower_components)/,

Aka. “exclude bower_components, and all node_modules except for is-online”

Just in case -- to exclude more modules, write:

exclude: /(node_modules\/(?!is-online|another-es6-module|yet-another-one)|bower_components)/,

There may be more pretty ways to put it; if you're an aesthete, try your luck here .

Once done, check the output file for the string "..." . Hopefully it's gone!

If you feel fancy, you could automate that checking the output for "..." after each build so as to be sure not to miss any module. But then again, it would fire on legit string literals containing ellipses...

Phew! I almost thought other forces were at play ...


Old response due to error in question:

Your fat-arrow function returns an object literal that's not wrapped in parentheses.

Mozilla says:

Returning object literals

Keep in mind that returning object literals using the concise body syntax params => {object:literal} will not work as expected.

 var func = () => { foo: 1 }; // Calling func() returns undefined! var func = () => { foo: function() {} }; // SyntaxError: function statement requires a name 

This is because the code inside braces ( {} ) is parsed as a sequence of statements (ie foo is treated like a label, not a key in an object literal).

You must wrap the object literal in parentheses:

 var func = () => ({ foo: 1 }); 

Fixed it in many ways thanks to @hugo.

The original problem was that the module itself wasn't processed by babel-loader.

As @hugo suggested (adding “is-online” to the exclude list), my exclude became like so:

exclude: /(node_modules\\/(?!is-online|public-ip)|bower_components)/

Then I started getting another error:

在此输入图像描述

After looking for a solution, I figured I also had to add import "regenerator-runtime/runtime”; in my code before I import that “is-online” module, as suggested here: https://stackoverflow.com/a/56754212/11033276 .

.babelrc (with no plugins)

{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react", 
    ],
}

I'm still unsure whether I have to also add useBuiltIns: entry to @babel/preset-env as it already seems to be working this way. I'm fairly new to web dev so if someone could suggest an optimization it would be nice!

Lastly, I uninstalled a bunch of dependencies I had tried attempting to fix this.

package.json

// …
  "devDependencies": {
    "@babel/cli": "^7.5.5",
    "@babel/core": "^7.5.5",
    "@babel/preset-env": "^7.5.5",
    "@babel/preset-react": "^7.0.0",
    "babel-loader": "^8.0.6",
    "css-loader": "^3.2.0",
    "file-loader": "^4.2.0",
    "html-webpack-plugin": "^3.2.0",
    "postcss-loader": "^3.0.0",
    "style-loader": "^0.23.1",
    "webpack": "^4.39.1",
    "webpack-cli": "^3.3.6",
    "webpack-dev-server": "^3.8.0",
    "webpack-merge": "^4.2.1"
  },
// …

I doubled-checked it all still works by reinstalling node_modules .

webpack.dev.js

// ...
                {
                    test: /\.(js|jsx)$/,
                    exclude: /(node_modules\/(?!is-online)\/(?!public-ip)|bower_components)/,
                    loader: "babel-loader",
                    options: {
                        presets: ["@babel/env"],
                    }
                },
// …

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM