c 网站开发案例详解光盘,福州如何做百度的网站,微信网站是什么,传奇类网页游戏排行1 引言 如今#xff0c;Javascript 模块化规范非常方便、自然#xff0c;但这个新规范仅执行了 2 年#xff0c;就在 4 年前#xff0c;js 的模块化还停留在运行时支持#xff0c;10 年前#xff0c;通过后端模版定义、注释定义模块依赖。对经历过来的人来说#xff0c;…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): 这种模块化方式很简单暴力将所有模块塞到一个 sandbox 变量中硬伤是无法解决命名冲突问题毕竟都塞到一个 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 年左右用的最多的还是 YUI2YUI2 是用 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 模块化最近出现的 script typemodule 方式虽然还没有得到浏览器原生支持但也是我比较看好的未来趋势这样就连 webpack 的拆包都不需要了直接把源代码传到服务器配合 http2.0 完美抛开预编译的枷锁。
上述三种方案都不依赖预编译分别实现了 html、css、js 模块化相信这就是未来。
模块化标准推进速度仍然缓慢 2015 年提出的标准在 17 年依然没有得到实现即便在 nodejs 端。 这几年 TC39 对语言终于重视起来了慢慢有动作了但针对模块标准制定的速度与落实都非常缓慢与 javascript 越来越流行的趋势逐渐脱节。nodejs 至今也没有实现 ES2015 模块化规范所有 jser 都处在构建工具的阴影下。
Http 2.0 对 js 模块化的推动 js 模块化定义的再美好浏览器端的支持粒度永远是瓶颈http 2.0 正是考虑到了这个因素大力支持了 ES 2015 模块化规范。 幸运的是模块化构建将来可能不再需要。随着 HTTP/2 流行起来请求和响应可以并行一次连接允许多个请求对于前端来说宣告不再需要在开发和上线时再做编译这个动作。
几年前模块化几乎是每个流行库必造的轮子YUI、Dojo、Angular大牛们自己爽的同时其实造成了社区的分裂很难积累。有了 ES2015 Modules 之后JS 开发者终于可以像 Java 开始者十年前一样使用一致的方式愉快的互相引用模块。
不过 ES2015 Modules 也只是解决了开发的问题由于浏览器的特殊性还是要经过繁琐打包的过程等 ImportExport 和 HTTP 2.0 被主流浏览器支持那时候才是彻底的模块化。
Http 2.0 后就不需要构建工具了吗 看到大家基本都提到了 HTTP/2对这项技术解决前端模块化及资源打包等工程问题抱有非常大的期待。很多人也认为 HTTP/2 普及后基本就没有 Webpack 什么事情了。 不过 Webpack 作者 sokra 在他的文章 webpack HTTP/2 里提到了一个新的 Webpack 插件 AggressiveSplittingPlugin。简单的说这款插件就是为了充分利用 HTTP/2 的文件缓存能力将你的业务代码自动拆分成若干个数十 KB 的小文件。后续若其中任意一个文件发生变化可以保证其他的小 chunk 不需要重新下载。
可见即使不断的有新技术出现也依然需要配套的工具来将前端工程问题解决方案推向极致。
模块化是大型项目的银弹吗 只要遵循了最新模块化规范就可以使项目具有最好的可维护性吗 Js 模块化的目的是支持前端日益上升的复杂度但绝不是唯一的解决方案。 分析下 JavaScript 为什么没有模块化为什么又需要模块化这个 95 年被设计出来的时候语言的开发者根本没有想到它会如此的大放异彩也没有将它设计成一种模块化语言。按照文中的说法99 年也就是 4 年后开始出现了模块化的需求。如果只有几行代码用模块化是扯初始的 web 开发业务逻辑都写在 server 端js 的作用小之又小。而现在 spa 都出现了几乎所有的渲染逻辑都在前端如果还是没有模块化的组织开发过程会越来越难维护也是更痛苦。
文中已经详细说明了模块化的发展和优劣这里不准备做过多的讨论。我想说的是在模块化之后还有一个模块间耦合的问题如果模块间耦合度大也会降低代码的可重用性或者说复用性。所以也出现了降低耦合的观察者模式或者发布/订阅模式。这对于提升代码重用复用性和避免单点故障等都很重要。说到这里还想顺便提一下最近流行起来的响应式编程RxJS响应式编程中有一个很核心的概念就是 observable也就是 Rx 中的流stream。它可以被 subscribe其实也就是观察者设计模式。
补充阅读
JavaScript 模块化七日谈JavaScript 模块化编程简史2009-2016
总结
未来前端复杂度不断增加已成定论随着后端成熟自然会将焦点转移到前端领域而且服务化、用户体验越来越重要前端体验早不是当初能看就行任何网页的异常、视觉的差异或文案的模糊都会导致用户流失支付中断。前端对公司营收的影响渐渐与后端服务宕机同等严重所以前端会越来越重异常监控性能检测工具链可视化等等都是这几年大家逐渐重视起来的。
我们早已不能将 javascript 早期玩具性质的模块化方案用于现代越来越重要的系统中前端界必然出现同等重量级的模块化管理方案感谢 TC39 制定的 ES2015 模块化规范我们已经离不开它哪怕所有人必须使用 babel。
话说回来标准推进的太慢我们还是把编译工具当作常态抱着哪怕支持了 ES2015 所有特性babel 依然还有用的心态将预编译进行到底。一句话模块化仍在路上。js 模块化的矛头已经对准了 css 与 html这两位元老也该向前卫的 js 学习学习了。
未来 css、html 的模块化会自立门户还是赋予 js 更强的能力让两者的模块化依附于 js 的能力呢目前 html 有自立门户的苗头htmlModules而 css 迟迟没有改变社区出现的 styled-component 已经用 js 将 css 模块化得很好了最新 css 规范也支持了与 js 的变量通信难道希望依附于 js 吗这里希望得到大家更广泛的讨论。
我也认同毕竟压缩、混淆、md5、或者利用 nonce 属性对 script 标签加密都离不开本地构建工具。
据说 http2 的优化中有个最佳文件大小与数量的比例那么还是脱离不了构建工具前端未来会越来越复杂同时也越来越美好。
至此对于 javascript 模块化讨论已接近尾声对其优缺点也基本达成了一致。前端复杂度不断提高促使着模块化的改进代理浏览器、node 的支持程度与前端特殊性流量、缓存可能前端永远也离不开构建工具新的标准会让这些工作做的更好同时取代、增强部分特征前端的未来是更加美好的复杂度也更高。