electron 项目升级了 webpack5,项目跑起来发现报错,regeneratorruntime is not defined,项目无法正常运行 😂
报错原因
这个报错是由于 async function 语法糖被 babel 转译之后使用了 regeneratorRuntime
这个变量,但是这个变量在最终的代码里未定义造成的报错。
情景复现
我们新建一个文件,使用 async 语法来编写代码
// index.jsasync function foo() { const ret = await Promise.resolve(2); console.log(ret);}foo();
配置 webpack.config.js
// webpack.config.jsmodule.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