在ES5模块中支持ES6导入

时间:2019-11-25 23:48:58

标签: javascript ecmascript-6 es6-modules

对于一年级的学生,我提供了一个简单的基于ES5的库,该库使用显示模块模式编写。这是“主”模块/命名空间的片段,它将包含其他扩展名:

window.Library = (function ($) {
    if (!$) {
        alert("The Library is dependent on jQuery, which is not loaded!");
    }

    return {};
})(window.jQuery);

这对大约99.9%的Web开发新手并且没有将ES6等奇特的东西与Webpack或Babel结合使用的学生有效。

0.1%的人现在要求我提供基于ES6的版本,可以正确导入。我很乐意提供这一点,但是我对如何最好地解决这个问题有些困惑。

我显然想保留ES5的方式,因此我的学生可以使用脚本标签包括该文件,并在任何需要的地方键入Library.SomeExtension.aFunction();。最重要的是,某些扩展依赖于jQuery,它的注入方式与上面的代码段类似。

我现在正在寻找一种可维护的方法,以一个代码库,以jQuery作为依赖关系来实现两全其美。我想给99.9%的人window.Library,而我想给0.1%的人使用import Library from 'library'

我可以用同时执行两个操作的单个JS文件来完成此操作吗?还是我需要一个特殊的ES6版本(不是问题)?最重要的是:如何以一种我可以同时支持两种情况的方式来重新整理我的代码(均与上述代码段相似)?

任何指针都将不胜感激!

编辑:作为一个旁注,我已经有一个gulpfile.js,可以通过Babelminifiers等方式运行此库。因此,必须扩展它来解决上述问题不是问题!

3 个答案:

答案 0 :(得分:5)

经过几个晚上的代码移动并安装了许多gulp软件包,我什至都不记得尝试过的所有软件包,最终我还是选择了半满意的东西。

首先,回答我自己的问题,@Bergi在评论中也对此进行了支持:

  

简短的回答:不,您不能(现在)以任何方式在单个文件中混合使用ES6语法和ES5(模块),因为浏览器会因使用export而出错。

     

长答案:从技术上讲,您可以将脚本元素类型设置为“模块”,这将使浏览器接受export关键字。但是,您的代码将只运行两次(加载后一次,导入后一次)。如果您可以忍受,那么“否”就变成“是”。

那我最终做了什么?让我先说一下,我真的很想将我目前拥有的IIFE模块设置保留在输出ES5文件中。我将代码库更新为纯ES6,并尝试了各种插件组合(包括@David Bradshaw提到的Rollup.js)。但是我根本无法使它们工作,否则它们将完全破坏输出,使浏览器无法再加载模块或放弃对源地图的支持。通过该项目,学生们现在正在做的工作接近尾声,我已经为0.1%的学生浪费了足够的业余时间。明年,祝您有更好的“更好的”解决方案。

  1. 我基于jQuery建立了我的UMD模式(如@Sly_cardinal所提到的),并将该代码放入Library.umd.js中。对于ES6部分,我制作了一个Library.es6.js,其中只包含export default Library

  2. 在两个文件中,我都放置了一个多行注释/*[Library.js]*/,我想在其中插入串联的未缩小的Library.js。

  3. 我修改了现有的Gulp任务,仅使用Library.jsconcat构建Babel并将其存储在一个临时位置。我选择在此过程中放弃对源映射的支持,因为级联代码在输出中完全可读。从技术上讲,源映射支持“有效”,但仍会使调试器产生过多影响。

  4. 我添加了一个额外的Gulp任务来读取临时Library.js的内容,然后对于步骤1中的每个文件,我都会找到多行注释并将其替换为内容。保存结果文件,然后将它们扔到最后的concat(例如,与jQuery捆绑在一起),terser和源地图生成中。

最终结果是两个文件:

  • 一个具有UMD / ES5浏览器支持的人
  • 一个支持ES6的人

虽然我对结果感到满意,但我不喜欢Gulp任务链以及在过程的前半部分失去对Sourcemap的支持。如前所述,我尝试了许多gulp插件来实现相同的效果(例如gulp-inject),但是它们要么无法正常工作,要么对Sourcemap进行了怪异的处理(即使他们声称支持)

下一步,我可能会研究与Gulp不同的东西,或者自己动手做上述事情的插件,但是:P

答案 1 :(得分:0)

您可以使用Rollup.js将代码捆绑为ES5库和随附的ES6模块。

Rollup有built-in support for Gulp,所以这样的事情是一个合理的起点(基于Rollup的Gulp示例):

    const gulp = require('gulp');
    const rollup = require('rollup');
    const rollupTypescript = require('rollup-plugin-typescript');

    gulp.task('bundle', () => {
      return rollup.rollup({
        input: './src/main.ts',
        plugins: [
          rollupTypescript()
        ]
      }).then(bundle => {
          return Promise.all([
              // Build for ES5
              bundle.write({
                file: './dist/library.js',
                format: 'umd',
                name: 'Library',
                sourcemap: true
            }),

            // Build for ES6 modules
            bundle.write({
                file: './dist/library.esm.js',
                format: 'esm',
                sourcemap: true
            })
          ]);
      });
    });

您可以查看有关可用的不同输出格式的更多信息:https://rollupjs.org/guide/en/#outputformat

通常,最简单的方法是使用ES模块编写库源代码,然后将其捆绑/向下移植到ES5捆绑包中。

答案 2 :(得分:-1)

它们是 Universal JS Loader Patten ,可让您以多种不同方式导出代码。

;(function (root, factory) {

  if (typeof define === 'function' && define.amd) {
    define(factory);
  } else if (typeof exports === 'object') {
    module.exports = factory();
  } else {
    root.YourModule = factory();
  }

}(this, function () {
  return {};
}));