Babel转换导入以构造默认值

时间:2018-03-27 15:48:33

标签: javascript ecmascript-6 babel commonjs

我正在尝试创建一个不将文件捆绑在一起的构建管道,而是使用<script type="module">。这样我就可以在不重新绑定的情况下重新编译文件,从而大大缩短开发过程中的构建时间。

我们的项目使用ES6,因此通常很容易。

但是有一个障碍:第三方模块只有CommonJS版本(例如反应)。

有几种方法可以解决这个问题。现在,我有一个转换,将导入名称从react更改为/node_modules/react,我的服务器非常智能,然后从dist找到相应的node_modules文件并提供服务它了。一切正常。

问题在于,当我尝试执行以下操作时会感到困惑:

import { Component } from 'react';

目前的情况不会起作用(因为它没有默认值而感到困惑)。但是,这将有效:

import * as React from 'react';
const { Component } = React;

我可以手动为所有文件和软件包执行此操作,但是a)会使其不必要地变得丑陋(使用Redux和其他东西,在我们必须执行此操作的许多文件中有六个不同的软件包和b )有很多文件,我不想手动全部更改。

是否有可以自动进行此类转换的Babel转换插件?这似乎不是一种全新的方法,所以我希望有一个插件可以做对我而言,我的Google-fu无法找到。

1 个答案:

答案 0 :(得分:0)

我设法让这个工作。我最终不得不编写自己的Babel插件来进行我正在寻找的更改。基本上,对于import语句的不同版本,它会更改它以便更好地使用UMD和CJS模块。

例如,像这样:

import A, { a, b, c } from 'a';

变成了这样的东西:

import * from __babel_A from 'a';
const A = __babel_A.default && (__babel_A.default.default || __babel_A.default) || __babel_A;
const { a, b, c } = __babel_A.default || __babel_A;

这种格式是基于大多数东西出口的方式而来的。许多人(如React)会将所有内容放入一个对象中,其名称可以module.exports(如果我提供了假名)或thiswindow。其他人最终没有把事情分组(比如ReactRTE)并且有自己的“默认”,这是default.default位的来源。

除了这个转换之外,当我的服务器提供第三方文件的dist版本时,它会以一种让我进行export default的方式将它们包装起来。看起来像这样:

const module = {}; 
const keys = Object.keys(this || window);
const toExport = (function __auto_wrapper() {  
  ${fileCode}

  return module.exports || Object.keys(this).reduce((r, k) => keys.includes(k) ? r : Object.assign(r, { [k]: this[k].default || this[k] }), {});
}).call(this || window);

export default Object.keys(toExport).length === 1 ? Object.entries(toExport)[0][1] : toExport;

同样,不同的方式基于不同项目的输出。一些人在给出它时会使用module.exports,其他人不会认为module.exports是真实的,因为我(故意)没有将export初始化为对象(如果我这样做,那就是尝试使用我不想要的require()。在我的例子中,ReactRTE只有一个CJS模块而不是UMD,所以我还必须替换它的代码来替换require('react')require('react-dom')而不是引用window上的对象

这一切都按我想要的方式工作(在浏览器中完全非捆绑式代码加载)。唯一的轻微副作用是React和朋友都在window上可用(如果正确捆绑它们通常不会这样),但这很小。