1 引言

如今,Javascript 模块化规范非常方便、自然,但这个新规范仅执行了2年,就在 4 年前,js 的模块化还停留在运行时支持,10 年前,通过后端模版定义、注释定义模块依赖。对经历过来的人来说,历史的模块化方式还停留在脑海中,反而新上手的同学会更快接受现代的模块化规范。

但为什么要了解 Javascript 模块化发展的历史呢?因为凡事都有两面性,了解 Javascript 模块化规范,有利于我们思考出更好的模块化方案,纵观历史,从 1999 年开始,模块化方案最多维持两年,就出现了新的替代方案,比原有的模块化更清晰、强壮,我们不能被现代模块化方式限制住思维,因为现在的 ES2015 模块化方案距离发布也仅仅过了两年。

2 内容概要

直接定义依赖 (1999): 由于当时 js 文件非常简单,模块化方式非常简单粗暴 —— 通过全局方法定义、引用模块。这种定义方式与现在的 commonjs 非常神似,区别是 commonjs 以文件作为模块,而这种方法可以在任何文件中定义模块,模块不与文件关联。

闭包模块化模式 (2003): 用闭包方式解决了变量污染问题,闭包内返回模块对象,只需对外暴露一个全局变量。

模版依赖定义 (2006): 这时候开始流行后端模版语法,通过后端语法聚合 js 文件,从而实现依赖加载,说实话,现在 go 语言等模版语法也很流行这种方式,写后端代码的时候不觉得,回头看看,还是挂在可维护性上。

注释依赖定义 (2006): 几乎和模版依赖定义同时出现,与 1999 年方案不同的,不仅仅是模块定义方式,而是终于以文件为单位定义模块了,通过 lazyjs 加载文件,同时读取文件注释,继续递归加载剩下的文件。

外部依赖定义 (2007): 这种定义方式在 cocos2d-js 开发中普遍使用,其核心思想是将依赖抽出单独文件定义,这种方式不利于项目管理,毕竟依赖抽到代码之外,我是不是得两头找呢?所以才有通过 webpack 打包为一个文件的方式暴力替换为 commonjs 的方式出现。

Sandbox模式 (2009): 这种模块化方式很简单,暴力,将所有模块塞到一个 sanbox 变量中,硬伤是无法解决明明冲突问题,毕竟都塞到一个 sandbox 对象里,而 Sandbox 对象也需要定义在全局,存在被覆盖的风险。模块化需要保证全局变量尽量干净,目前为止的模块化方案都没有很好的做到这一点。

依赖注入 (2009): 就是大家熟知的 angular1.0,依赖注入的思想现在已广泛运用在 react、vue 等流行框架中。但依赖注入和解决模块化问题还差得远。

CommonJS (2009): 真正解决模块化问题,从 node 端逐渐发力到前端,前端需要使用构建工具模拟。

Amd (2009): 都是同一时期的产物,这个方案主要解决前端动态加载依赖,相比 commonJs,体积更小,按需加载。

Umd (2011): 兼容了 CommonJS 与 Amd,其核心思想是,如果在 commonjs 环境(存在 module.exports,不存在 define),将函数执行结果交给 module.exports 实现 Commonjs,否则用 Amd 环境的 define,实现 Amd。

Labeled Modules (2012): 和 Commonjs 很像了,没什么硬伤,但生不逢时,碰上 Commonjs 与 Amd,那只有被人遗忘的份了。

YModules (2013): 既然都出了 Commonjs Amd,文章还列出了此方案,一定有其独到之处。其核心思想在于使用 provide 取代 return,可以控制模块结束时机,处理异步结果;拿到第二个参数 module,修改其他模块的定义(虽然很有拓展性,但用在项目里是个搅屎棍)。

ES2015 Modules (2015): 就是我们现在的模块化方案,还没有被浏览器实现,大部分项目已通过 babel 或 typescript 提前体验。

3 精读

从语言层面到文件层面的模块化

从 1999 年开始,模块化探索都是基于语言层面的优化,真正的革命从 2009 年 CommonJS 的引入开始,前端开始大量使用预编译。

这篇文章所提供的模块化历史的方案都是逻辑模块化,从 CommonJS 方案开始前端把服务端的解决方案搬过来之后,算是看到标准物理与逻辑统一的模块化。但之后前端工程不得不引入模块化构建这一步。正是这一步给前端开发无疑带来了诸多的不便,尤其是现在我们开发过程中经常为了优化这个工具带了很多额外的成本。

从 CommonJS 之前其实都只是封装,并没有一套模块化规范,这个就有些像类与包的概念。我在10年左右用的最多的还是 YUI2,YUI2 是用 namespace 来做模块化的,但有很多问题没有解决,比如多版本共存,因此后来 YUI3 出来了。

YUI().use('node', 'event', function (Y) { // The Node and Event modules are loaded and ready to use. // Your code goes here!});

YUI3 的 sandbox 像极了差不多同时出现的 AMD 规范,但早期 yahoo 在前端圈的影响力还是很大的,而 requirejs 到 2011 年才诞生,因此圈子不是用着 YUI 要不就自己封装一套 sandbox,内部使用 jQuery。

为什么模块化方案这么晚才成型,可能早期应用的复杂度都在后端,前端都是非常简单逻辑。后来 Ajax 火了之后,web app 概念的开始流行,前端的复杂度也呈指数级上涨,到今天几乎和后端接近一个量级。工程发展到一定阶段,要出现的必然会出现。

前端三剑客的模块化展望

从 js 模块化发展史,我们还看到了 css html 模块化方面的严重落后,如今依赖编译工具的模块化增强在未来会被标准所替代。

原生支持的模块化,解决 html 与 css 模块化问题正是以后的方向。

再回到 JS 模块化这个主题,开头也说到是为了构建 scope,实则提供了业务规范标准的输入输出的方式。但文章中的 JS 的模块化还不等于前端工程的模块化,Web 界面是由 HTML、CSS 和 JS 三种语言实现,不论是 CommonJS 还是 AMD 包括之后的方案都无法解决 CSS 与 HTML 模块化的问题。

对于 CSS 本身它就是 global scope,因此开发样式可以说是喜忧参半。近几年也涌现把 HTML、CSS 和 JS 合并作模块化的方案,其中 react/css-modules 和 vue 都为人熟知。当然,这一点还是非常依赖于 webpack/rollup 等构建工具,让我们意识到在 browser 端还有很多本质的问题需要推进。

对于 css 模块化,目前不依赖预编译的方式是 styled-component,通过 js 动态创建 class。而目前 css 也引入了与 js 通信的机制 与 原生变量支持。未来 css 模块化也很可能是运行时的,所以目前比较看好 styled-component 的方向。

对于 html 模块化,小尤最近爆出与 chrome 小组调研 html Modules,如果 html 得到了浏览器,编辑器的模块化支持,未来可能会取代 jsx 成为最强大的模块化、模板语言。

对于 js 模块化,最近出现的

js define函数_聊聊JS模块化发展历程相关推荐

  1. js define函数_不夸张,这真的是前端圈宝藏书!360前端工程师Vue.js源码解析

    优秀源代码背后的思想是永恒的.普适的. 这些年来,前端行业一直在飞速发展.行业的进步,导致对从业人员的要求不断攀升.放眼未来,虽然仅仅会用某些框架还可以找到工作,但仅仅满足于会用,一定无法走得更远.随 ...

  2. js html字符串转对象,js eval函数使用,js对象和字符串互转.

    js eval函数使用,js对象和字符串互转. JavaScript eval() 函数  JavaScript 全局函数 定义和用法 eval() 函数计算 JavaScript 字符串,并把它作为 ...

  3. javascript模块化发展历程

    什么是模块化 ? 为什么要做Javascript模块化? JavaScript 模块化发展历程 什么是模块化 ? 模块化是一种处理复杂系统分解成为更好的可管理模块的方式,它可以把系统代码划分为一系列职 ...

  4. require js define 函数

    模块不同于传统的脚本文件,它良好地定义了一个作用域来避免全局名称空间污染.它可以显式地列出其依赖关系,并以函数(定义此模块的那个函数)参数的形式将这些依赖进行注入,而无需引用全局变量.RequireJ ...

  5. js 匿名函数_编写高质量箭头函数的5个最佳做法

    作者:Dmitri Pavlutin译者:前端小智 来源:dmitripavlutin.com 箭头功能值得流行.它的语法简洁明了,使用词法绑定绑定 this,它非常适合作为回调.在本文中,通过了解决 ...

  6. c2064 项不会计算为接受0个参数的函数_【JS必知必会】高阶函数详解与实战

    本文涵盖 前言 高级函数概念 函数作为参数的高阶函数 map filter reduce sort详解与实战 函数作为返回值的高阶函数 isType函数与add求和函数 如何自己创建高阶函数 前言 一 ...

  7. js 字符串截取_【js】让你一次性搞清楚slice,substr,substring字符串截取函数

    假设 str是个字符串变量,且设置值为"LittleAnn",字符长度是9 那么这三个函数使用方式: var 相同点: start为开始位置下标,end为结束位置下标 下标从0开始 ...

  8. js立即执行函数_《JS 函数的执行时机》

    1 .为什么如下代码会打印 6 个 6 let i = 0 for(i = 0; i<6; i++){setTimeout(()=>{console.log(i)},0) } 那是因为se ...

  9. js增加属性_前端js基础2

    JavaScript ECMAScript(ES):规定了js的一些基础的核心知识(变量.数据类型.语法规范.操作语句等) 3/5==6/7 说出ES5和ES6的区别? DOM:document ob ...

最新文章

  1. 编写spring应用
  2. POJ 1704 Georgia and Bob (Nim游戏变形)
  3. 库克笑了,说要给股东多分红:换了M1后Mac销售额增长70%,iPhone也增长66%
  4. Kotlin极简教程:第4章 基本数据类型与类型系统
  5. Scala的符号入门
  6. 第三章 组装个人计算机
  7. 2017年春季计算机试题,【2017年整理】计算机试题.doc
  8. 【蓝桥杯嵌入式】【STM32】10_InputCaputer之输入捕获
  9. 【Linux】解决Linux上解压jdk报错gzip: stdin: not in gzip format
  10. 哪个员工上班健身,定性考勤造假;哪个员工反映问题,考虑把他清退!华为HR实名内曝...
  11. swift5 修改Accessibility order读取的顺序
  12. 快解析:用友T+异地访问解决方案
  13. ubuntu 开机后 按键 鼠标不能用
  14. pyecharts动态图表嵌入ppt
  15. zrst指令是什么意思_三菱PLC梯形图所有指令符号是什么意思?
  16. 39. 组合总和(Python)
  17. 如何搭建一个超级好用的JavaWeb框架?
  18. 工艺路线和工序有差别吗_做为一名机械人,你知道机械加工工艺的流程吗?
  19. 微信支付企业付款到零钱
  20. SQL索引的创建和使用

热门文章

  1. [bzoj1547]周末晚会
  2. python3爬虫(2)下载有固定链接的视频
  3. 【Boost】boost库中thread多线程详解2——mutex与lock
  4. cocos2d-x游戏开发(十二)场景切换:滑门效果
  5. Gh0st源码学习(一)前期准备工作
  6. 基于WinDbg的内存泄漏分析
  7. 字符串匹配算法(二):BM(BoyerMoore)算法、坏字符规则,好后缀规则
  8. 深入理解RCU|核心原理
  9. Linux调度系统全景指南(终结篇)
  10. 搞懂 SQL 查询优化原理分析,秒速处理大数据量查询