我正在寻找一种方法将完整节点项目的Babelimport
s转换为CommonJS风格的require()
。目标是摆脱巴别塔。
考虑到node.js有像async / await内置的东西,现在运行Babel感觉多余。 Babel目前唯一做的就是将ES6风格的import
s转换为require()
。
我一直在寻找,但找不到任何优雅的解决方案,半自动地做到这一点。编译Babel时的输出不够干净,只需复制而无需大量手动工作。
如果我有一个像这样输入的文件:
import express from 'express'
import bodyParser from 'body-parser'
import authMiddleware from './middlewares/auth'
import { get } from 'lodash'
export const myVar = 1
export default function doSomething() {
// ...
}
..我想要一个与此类似的输出
const express = require('express')
const bodyParser = require('body-parser')
const authMiddleware = require('./middlewares/auth').default
const { get } = require('lodash')
export.myVar = 1
export.default = function doSomething() {
// ...
}
或者,它将文件转换为相对的文件的.mjs
语法,并使用require()
作为外部的东西。
这不是我第一次运行Babel的旧节点项目,随着时间的推移它变得越来越冗余,所以我确信有人在此之前已经做了很好的解决方案。
我挖掘了babel-plugin-transform-modules-commonjs
的源代码。看起来配置babel输出您想要的结果是不可能的。
背后的原因是像_interopRequireDefault
这样的帮手仍然保持强大的必要性,因为ES模块并不是对普通人的反击,特别是export default
的事情。
举个例子:
// input
import bodyParser from 'body-parser'
import authMiddleware from './middlewares/auth'
// your desired output
const bodyParser = require('body-parser') // <-- no default
const authMiddleware = require('./middlewares/auth').default // <-- default
// actual babel output
var _bodyParser = _interopRequireDefault(require("body-parser"));
var _auth = _interopRequireDefault(require("./middlewares/auth"));
您无法分辨何时添加.default
以及何时不添加。只有正确的方法来处理这个问题是通过使用require()
包装_interopRequireDefault
并进行运行时检查。
如果编译器确实跟踪了所需的模块并检查它是否是ES模块或commonjs模块,那么它可以判断是否需要.default
。然而,babel是围绕单个文件模型设计的,所以没有机会为你做到这一点。
我想如果你能找出一个可靠的规则来告诉我什么时候添加一个.default
,那么当时没有,或许一个简单的正则表达式替换将解决你的问题。
边注。我确实有一些想法用自定义的babel插件来破解它。
您可以分叉babel-plugin-transform-modules-commonjs
源,删除_interopRequireDefault
包装逻辑,然后使用解析器执行上述check-if-requiree-is-esmodule作业,然后查看输出中是否需要.default
。
但说起来容易做起来难,这需要一些认真的努力。
简单的解决方案,在编辑器中打开源代码,可以浏览我使用VSCode的所有文件,并在node_modules文件夹上设置一个忽略,如果需要多个导出,请在所有文件中使用正则表达式替换。
RegEx方式
搜索:
import[\s*]([a-zA-Z0-9,]*)[\s*]from[\s*]['|"]([a-zA-Z0-9\{\},\.\/\\]*)['|"][\s*]
用。。。来代替
const $1 = require('$2')
如果你使用as
也这样做。搜索:
import[\s*][a-zA-Z0-9,]*[\s*]as[\s*]([a-zA-Z0-9]*)[\s*]from[\s*]['|"]([a-zA-Z0-9\{\},\.\/\\]*)['|"][\s*]
用。。。来代替
const $1 = require('$2')
这里有一些缺点,你不能使用多个导出,你需要完整的方式
很长的路要走
好吧,对于任何有兴趣的人,这是我用来解决这个问题的过程,然后你可以将你的源码从build文件夹复制到一个新的位置作为一个新的源或覆盖你的旧src并删除所有的babel你的项目(npm prune
)。
这将留下模块所需的所有支持内容,包括对导出默认_interopRequireDefault()
的支持,摆脱这种情况的唯一方法是创建自己的插件,而不是这样做。
步骤1
确定ECMA巴贝尔正在使用什么。所以我去了https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
它表明自ES6(也称为ECMA2015)以来,导入已成为规范的一部分
第2步
预设只是包的组,因此标识该特定转换的包。
打开我的package.json,找了babel-preset-es2015
找到它。去了node_moduels \ babel-preset-es2015,打开它的package.json来查找
"babel-plugin-transform-es2015-modules-amd": "^6.24.1",
"babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
"babel-plugin-transform-es2015-modules-systemjs": "^6.24.1",
"babel-plugin-transform-es2015-modules-umd": "^6.24.1",
第3步
一些测试,所以使用--plugins=
论证为babel我测试了他们每个人在一小组2个文件上做了什么,一个需要另一个并测试我解决的每一个是require();
所需的commonjs版本
第4步
做转换
因此,请确保已安装以下节点模块babel-cli, babel-core, babel-plugin-transform-es2015-modules-commonjs
然后启动CLI并执行,
babel --plugins=transform-es2015-modules-commonjs ./src/ --out-dir build/