前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >五分钟带你回顾前端模块化发展史

五分钟带你回顾前端模块化发展史

作者头像
童欧巴
修改2020-05-08 17:30:19
7620
修改2020-05-08 17:30:19
举报
文章被收录于专栏:前端食堂前端食堂

微信搜索【前端食堂】你的前端食堂,记得按时吃饭。

本文已收录在前端食堂 Github https://github.com/Geekhyt/front-end-canteen,感谢Star。

CSS 早在 2.1 的版本就提出了 @import 来实现模块化,但是 JavaScript 直到 ES6 才出现官方的模块化方案 ES Module。尽管早期 JavaScript 语言规范上不支持模块化,但这并没有阻止 JavaScript 的发展。官方没有模块化标准,那么我们就自己动手创建标准。社区里的前辈们创建并实现了规范,这些规范便是前端模块化发展之路上智慧的结晶。

模块化的价值

2020 年的今天来看,模块化应该具有以下价值:

  • 可维护性
  • 减少全局污染
  • 可复用性
  • 方便管理依赖关系
  • 分治思想的实践

十年之前,模块化还只是使用「闭包」简单的实现一个命名空间。使用这种解决方式可以简单粗暴的处理全局变量和依赖关系等问题。

关于闭包的概念可以参考我的另一篇文章

CommonJS

让我们把时间追溯到 2009 年 1 月,在这个普通的冬天里,万物开始生长。中国南极科学考察站昆仑站落成,成为南极海拔最高的科学考察站。在 JavaScript 社区中, Mozilla 的工程师 Kevin Dangoor 发起了 CommonJS 的提案。(最初叫ServerJS)

再到后来横空出世的 Node.js 采用 CommonJS 模块化规范,同时还带来了 npm (全球最大的模块仓库) 。

「nodejs 中模块的实现并非完全按照 CommonJS 的规范来的,而是进行了取舍,并增加了少许特性。」

CommonJS 规范在服务端表现出色,使得 JavaScript 在服务器端大放异彩,与传统服务器语言(PHP、Python)等产生抗衡甚至压倒之势。程序员们便萌发出了将它移植到浏览器端的想法。

然而由于CommonJS的模块加载是同步的。我们知道,服务器端加载的模块从内存或磁盘中加载,耗时基本可忽略。但是在浏览器端却会造成阻塞,白屏时间过长,用户体验不够友好。

因此,从CommonJS中逐渐产生了一些分支,也就是业内熟知的AMDCMD等。

AMD规范

「James Burke」提出了 AMD 规范,RequireJS 也是他的代表作。他同时开发了 amdefine(在node中可以使用AMD规范的库)。

AMD 主要是为了解决 CommonJS 规范在浏览器端的不足:

  • 缺少模块封装的能力
  • 使用同步的方式加载依赖
  • export 只能导出变量,导出函数需要用 module.export (这通常不符合直觉)

AMD 规范定义了一个 define 全局方法用来定义和加载模块,RequireJS 后期也扩展了 require 全局方法用来加载模块 。「其核心实现是内部的模块加载器。」

CMD规范

「@玉伯」提出了 sea.js (CMD规范的实现)。

准确的说 CMDSeaJS 在推广过程中对模块定义的规范化产物。

相比于AMD的异步加载,CMD更倾向于懒加载,规范本身也与CommonJS更贴近。

因为是懒加载机制,所以 sea.js 提供了 seajs.use 方法,来运行已经定义的模块。所有 define 的回调函数都不会立即执行,而是将所有的回调函数进行缓存,只有 use 之后,以及被 require的模块回调才会执行。

RequireJS 和 sea.js 的区别

  • sea.js 只有在 require 的地方,才会真正执行模块。
  • RequireJS 会先运行所有的依赖,得到所有的结果后再执行回调。

AMD 和 CMD 区别

  • 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。
  • CMD 推崇依赖就近,AMD 推崇依赖前置。
  • AMDAPI 一个当多个用,职责单一。CMD 中,每个API都简单纯粹。

来自@玉伯的回答

https://www.zhihu.com/question/20351507/answer/14859415

UMD

UMDAMDCommonJS 的综合产物。AMD 用于浏览器,CommonJS 用于服务器。UMD 则是两者的兼容模式,解决了跨平台问题。

实现原理:if-else

详情请移步github

https://github.com/umdjs/umd

ES Module

天下大势,分久必合。

十年之后,官方爸爸推出的 ES6 模块化方案,一统浏览器和服务器。采用了完全静态化的方式进行模块加载。

语法

模块导入
代码语言:javascript
复制
// 默认导入default模块
// main.js
import name from './module.js'

// module.js
const name = '前端食堂'
export default name
代码语言:javascript
复制
// 如果想导入其他模块
// main.js
import { name, getName } from './module.js'

// module.js
export const name = '前端食堂'
export const getName = () => name
代码语言:javascript
复制
// 同时导入
// main.js
import  name, { getName } from './module.js'

// module.js
const name = '前端食堂'
export const getName = () => name
export default name
代码语言:javascript
复制
// 重命名
// main.js
import * as mod from './module.js'
let name = ''
name = mod.name
name = mod.getName()

// module.js
export const name = '前端食堂'
export const getName = () => name
代码语言:javascript
复制
// 对单独的变量进行重命名
import { name, getName as getModName }
模块导出
代码语言:javascript
复制
// 第一种写法
export const name = '前端食堂'

// 第二种写法
export function getName() {
    return name
}
export class Logger {
    log(...args) {
      console.log(...args)
    }
}

// 第三种写法
const name = '前端食堂'
function getName() {
	return name
}
class Logger {
    log(...args) {
      console.log(...args)
    }
}
export {name, getName, Logger}

// 第四种写法
const name = '前端食堂'
export default name

这里只提供了一些基本语法,更多语法请参考阮一峰老师的 《ECMAScript 6 入门》。

https://es6.ruanyifeng.com/#docs/module

当然,不同的规范之中,被规范的语法也有所不同,这里推荐业内公认的语法规范airbnb。

https://github.com/airbnb/javascript

这里列举出几个airbnb中模块导出/引入的规范。

1.如果模块只有一个输出值,就使用 export default ,如果模块有多个输出值,就不使用 export defaultexport default 与普通的 export 不要同时使用。

2.模块导入时不要使用通配符。因为这样可以确保你的模块之中,有一个默认输出 (export default)

代码语言:javascript
复制
// bad
import * as myObject from './importModule';

// good
import myObject from './importModule';

ES Module与CommonJS的差异

1.语法 import/export require/module

2.CommonJS 模块输出的是一个值的拷贝(不会随原始值变化),ES6 模块输出的是值的引用(会随着原始值变化)。

3.CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。

写在最后

❝成天讨论这门语言好,或者那门语言坏的人,甚至是可悲的。既悲其一叶障目,更悲其大愚若智的自得心态。 ——《大道至简》 ❞

JavaScrit 至今仍有被人诟病的缺憾之处。但历史告诉我们,再多的阻力也阻挡不了真正热爱它的人们。

感谢为 JavaScript 模块化之路贡献的开发者们。

微信搜索【前端食堂】你的前端食堂,记得按时吃饭。

本文已收录在前端食堂 Github https://github.com/Geekhyt/front-end-canteen,感谢Star。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端食堂 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 模块化的价值
  • CommonJS
  • AMD规范
  • CMD规范
    • RequireJS 和 sea.js 的区别
      • AMD 和 CMD 区别
      • UMD
      • ES Module
        • 语法
          • 模块导入
          • 模块导出
        • ES Module与CommonJS的差异
        • 写在最后
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档