Skip to main content

babel-编译构建之preset属性值modules

@babel/preset-env作用

@babel/preset-env 是 Babel 中的一个预设(preset),它的作用是根据目标环境(通常是目标浏览器或 Node.js 版本)来自动转译(transpile)你的 JavaScript 代码,以确保你的代码在目标环境中能够运行。

具体来说,@babel/preset-env 可以根据你配置的目标环境自动选择合适的 Babel 插件和转译规则,以处理现代 JavaScript 语法、新特性和 API,使它们在旧版浏览器或 Node.js 中也能正常运行。这有助于确保你的代码在各种浏览器和 Node.js 版本中具有跨浏览器和跨平台的兼容性。

你可以在项目的 Babel 配置文件中设置 @babel/preset-env 的目标环境,例如:

{
"presets": [
["@babel/preset-env", {
"targets": "> 0.25%, not dead"
}]
]
}

一次升级中的preset-env造成的报错

在升级@babel/preset-env 之前,项目中的配置是这样的:

{
test: /\.(ts|js)x?$/,
include: [
path.resolve(__dirname, '../src'),
/node_modules[\\/]antd/,
],
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true,
cacheCompression: false,
},
},
{
loader: 'ts-loader',
options: {
transpileOnly: true,
},
}
],
}

问题:exports is undefined

升级@babel/preset-env 之后,babel-loader 的配置保持不变。

babel.config.js 中@babel/preset-env 的配置 modules 变为 auto。

这时就出现了文章开头提到的异常:exports is undefined。

当这个异常出现后,把 modules 的值改回去变为 commonjs,异常又消失了。

推论: 问题出在模块包装上,具体就是 webpack 打包的时候注入的形参变量中没有 exports。而引起 webpack 未在包装时注入形参的原因很可能是@babel/preset-env 的配置 modules 导致的

babel.config.js

const plugins = [
[
"@babel/plugin-transform-runtime",
{
corejs: 3,
},
],
[
"import",
{
libraryName: "antd",
libraryDirectory: "lib",
style: true,
},
"ant",
],
];

module.exports = {
presets: [
[
"@babel/preset-react",
{
runtime: "automatic",
},
],
[
"@babel/preset-env",
{
modules: "commonjs", // 升级之后这里变为'auto'
useBuiltIns: "usage",
corejs: "3.9",
},
],
],
plugins,
};

解决方案:模块转换:@babel/preset-env 的配置项 modules

modules:

"amd" | "umd" | "systemjs" | "commonjs" | "cjs" | "auto" | false, defaults to "auto".
  • modules 值为 umd: 其含义为将 es module 的模块语法、模块特性转换成 umd 的模块语法、模块特性; 如果是非 es module 的模块语法、模块特性,则不会转换其模块语法和模块特性,只是做一层 umd 的模块包装。

  • modules 值为 systemjs: 其含义为将 es module 的模块语法、模块特性转换成 systemjs 的模块语法、模块特性; 如果是非 es module 的模块语法、模块特性,则不会转换其模块语法和模块特性,只是做一层 systemjs 的模块包装。

  • modules 值为 commonjs 或者 cjs(二者等价): 其含义为将 es module 的模块语法、模块特性转换成 commonjs 的模块语法、模块特性。 如果是非 es module 的模块语法、模块特性,则原样输出

  • modules 值为 false: 其含义为:不转换 es module;如果是非 es module 的模块语法、模块特性,则原样输出。

  • modules 值为 auto: 其含义为:根据 caller 参数 supportsStaticESM 来决定要不要转换 es module,为 true 则不转换,为 false 则转换成 commonjs。caller 可以手动传入,也可以是 loader 或者 plugin 传入的(如 babel-loader)。非必要不要手动传入,因为会影响 loader 或者 plugin 的行为,导致产物和预期有差别。

将 babel-loader 中处理 node_modules 下的模块的配置单独拎出去,覆盖公共的 babel.config.js 配置

用 babel-loader 去处理 node_modules 的原因是做语法兼容。

[
{
test: /\.(ts|js)x?$/,
include: [
path.resolve(__dirname, "../src"),
// /node_modules[\\/]antd/, // 从这里去掉
],
use: [
{
loader: "babel-loader",
options: {
cacheDirectory: true,
cacheCompression: false,
},
},
{
loader: "ts-loader",
options: {
transpileOnly: true,
},
},
],
},
{
test: /\.(ts|js)x?$/,
include: [/node_modules[\\/]antd/],
use: [
{
loader: "babel-loader",
options: {
cacheDirectory: true,
cacheCompression: false,
presets: [
[
"@babel/preset-env",
{
modules: "cjs",
useBuiltIns: "usage",
corejs: "3.9",
},
],
],
},
},
{
loader: "ts-loader",
options: {
transpileOnly: true,
},
},
],
},
];