0

I'm having an issue with upgrading from Webpack 4 to Webpack 5, where Babel no longer seems to transpile code from one of my dependencies (async-mutex). I managed to strip it down to a minimal setup that demonstrates the problem:

package.json

{
    "scripts": {
        "build": "webpack --mode=production"
    },
    "devDependencies": {
        "@babel/core": "~7.12.0",
        "@babel/preset-env": "~7.12.0",
        "async-mutex": "~0.2.0",
        "babel-loader": "~8.2.0",
        "webpack": "~5.10.0",
        "webpack-cli": "~4.2.0"
    },
    "babel": {
        "presets": [
            "@babel/preset-env"
        ]
    },
    "browserslist": [
        "Explorer >= 11"
    ]
}

webpack.config.js

module.exports = {
    entry:  {
        bundle: './index.js',
    },
    module: {
        rules: [
            {
                test: /\.m?js$/,
                use:  'babel-loader',
            },
        ],
    },
};

index.js

import {Mutex} from 'async-mutex';
console.log(Mutex);

class MyClass {}
console.log(MyClass);

As per my browserslist, I need to support IE 11. After building this and inspecting the resulting dist/bundle.js I can see that the class MyClass was transpiled into a function, but the class Mutex was not transpiled, which obviously causes IE 11 to fail with a syntax error. It's as if Babel is using different settings to process the async-mutex package than it uses to process my index.js.

I found another question with an answer that suggests adding target: ['web', 'es5'], but that doesn't help and it also seems unnecessary, since Webpack is supposed to honor browserslist.

With Webpack 4 I did not have this issue, but I'm not sure if the problem is with my setup, with Webpack, with Babel or even with async-mutex.

Note aside: I'm aware that this minimal setup is lacking a Promise polyfill, but I omit it here because it seems irrelevant to the issue.

isherwood
  • 58,414
  • 16
  • 114
  • 157
jlh
  • 4,349
  • 40
  • 45
  • they've undoubtedly [deliberately] dropped the existing support for IE11 - but you don't need to upgrade to Webpack 5 anyway. Try to follow this wise headache free principle :: Don't fix and don't upgrade systems and apps and programs that are working flawlessly in their existing environment. Don't put a thorn on your healthy heel. – Bekim Bacaj Dec 17 '20 at 18:44
  • @BekimBacaj Neither Webpack nor Babel has dropped support for IE 11. And async-mutex has never directly supported it in the first place, hence the requirement for polyfills and transpilation. – jlh Dec 17 '20 at 20:22

2 Answers2

1

Babel configuration within package.json only applies within your specific package, not node_modules, so even though Babel is set up to process all files in your bundle, it's only been configured to perform transformations on your own package's files. See the Babel config file docs.

You need to create a babel.config.json instead, or you need to put the config directly into the Webpack config, so either

babel.config.json:

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

OR webpack.config.js:

module.exports = {
    entry:  {
        bundle: './index.js',
    },
    module: {
        rules: [
            {
                test: /\.m?js$/,
                use:  'babel-loader',
                options: {
                    "presets": [
                        "@babel/preset-env"
                    ]
                }
            },
        ],
    },
};
loganfsmyth
  • 156,129
  • 30
  • 331
  • 251
0

You'll need to include async-mutex in your webpack.config.js's module rule for babel. Once in awhile you'll come across a package that doesn't transform its ES6. Funny enough, the best way to include it in your transpilation is using exclude, like this:


module.exports = {
    entry:  {
        bundle: './index.js',
    },
    module: {
        rules: [
            {
                test: /\.m?js$/,
                exclude: /node_modules\/(?!(async-mutex)\/).*/,
                use:  'babel-loader',
            },
        ],
    },
};

This exclude rule says, "exclude all node_modules but async-mutex".

Jay Kariesch
  • 1,392
  • 7
  • 13
  • Unsurprisingly, this does not change anything. I know that it's common practice to exclude "node_modules" from babel, but I deliberately did not do that in order to include it. There is no default exclude rule as far as I know, so this does not have any effect. – jlh Dec 17 '20 at 20:16
  • Are you using `@babel/plugin-proposal-class-properties` in your babelrc? I see in your OP it's not there. Try adding it. You'll need to add that transform manually to transform ES6 classes. – Jay Kariesch Dec 17 '20 at 20:19
  • Weird. I see the `preset-env` already has it. It seems that webpack simply isn't including that package during compilation. That much is clear. I'd try a variation of the exclude. You can find quite a few here: https://github.com/webpack/webpack/issues/2031#issuecomment-244921229 – Jay Kariesch Dec 17 '20 at 20:34
  • Again, this makes no difference at all. Class properties seem to be a proposed addition to ES6 classes. Enabling support for this only makes sense when actually using them (which I'm not and async-mutex isn't either). `MyClass` can be transpiled just fine without it. – jlh Dec 17 '20 at 20:35
  • I understand. It doesn't matter anyway since *all* class transforms are already in `preset-env`. And on top of that, it seems `async-mutex` is targeting ES5 in its `tsconfig` build output, so it's strange to me that it's throwing that error, unless I'm reading its `tsconfig` wrong. Either way, since your class was transpiled to a function, but for some reason, according to your OP, `async-mutex` was not, it seems webpack isn't transpiling it, so I'd try various methods to include it. Also, IIRC, `target: ['web', 'es5']` only impacts webpack generated boilerplate. – Jay Kariesch Dec 17 '20 at 20:40