JS模块化梳理

39 阅读2分钟

什么是模块化?

模块化主要是为了实现代码可复用,一个模块拥有独立的作用域,避免多个功能模块定义的变量冲突,防止全局污染。同时通过模块化的代码拆分,拥有更规范的代码结构,增强代码的维护性,提高开发效率。有了模块化后,就可以根据需要加载对应的功能模块,减少代码体积的同时也使代码结构更直观。在早些时候,JavaScript并没有其官方支持的模块化,为了应对多种场景需求,社区中出现了多种规范,其中包括AMD、CMD、UMD、CJS、ESM,其中ESM是ES6中原生支持的,是现在以及将来主要使用的规范。

模块化的分类

CJS规范

CommonJS的缩写,用于后端,在nodejs中的模块化,使用的是common.js规范。一个文件就是一个模块,通过require导入模块,module.export或exports导出模块。模块可以多次加载,但只会在第一次加载执行一次,然后运行结果就会被缓存,模块加载的顺序是按照其在代码中出现的顺序加载的。

由于用户可以动态 require,无法做到提前分析依赖以及Tree-Shaking。CommonJS 规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。

// 文件名: foo.js
var $ = require('jquery'); // 导入模块// 暴露公共方法(一个)
function myFunc(){};
​
module.exports = myFunc; // 导出方法

AMD规范

AMD即 Asynchronous Module Definition 的缩写,代表异步模块定义,它是一个概念,并不是一个真实的规范标准,RequireJS是对这个概念的实现,可以实现异步加载文件。通过define()函数定义,接收两个参数,第一个参数是一个数组,数组里定义了一些需要依赖的包,第二个参数是一个回调函数,当依赖可用时调用此回调函数,并且参数就是依赖的包变量。

// 文件名: foo.js
define(['jquery'], function ($) {
    function myFunc(){};
    // 暴露公共方法
    return myFunc;
});

UMD规范

UMD是 Universal Module Definition 的缩写,代表通用模块定义。是一种通用的写法,在AMD和CJS流行而不统一的情况下,催生出了UMD来统一规范,所以UMD同时兼容 CJS 和 AMD,前后端通用。

(function(root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node, CommonJS之类的
        module.exports = factory(require('jquery'));
    } else {
        // 浏览器全局变量(root 即 window)
        root.returnExports = factory(root.jQuery);
    }
}(this, function($) {
    function myFunc() {};
    // 暴露公共方法
    return myFunc;
}));

CMD规范

CMD规范是在sea.js推广过程中对模块定义的规范化产出。sea.js是淘宝团队提供的一个模块化开发框架,是一个同步模块定义,通过define()定义,通过require加载。与AMD类型,区别是CMD没有依赖前置,它是依赖就近,在什么地方使用到插件就在什么地方require该插件,即用即返,是一个同步的概念。

define(function(require, exports, module){
  var $ = require('jquery.js');
  function myFunc() {};
  exports.myFunc = myFunc;
})

ESM规范

ESM是 ECMAScript Module 的缩写,是ES6原生支持的,使用 import、export 来管理依赖。由于它们只能写在所有表达式外面,所以打包器可以轻易做到分析依赖以及 Tree-Shaking。ESM 也支持动态加载(import )。浏览器直接通过 <script type="module"> 即可使用该写法。

export 向外暴露或导出模块 export default xxx;

import 引入模块 import { xxx } from './xxx';

import React from 'react';
​
export default MyFunc(){};

总结

  • 由于 ESM 具有简单的语法,异步特性和可摇树性,因此它是最好的模块化方案
  • UMD 随处可见,通常在 ESM 不起作用的情况下用作备用
  • CJS 是同步的,适合后端
  • AMD 是异步的,适合前端