我正在寻找一种将整个节点项目的Babel import
转换为CommonJS风格的require()
的方法。目标是摆脱通天塔。
考虑到node.js内置了async / await之类的东西,如今运行Babel感觉很多余。 Babel当前唯一要做的就是将ES6样式的import
转换为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的旧节点项目,随着时间的流逝,它变得越来越多余,所以我敢肯定有人以前对此做了巧妙的解决方案。
答案 0 :(得分:2)
我挖掘了babel-plugin-transform-modules-commonjs
的源代码。似乎无法配置babel来输出所需的结果。
背后的原因是像_interopRequireDefault
这样的助手仍然很有必要,因为ES模块不会向后兼容commonjs,尤其是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工作,然后查看是否{{1 }}在输出中是必需的。
但是说起来容易做起来难,这需要认真的努力。
答案 1 :(得分:1)
简单的解决方案,在可以使用我使用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并删除所有项目(npm prune
中的Babel。
这将留下模块所需的所有支持内容,包括对导出默认_interopRequireDefault()
的支持。摆脱此问题的唯一方法是创建自己的插件,而不执行此操作。
第1步
确定ECMA babel为此使用了什么。所以我去了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=
参数进行通天塔测试,我测试了每个文件在一组2个文件中的作用,一个文件又需要另一个文件进行测试,我测试了每个文件,得出的结果是commonjs版本require();
第4步
进行转换
因此请确保您已安装以下节点模块bable-cli, babel-core, babel-plugin-transform-es2015-modules-commonjs
然后启动CLI并执行
babel --plugins=transform-es2015-modules-commonjs ./src/ --out-dir build/
答案 2 :(得分:0)
为此目的,您可以使用名为 putout 的 @putout/plugin-convert-esm-to-commonjs 中的 plugin
。它转换:
import {readFile} from 'fs/promises';
致:
const readFile = require('fs/promises');
要完成工作,请使用以下命令设置基线:
npx putout . --disable-all
在配置文件 convert-esm-to-commonjs
中启用 .putout.json
:
{
"rules": {
"convert-esm-to-commonjs": "on"
}
}
并应用修复:
npx putout . --fix