上一篇文章《前端工程化-序言》中提到”项目复杂度”的问题。
文章开头,其实可以先思考一下,项目复杂度为什么会提升?
- 不好的开发习惯,没有规范?
- 单文件、巨石代码?
- 命令式编程,毫无章法可言?
结论是肯定的,大部分场景的项目复杂度的提升都离不开以上的三种原因,当然也有别的原因,我这里暂时先列举这三种主要的。
所以,前端开发的思想以及技术要革新,模块化技术也随之更替演变。
模块化之function
-猿猴模式
借助函数实现模块化,最终还是暴露在 window
上,内部封闭了若干常量。
function getEnvUrl() {
return {
qa: 'test.xxx',
pre: 'pre.xxx',
prod: 'prod.xxx'
}
}
function getGatwayByEnv() {
return {
qa: 'test.gatway.xxx',
pre: 'pre.gatway.xxx',
prod: 'prod.gatway.xxx'
}
}
const qaUrl = getEnvUrl().qa;
- 缺点
- 容易明名冲突
- 模块函数众多,且毫无关联
改进:
- 可以作函数聚合、函数收敛
模块化之namespace
-原始人
使用全局变量聚合所有函数模块以及常量模块;
var __module__ = {
__vars: {
env: ['qa', 'pre', 'prod']
},
// ...
}
// 严格意义上等同于 window.__module__
- 优点:
- 避免了命名冲突
- 缺点:
- 外部容易修改
改进: Object.freeze
冻结对象属性。
模块化之IIFE
-山顶洞人
闭包实现模块化,保证内部的变量私有化,只暴露访问函数,外部无法改变内部私有化变量;
;(function (root) {
var x = 1;
const getX = () => x;
root.__XModule = {
getX
};
})(window)
;(function (root, xModule) {
root.__YModule = xModule.getX();
})(window, window.__XModule)
- 好处
- 解决了私有化变量的问题
- 解决了模块之间互相引用的问题
籍此,早起模块化的实现方案就此诞生了,但是按照早期的方案而言,一个项目中如果存在若干个模块就势必会出现若干个 script
标签。
由此导致的后果就是: 拖慢应用加载速度,牺牲用户的体验,流量流失。
在介绍现代模块化的前面,这里先解释下,模块化到底是什么?
模块化是 规范,不是 实现。
- Node
- commonjs
- esmodule
- mjs
- Browser
- amd
- cmd
- esmodule
- Node & Browser
- umd
本篇文章暂时不具体介绍 amd
、cmd
规范,因为目前基本不再使用了。
CommonJs
CommonJs
规范,本身是基于 IIFE
机制实现的。
那么,可以思考:require
、module
等为什么可以直接使用?
模块加载时,自动注入。
;(function Module(require, module) {
})(require = () => 0, module = { exports: {} })
下面是 CommonJs
模块加载原理。
图片来源于:https://javascript.ruanyifeng.com/nodejs/module.html#toc14
- 特点
- 同步加载
- 运行时加载,会先加载一遍全模块,再缓存
- 模块输出是值拷贝
- 注意:是浅拷贝
ES Module
- 特点
- 同步/异步加载
- 编译时加载
- 模块输出是值引用
End
文章结束了,请思考一个问题:
模块化最终解决了什么问题?