【译】基于JS模块化现状谈谈选择ES6模块的缘由

这篇文章,咱们将了解为何JS社区有必要选择ES6模块。html

现状

要明白这种重要性,首先咱们须要描述一下JS的实际状况。过去5年,JavaScript 发展得很是迅猛,大多数开发人员几乎没意识到当前已经有 5 种方式,能够为 JavaScript 脚本和应用建立模块了!前端

  • 原始的 IIFE () : 这是最古老,也是比较简单的建立 JS 模块的方法了。如下是用 IIFE 实现的简单模块化示例:node

const myModule = (function (...deps){
       // JavaScript chunk
       return {hello : () => console.log(‘hello from myModule’)};
    })(dependencies);

相信你们对这段代码都不陌生,它只是把变量和方法都封装在自己做用域内的一种普通模式。其存在的缺点就是没有帮咱们处理依赖。es6

  • requirejsAMD (异步模块依赖) : Require.js 很受欢迎,它能够给模块注入依赖,还容许动态地加载 JS 块。浏览器

<pre>define(‘myModule’, [‘dep1’, ‘dep2’], function (dep1, dep2){
        // JavaScript chunk, with a potential deferred loading
        return {hello: () => console.log(‘hello from myModule’)};
    });
    // anywhere else
    require([‘myModule’], function (myModule) {
        myModule.hello() // display ‘hello form myModule’
    });

效率高,惋惜有点冗长,并且不能在 Node.js 本地运行。服务器

  • CommonJs : Node.js 平台的默认格式. 一般用法相似这样:app

// file1.js
    modules.export = {
        hello : () => console.log(‘hello from myModule’)
    }

    // file2;
    const myModule = require('./file1.js');
    myModule.hello();

nodejs

感受这种方式更酷吧,不只能够定义变量的做用域,还能够定义模块之间的依赖。惋惜这是专为 Node 设计的,不支持在浏览器运行,也不能异步加载模块。可是,它能够在前端app使用,借助 Browserify 或者其余工具来转换,就可让它在浏览器运行了。异步

  • UMD (通用模块依赖) : 到这里,咱们发现尚未一种既能够同时兼容浏览器和 Node 服务器的解决方案。AMD 适合浏览器,CommonJS 适合 Node.模块化

UMD 就来尝试解决这个问题了。它经过把 AMD 和 CommonJS 结合起来,使之在各类需求下都是可集成的,代码大概以下:工具

(function (global, factory) {
        typeof exports === 'object' && typeof module !== 'undefined' ? factory() :
        typeof define === 'function' && define.amd ? define(factory) :
    (factory());
    }(this, function () {
        // JavaScript chunk
        return {
           hello : () => console.log(‘hello from myModule’)
        }
    });

该模式根据内容来判断选择 AMD 仍是 CommonJS. 这种模式对于打包 多环境 的库,如 lodash 或者 moment.js 是十分适合的。

所以,为什么要加一个新模块类型 ?

首先,这些解决方案没有一个是由TC39团队定义的标准。ECMA6 如今已经被大量的开发者所使用,那为什么不选择该版本JS定义的标准(ES6模块)呢?

这个标准提供了一个更加灵活有力的解决方式。我推荐你看这篇文章, 了解 ES6模块的所有属性,由于这篇文章,我把重点放在了ES6模块这个性质上。它可以更加精确地定义模块间哪些须要被 exposed/imported 。一块儿看看下面的代码:

// file1.js
const f1 = ()=> console.log(‘f1’);
const f2 = ()=> console.log(‘f2’);
const f3 = ()=> console.log(‘f3’);
export {f1, f2, f3};

// file2.js
import {f1, f2} from “./file1”;
f1(); // display ‘f1’
f2(); // display ‘f2’

从这里能够看出,只须要静态地声明咱们想要 import 的内容就能够。与其它模式不一样,像 CommonJS 咱们能够动态加载须要的文件。若是咱们在 CommonJS 里面使用这个例子,就会有点不一样:

// file1.js
const f1 = ()=> console.log(‘f1’);
const f2 = ()=> console.log(‘f2’);
const f3 = ()=> console.log(‘f3’);
modules.exports = {f1,f2,f3};

// file2.js
const file1 = require(‘./file1’);
file1.f1(); // display ‘f1’
file1.f2(); // display ‘f2’
file1[process.ENV.funcName]();

很明显,最后一行没法呈现成真正的代码,但它代表了一些值超出了可控范围,没法在静态分析中被预知。这里,咱们实质上是能够调用 f3,由于用 CommonJs (AMD、IIFE 或者 UMD) 咱们都是没法限制 import 的内容。

tree-shacking

因此?了解代码的静态分析是使用什么是否是也很重要呢?

答案是确定的!

由于有了这个控制,开发者工具能够检测到一些 bug。 若是你使用 WebPack 2 或者 Rollup.js 将会更有趣,结合 Tree Shaking, 你编译的文件将会更小。Tree Shaking 的功能就是把不用用到的代码移除掉。

这就是 tree shaking 的一个例子 :

原文件
//-------------
// main.js
import {cube} from './maths.js';
console.log( cube( 5 ) ); // 125

//-------------
// maths.js
export function square ( x ) {
   return x * x;
}

// This function gets included
export function cube ( x ) {
   return x * x * x;
}
输出文件
function cube ( x ) {
   return x * x * x;
}

console.log( cube( 5 ) ); // 125

Mathieu Breton CTO chez JS-Republic

相关文章
相关标签/搜索