electron 项目升级了 webpack5,项目跑起来发现报错,regeneratorruntime is not defined,项目无法正常运行  😂

报错原因

这个报错是由于 async function 语法糖被 babel 转译之后使用了 regeneratorRuntime 这个变量,但是这个变量在最终的代码里未定义造成的报错。

情景复现

我们新建一个文件,使用  async  语法来编写代码

// index.js
async function foo() {
const ret = await Promise.resolve(2);
console.log(ret);
}
foo();

配置 webpack.config.js

// webpack.config.js
module.exports = {
entry: './index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.bundle.js',
},
};

运行  webpack  后打包出的结果如下

!(async function () {
const o = await Promise.resolve(2);
console.log(o);
})();

为了兼容低版本浏览器,我们再引入  babel

module.exports = {
...
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}
]
}
};

配置  .babelrc  如下

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

打包的结果如下

!(function () {
function n(n, e, r, t, o, i, u) {
try {
var c = n[i](u),
a = c.value;
} catch (n) {
return void r(n);
}
c.done ? e(a) : Promise.resolve(a).then(t, o);
}
function e(e) {
return function () {
var r = this,
t = arguments;
return new Promise(function (o, i) {
var u = e.apply(r, t);
function c(e) {
n(u, o, i, c, a, 'next', e);
}
function a(e) {
n(u, o, i, c, a, 'throw', e);
}
c(void 0);
});
};
}
function r() {
return (r = e(
regeneratorRuntime.mark(function n() {
var e;
return regeneratorRuntime.wrap(function (n) {
for (;;)
switch ((n.prev = n.next)) {
case 0:
return (n.next = 2), Promise.resolve(2);
case 2:
(e = n.sent), console.log(e);
case 4:
case 'end':
return n.stop();
}
}, n);
})
)).apply(this, arguments);
}
!(function () {
r.apply(this, arguments);
})();
})();

运行一下打包  index.bundle.js  文件,发现报错了,错误如下图

因为  babel  在转  async  语法的时候,使用  regeneratorRuntime  这个变量。然后这个变量未声明,所以报错了。

解决办法

1.  配置  @babel/preset-env  的  targets  选项

如果我们确定代码运行在兼容  async  语法的环境下,可以配置  node  的版本,这样  babel  在转换的时候就不会去处理  async  语法的代码

{
"presets": [
[
"@babel/preset-env", {
"targets": {
"node": "15.4"
}
}
]
]
}

结果等同于上面不配置  babel  的情况

!(async function () {
const o = await Promise.resolve(2);
console.log(o);
})();

2. 配置  @babel/plugin-transform-runtime (推荐)

{
"presets": ["@babel/preset-env"],
"plugins": [
"@babel/plugin-transform-runtime"
]
}

3.  配置  @babel/preset-env  的  useBuiltIns (不推荐)

如果使用  usage  或者  entry ,将会使用  core-js  模块来处理,默认使用  2.0  版本,我们这里安装 3.0 npm i core-js@3.17.3,然后手动声明  corejs  版本

{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": "3.17.3"
}
]
]
}

使用  useBuiltIns  可能会修改全局变量或者全局对象的原型链,如果多个库同时修改同一变量的情况下就会导致难以跟踪的问题  https://github.com/babel/babel/issues/10271#issuecomment-5283795