Codemod для Babel `import` в commonjs` require` - PullRequest
3 голосов
/ 20 апреля 2019

Я ищу способ преобразовать полный Babel import s нод-проекта в CommonJS-стиль require(). Цель - избавиться от Вавилона.

Учитывая, что в node.js есть такие вещи, как async / await, встроенные в наше время, он чувствует себя избыточным для запуска Babel. Единственное, что осталось от Babel, это то, что он конвертирует import s в стиле ES6 в 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, где он становится все более и более избыточным со временем, поэтому я уверен, что кто-то уже делал это аккуратное решение.

Ответы [ 2 ]

3 голосов
/ 25 апреля 2019

Выкапываю исходный код 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, а затем посмотреть, требуется ли .default в выводе .

Но легче сказать, чем сделать, это требует серьезных усилий.

2 голосов
/ 28 апреля 2019

Простое решение, откройте ваш исходный код в редакторе, который может просмотреть все файлы, которые я использую VSCode, и установить игнорирование в папке node_modules, и я должен регулярно заменять все файлы, если вам нужен множественный экспорт, ниже .

RegEx way

Поиск:

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')

здесь есть некоторые недостатки: вы не можете использовать несколько экспортов, которые вам нужны. Полный путь

Долгий путь

Хорошо, так что для всех, кто заинтересован, вот процесс, который я использовал для этого, вы можете затем скопировать ваш источник из папки сборки в новое место в качестве нового источника или перезаписать ваш старый 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 файлов, один из которых требовал другого, и протестировал каждый, который я разработал. Это была версия commonjs, которая была необходима для * 1057. *

Шаг 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

...