Codemod for Babel`import` into commonjs`require`

问题描述 投票:3回答:2

我正在寻找一种方法将完整节点项目的Babelimports转换为CommonJS风格的require()。目标是摆脱巴别塔。

考虑到node.js有像async / await内置的东西,现在运行Babel感觉多余。 Babel目前唯一做的就是将ES6风格的imports转换为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的旧节点项目,随着时间的推移它变得越来越冗余,所以我确信有人在此之前已经做了很好的解决方案。

javascript node.js import babel require
2个回答
3
投票

我挖掘了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

但说起来容易做起来难,这需要一些认真的努力。


2
投票

简单的解决方案,在编辑器中打开源代码,可以浏览我使用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/

取自https://babeljs.io/docs/en/babel-cli

© www.soinside.com 2019 - 2024. All rights reserved.