简体   繁体   中英

Webpack and Babel not transpiling a dependency inside node_modules that breaks IE 11 and Edge due to ES6's spread syntax

I have a project that uses @mdx-js/runtime and it completely breaks on IE 11 or Edge ( Edge 44.18362.449.0 ):

SCRIPT1028: SCRIPT1028: Expected identifier, string or number

It actually breaks because of the spread syntax here:

const allNodes = sortedNodes.map(({ start: _, ...node }, i) => { 

This line of code comes from remark-mdx , which is a dependency of @mdx-js/runtime , particularly this file and line: https://github.com/mdx-js/mdx/blob/master/packages/remark-mdx/extract-imports-and-exports.js#L66

I've been trying to get Webpack and Babel to transform that file so that the spread is no longer there:

Browserlist:

If I run npx browserslist I can see IE 11 is there.

"browserslist": [
    "> 0.5%",
    "last 2 version",
    "Firefox ESR",
    "not dead",
    "iOS >= 9"
]

.babelrc:

I've tried disabling loose mode and adding @babel/plugin-transform-spread and @babel/plugin-proposal-object-rest-spread , but didn't fix the issue.

  {
    "presets": [[
        "@babel/preset-env", {
            "useBuiltIns": "usage",
            "loose": false, // Was true before
            "modules": "auto",
            "corejs": 3
        }],
        "@babel/preset-react",
        "@babel/preset-typescript"
    ],

    "plugins": [
        ["@babel/plugin-proposal-decorators", {
            "legacy": true
        }],
        ["@babel/plugin-proposal-class-properties", {
            "loose": true
        }],
        "@babel/plugin-transform-spread", // Just added
        "@babel/plugin-proposal-object-rest-spread", // Just added
        "@babel/plugin-proposal-optional-chaining",
        "@babel/plugin-proposal-nullish-coalescing-operator",
        "react-hot-loader/babel"
    ]
}

webpack.config.js:

Here I tried explicitly including remark-mdx and @mdx-js/runtime and also removing the exclude property or changing it to /node_modules\\/(?!(remark-mdx|@mdx-js\\/runtime)\\/).*/ , but nothing seems to work:

  {
    test: /\.(j|t)sx?$/,
    include: [
      path.resolve(__dirname, 'src'),
      // Tried explicitly adding these 2:
      path.resolve('node_modules/remark-mdx'),
      path.resolve('node_modules/@mdx-js/runtime'),
    ],
    // Tried removing `exclude` or not excluding those 2 packages:
    // exclude: /node_modules/,
    // exclude: /node_modules\/(?!(remark-mdx|@mdx-js\/runtime)\/).*/,
    use: [{
      loader: 'babel-loader',
      options: {
        cacheDirectory: true,
        babelrc: true,
      }
    }],
  }

I'm using Babel 7 an Webpack 4.

Ok, it turns out to process files inside node_modules you need to use babel.config.js rather than .babelrc as explained here and here :

What's your use case?

  • You are using a monorepo?
  • You want to compile node_modules?

    babel.config.json is for you!

  • You have a configuration that only applies to a single part of your project?

    .babelrc.json is for you!

Also, if you are using a monorepo you need to set rootMode: 'upward' so that Babel can find your new config file, as explained here .

Webpack's babel-loader config should look something like this:

  {
    test: /\.(j|t)sx?$/,
    include: [
      path.resolve(__dirname, 'src'),
      // No need to add @mdx-js/runtime, just add the problematic package:
      path.resolve('node_modules/remark-mdx'),
    ],
    // You also need to exclude it from the exclusions:
    exclude: /node_modules\/(?!(remark-mdx)\/).*/,
    use: [{
      loader: 'babel-loader',
      options: {
        cacheDirectory: true,
        // And replace .babelrc with babel.config.json...
        babelrc: false,
        // ...which might also mean you need this if you are using a monorepo:
        rootMode: 'upward',
      }
    }],
  }

After this change the file was being processed, but I was getting a different error:

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

In this case, I had to add sourceType: "unambiguous" to babel.config.json , as remark-mdx was using CommonJS modules rather than ES6 ones. You can add this at the root of your babel.config.json file or inside overrides , so that it only targets packages inside node_modules .

For more on why this happens, see How do I use babel's `useBuiltIns: 'usage'` option on the vendors bundle? .

Babel's babel.config.json ended up looking like this:

{
    "presets": [[
        "@babel/preset-env", {
            "useBuiltIns": "usage",
            "loose": true,
            "modules": "auto",
            "corejs": 3
        }],
        "@babel/preset-react",
        "@babel/preset-typescript"
    ],

    "plugins": [
        ["@babel/plugin-proposal-decorators", {
            "legacy": true
        }],
        ["@babel/plugin-proposal-class-properties", {
            "loose": true
        }],
        "@babel/plugin-proposal-optional-chaining",
        "@babel/plugin-proposal-nullish-coalescing-operator",
        "react-hot-loader/babel"
    ],

    "overrides": [{
        "test": "./node_modules",
        "sourceType": "unambiguous"
    }]
}

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