js模块化建设历史:AMD、CJS、UMD、ESM

2024 年 7 月 10 日 星期三(已编辑)
/ , ,
4
摘要
JavaScript 起初是浏览器中的脚本语言,由于语法宽松,模块化需求不高,导致随着外部 JS 代码的增多,变量冲突频发。为解决这一问题,开发者采用闭包或 AMD 加载器(如 RequireJS)进行模块封装。随着 Node.js 的崛起,CJS(CommonJS)成为标准模块化方案,但这进一步加剧了 Node.js 和浏览器之间的差异。为兼容两者,UMD 模块化方案诞生,但最终被 ES2015 推出的 ESM 标准取代。虽然 ESM 在 Node.js 和浏览器中逐渐普及,但老的 CJS 模块仍需兼容适配,像 CoffeeScript 在某些情况下因 Node.js 的 CJS 限制无法正常运行。

阅读此文章之前,你可能需要首先阅读以下的文章才能更好的理解上下文。

js模块化建设历史:AMD、CJS、UMD、ESM

起初

最开始的js是用于浏览器的快速脚本语言

动态、宽松语法让许多代码得于以BUG的方式运行起来(((

但是最开始作为一个脚本语言,并没有考虑到js发展规模之快,以至于ES标准起初没有模块化的要求

随着外部js引入的逐渐增多,各类js的变量出现了冲突

为了解决这个办法,一部分是通过闭包,将自己的变量封装在一个大家基本不会使用的变量名上

比如 jQuery 这名老将,就以自己独特的占有率占用了$这个大变量

模块一多就不太好管理了,譬如现在的Node.js的npm一拉取webpack差不多就有150多个包

这么多模块的变量冲突在处理依赖的时间恐怕要比实际引入开发多得多

此时除了手动闭包冒出变量之外有了新的选择:那就是采用AMD加载器

例如像使用 RequireJS 这种 AMD 加载器,利用define()语法来

自动化帮我们闭包封装各自所需要的模块。

变革

随着谷歌花大价钱投入的V8引擎受到各种吹捧之后,

基于 Nodejs 的 JS 运行环境应运而生,

他类似 JVM、Rust标准库 一样,把电脑上的各类接口封装为统一的 API

例如:fs、http、fetch(> Node.js v13) 等打包好的轮子

通过 V8 引擎的跨平台通用性,我们可以很方便的翻阅文档,轻松调用这些 API

一套代码,只要是个能够支持浏览器运行的环境(主要是支持V8引擎)都可以顺利运行

在 Node.js 上,node开发团队不满足于这个抽象的AMD加载器

采用了CJS(CommonJS)模块化语法,不再使用define而是module.export这类关键字来构建模块

虽然js语法都一致,但是这造成了浏览器和Node.js的愈来愈割裂

统一

为了让Nodejs和浏览器能够同时支持CJS和AMD标准

更抽象的UMD模块化统一兼容层诞生了

本质上还是通过 Nodejs、AMD模块加载器、原生浏览器 对typeof的解析值不同所采用不同的方法

太暴力了,之后就被ESM拉清单了


(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['b'], factory);
    } else if (typeof module === 'object' && module.exports) {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like environments that support module.exports,
        // like Node.
        module.exports = factory(require('b'));
    } else {
        // Browser globals (root is window)
        root.returnExports = factory(root.b);
    }
}(typeof self !== 'undefined' ? self : this, function (b) {
    // Use b in some fashion.
    
    // Just return a value to define the module export.
    // This example returns an object, but the module
    // can return a function as the exported value.
    return {};
}));

终结

ES2015之后,以import export为模块化语法糖的ESM标准逐渐扩散,node、浏览器、typescript逐渐采用官方模块化ESM语法,但是对于老的模块,采用兼容模式,ESM和CJS混合在一些框架适配上仍无法正常工作

我们需要更多的UMD 2.0(((

因为我最喜欢的coffeescript,因为node的vm模块还在古老的CJS语法,不能正常运行,气死偶嘞

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...