如何仅用Babel在构建时编译模板字符串(不使用Webpack)
问题
我使用Babel(不搭配Webpack)转译ES6代码,希望在构建阶段直接计算代码中的模板字面量,注入版本号。代码中有如下导入语句:
const Component = React.lazy(() => import(`projectVersion${__VERSION__}/FooBar`))
我尝试了babel-plugin-inline-replace-variables、babel-plugin-transform-inline-environment-variables等插件,但编译后的代码会保留字符串拼接逻辑:
var Component = /*#__PURE__*/_react.default.lazy(function () { return Promise.resolve("projectVersion".concat("1", "/FooBar")).then(function (s) { return _interopRequireWildcard(require(s)); }); });
这会导致运行时报错:Critical dependency: the request of a dependency is an expression。我需要的是版本号直接合并为固定字符串的编译结果,类似:
const Component = /* #__PURE__*/_react.default.lazy(() => Promise.resolve().then(() => _interopRequireWildcard(require('projectVersion1/FooBar'))))
补充信息:
- 构建命令:
babel src --out-dir build - 当前Babel配置:
module.exports = api => { api.cache(true) return { presets: [ ['@babel/preset-env', { corejs: 3, targets: '> 0.25%, not dead', useBuiltIns: 'usage', }], ['@babel/preset-react', { runtime: 'automatic', }], '@babel/preset-typescript', ], plugins: [], } }
解决方案
要让Babel在语法转换阶段就完全合并模板字面量为固定字符串,需要使用能直接替换并拼接完整字符串的插件,而非仅替换变量、保留拼接逻辑的工具。以下是两种可行方案:
方案一:使用babel-plugin-preprocessor
- 安装插件:
npm install babel-plugin-preprocessor --save-dev
- 修改Babel配置,添加插件并配置版本变量:
module.exports = api => { api.cache(true) return { presets: [ ['@babel/preset-env', { corejs: 3, targets: '> 0.25%, not dead', useBuiltIns: 'usage', }], ['@babel/preset-react', { runtime: 'automatic', }], '@babel/preset-typescript', ], plugins: [ ['babel-plugin-preprocessor', { macros: { __VERSION__: process.env.VERSION || '1' // 可直接写死版本,或从环境变量读取 } }] ], } }
- 运行构建命令(若用环境变量传版本,需先设置):
# Linux/macOS VERSION=1 babel src --out-dir build # Windows(PowerShell) $env:VERSION='1'; babel src --out-dir build
该插件会在语法解析阶段直接合并模板字面量为完整字符串,编译后即可得到固定的require('projectVersion1/FooBar')形式。
方案二:自定义极简Babel插件
若不想额外安装依赖,可编写一个简单的自定义插件处理版本替换:
- 在项目根目录创建
babel-plugin-replace-version.js:
module.exports = function({ types: t }) { return { visitor: { TemplateLiteral(path) { // 检查模板字面量是否包含__VERSION__标识符 const hasVersion = path.node.expressions.some(expr => t.isIdentifier(expr) && expr.name === '__VERSION__' ); if (!hasVersion) return; // 获取版本号(可从环境变量或配置读取) const version = process.env.VERSION || '1'; // 拼接所有模板片段与版本号 const fullString = path.node.quasis.reduce((str, quasi, index) => { return str + quasi.value.cooked + (index < path.node.expressions.length ? version : ''); }, ''); // 将模板字面量替换为字符串字面量 path.replaceWith(t.stringLiteral(fullString)); } } }; };
- 修改Babel配置引入自定义插件:
module.exports = api => { api.cache(true) return { presets: [ ['@babel/preset-env', { corejs: 3, targets: '> 0.25%, not dead', useBuiltIns: 'usage', }], ['@babel/preset-react', { runtime: 'automatic', }], '@babel/preset-typescript', ], plugins: [ './babel-plugin-replace-version.js' ], } }
- 设置环境变量后运行构建命令,即可得到期望的编译结果。
内容的提问来源于stack exchange,提问作者Patrick
相关产品推荐
相关产品推荐

