背景
最近在改造公司原有前端框架CLI,需要在兼容原有配置文件的前提下,通过webpack对文件进行读取组装。原有配置文件是使用的ESModule模块写法导出,nodejs直接读取ESModule模块文件会报错。例如:
export default routes;
^^^^^^
最近在阅读Taro源码中,发现他们使用了@babel/register,为 require 方法注册了 babel,为它加上一个钩子。此后,每当使用 require 加载指定文件,就会先用 Babel 进行转码。
那我们就可以利用这个功能,对CLI加载的ESModule文件进行一次编译后再读取。
@babel/register
先来介绍一下@babel/register
使用 Babel 的方法之一就是通过 require 钩子(hook),require 钩子将自身绑定到 node 的 require 模块上,并在运行时自动编译文件。
安装
@babel/register 只有一个功能,就是重写 node 的 require 方法。
安装命令如下所示:
npm install @babel/core @babel/register --save-dev
安装好后可以通过 require 引用,如下所示:
require("@babel/register");
@babel/register 在底层改写了 node 的 require 方法,在代码里引入 @babel/register 模块后,所有通过require引入并且以 .es6,.es,.jsx, .mjs,和 .js 为后缀名的模块都会被 Babel 转译。
指定参数
require("@babel/register")({
ignore: [
/regex/,
function(filepath) {
return filepath !== "/path/to/es6-file.js";
},
],
only: [
/my_es6_folder/,
function(filepath) {
return filepath === "/path/to/es6-file.js";
}
],
extensions: [".es6", ".es", ".jsx", ".js", ".mjs"],
cache: true,
});
或者还可以传递其他的参数,例如 plugins 和 presets。需要注意的是,配置文件也将被加载,并且编程方式的配置也将被合并进来,放在这些配置项的顶部。
具体实现
原有文件:
// src/pages/moduleName/router.js
const router = [
// ...
]
export default routes;
现在需要通过nodejs读取此类文件,直接在nodejs代码中requier读取报错。我们在代码require之前进行require 钩子(hook)注册。
babel插件
首先,我们需要知道babel哪个插件是用于编译commonjs文件的。
通过官网了解,babel用于ESModule文件读取的插件为@babel/plugin-transform-modules-commonjs
- 安装babel插件
npm install --save-dev @babel/plugin-transform-modules-commonjs
注册函数
实现 createBabelRegister 注册函数。
function createBabelRegister() {
require('@babel/register')({
only: [
// 只对指定文件进行编译
function (filepath) {
return /pages.*router\.js/.test(filepath);
}
],
plugins: [
// 支持js文件的commonjs导出
'@babel/plugin-transform-modules-commonjs'
],
babelrc: false,
configFile: false,
cache: false
});
}
代码调用
我们在代码require之前进行注册即可。
// 调用注册hook
createBabelRegister();
//...
const routerContent = require(path.resolve(process.cwd(), `./src/pages/${item}/router.js`)).default;
console.log(routerContent);
//...
保存重新运行cli命令,观察打印内容正常展示:
说明功能实现了,最后优化下代码。
// createBabelRegister.js
function createBabelRegister({ only }) {
require('@babel/register')({
only: Array.from(new Set([...only])),
plugins: [
// 支持js文件的ESModule导出
'@babel/plugin-transform-modules-commonjs'
],
extensions: ['.js'],
babelrc: false,
configFile: false,
cache: false
});
}
// 注册时指定文件内容
createBabelRegister({
only: [(filepath) => /pages.*router\.js/.test(filepath)]
});
@babel/register
@babel/plugin-transform-modules-commonjs
Taro-createBabelRegister源码