目录
什么是模块化?为什么要模块化?
模块化是指将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起,块的内部数据与实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信
很久以前,开发网页要通过命名空间的方式来组织代码,例如 jQuery 库把它的API都放在了 window.$ 下,在加载完 jQuery 后其他模块再通过 window.$ 去使用 jQuery。 这样做有很多问题,其中包括:
命名空间冲突,两个库可能会使用同一个名称,例如 Zepto 也被放在 window.$ 下;
无法合理地管理项目的依赖和版本;
无法方便地控制依赖的加载顺序。
当项目变大时这种方式将变得难以维护,需要用模块化的思想来组织代码。
模块化的几种规范
CommonJS
用法:
// 导入
const moduleA = require('./moduleA');
// 导出
module.exports = moduleA.someFunc;
优点:
代码可复用于 Node.js 环境下并运行,例如做同构应用;
通过 NPM 发布的很多第三方模块都采用了 CommonJS 规范。
缺点:
代码无法直接运行在浏览器环境下,必须通过工具转换成标准的 ES5
CommonJS规范运行在node端非常流行,因为CommonJS是同步的,而node端资源加载快
补充:
CommonJS 还可以细分为 CommonJS1 和 CommonJS2,区别在于 CommonJS1 只能通过 exports.XX = XX 的方式导出,CommonJS2 在 CommonJS1 的基础上加入了 module.exports = XX 的导出方式。 CommonJS 通常指 CommonJS2。
AMD
AMD 也是一种 JavaScript 模块化规范,与 CommonJS 最大的不同在于它采用异步的方式去加载依赖的模块。 AMD 规范主要是为了解决针对浏览器环境的模块化问题,最具代表性的实现是 requirejs。
用法:
// 定义一个模块(利用exports暴露)
define('module', ['dep'], function(dep) {
return exports;
});
// 导入和使用
require(['module'], function(module) {
});
优点:
可在不转换代码的情况下直接在浏览器中运行;
可异步加载依赖;
可并行加载多个依赖;
代码可运行在浏览器环境和 Node.js 环境下。
缺点:
JavaScript 运行环境没有原生支持 AMD,需要先导入实现了 AMD 的库后才能正常使用
CMD
CMD规范是国内发展出来的,CMD有个浏览器的实现SeaJS,SeaJS要解决的问题和requireJS一样,只不过在模块定义方式和模块加载(可以说运行、解析)时机上有所不同
用法:
// 定义模块 myModule.js (利用exports暴露)
define(function(require, exports, module) {
var $ = require('jquery.js')
$('div').addClass('active');
});
// 加载模块
seajs.use(['myModule.js'], function(my){
});
与AMD的区别:
最明显的区别就是在模块定义时对依赖的处理不同
AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块
CMD推崇就近依赖,只有在用到某个模块的时候再去require
这种区别各有优劣,只是语法上的差距,而且requireJS和SeaJS都支持对方的写法
AMD和CMD最大的区别是对依赖模块的执行时机处理不同,注意不是加载的时机或者方式不同,这两种的是异步的
ES6 模块化
ES6 模块化是欧洲计算机制造联合会 ECMA 提出的 JavaScript 模块化规范,它在语言的层面上实现了模块化。浏览器厂商和 Node.js 都宣布要原生支持该规范。它将逐渐取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
用法:
// 导入
import { readFile } from 'fs';
import React from 'react';
// 导出
export function hello() {};
export default {
// ...
};
缺点:
ES6模块虽然是终极模块化方案,但它的缺点在于目前无法直接运行在大部分 JavaScript 运行环境下,必须通过工具转换成标准的 ES5 后才能正常运行。
样式文件中的模块化
除了 JavaScript 开始模块化改造,前端开发里的样式文件也支持模块化。 以 SCSS 为例,把一些常用的样式片段放进一个通用的文件里,再在另一个文件里通过 @import 语句去导入和使用这些样式片段。
用法:
// util.scss 文件
// 定义样式片段
@mixin center {
// 水平竖直居中
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}
// main.scss 文件
// 导入和使用 util.scss 中定义的样式片段
@import "util";
#box{
@include center;
}
参考资料
前端模块化,AMD与CMD的区别:https://juejin.im/post/5a422b036fb9a045211ef789
深入浅出 Webpack