一、理解
1.1 什么是模块化
-
将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起
-
块的内部数据/实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信
-
模块化的进化史
-
最早
-
简单封装:Namespace模式
-
匿名闭包:IIFE模式
-
再增强一点:引入依赖
-
1.2 为什么要模块化
1.3 模块化的好处
- 避免命名冲突(减少命名空间污染)
- 更好的分离, 按需加载
- 更高复用性
- 高可维护性
1.4 页面引引入script
问题:
- 请求过多
- 依赖模糊
- 难以维护
二、模块化规范
2.1 CommonJS
2.1.1 规范
2.1.1.1 说明
- http://wiki.commonjs.org/wiki/Modules/1.1
- 每个文件都可当作一个模块
- 在服务器端: 模块的加载是运行时同步加载的
- 在浏览器端: 模块需要提前编译打包处理
2.1.1.2 基本语法
-
暴露模块
module.exports = value
exports.xxx = value
问题: 暴露的模块到底是什么?
-
引入模块:require(xxx)
第三方模块:xxx为模块名
自定义模块: xxx为模块文件路径
2.1.1.3 module.exports和exports的区别
Node.js:模块化思想中一个Javascript文件分析以及exports 和 module.exports的区别
2.1.2 实现
2.1.2.1 服务器端实现
Node.js
http://nodejs.cn/
2.1.2.2 浏览器端实现
Browserify
http://browserify.org/
也称为CommonJS的浏览器端的打包工具
-
打包处理JS命令
browserify 源文件 -o 目标文件
browserify js/src/app.js -o js/dist/bundle.js // out
-
打包处理后直接引入目标文件即可
2.1.2.3 区别Node与Browserify
- Node.js运行时动态加载模块(同步)
- Browserify是在转译(编译)时就会加载打包(合并)require的模块
2.2 AMD
2.2.1 规范
2.2.1.1 说明
Asynchronous Module Definition(异步模块定义)
https://github.com/amdjs/amdjs-api/wiki/AMD
专门用于浏览器端, 模块的加载是异步的
2.2.1.2 基本语法
-
定义暴露模块
//定义没有依赖的模块 define(function(){ return 模块 })
//定义有依赖的模块 define(['module1', 'module2'], function(m1, m2){ return 模块 })
-
引入使用模块
require(['module1', 'module2'], function(m1, m2){ 使用m1/m2 })
2.2.2 实现(浏览器端)
Require.js
http://www.requirejs.cn/
http://www.ruanyifeng.com/blog/2012/11/require_js.html
-
如果没有AMD等,原生引入
-
自定义模块
-
第三方模块
注意:由于jQuery在源码中支持了AMD规范,并且自定义了名称,因此只能使用
jquery
注意Plus:有些第三方库需要进行额外配置,例如
angular.js
2.3 CMD
2.3.1 规范
2.3.1.1 说明
Common Module Definition(通用模块定义)
https://github.com/seajs/seajs/issues/242
专门用于浏览器端, 模块的加载是异步的
模块使用时才会加载执行
2.3.1.2 基本语法
-
定义暴露模块
//定义没有依赖的模块 define(function(require, exports, module){ exports.xxx = value module.exports = value })
//定义有依赖的模块 define(function(require, exports, module){ //引入依赖模块(同步) var module2 = require('./module2') //引入依赖模块(异步) require.async('./module3', function (m3) { }) //暴露模块 exports.xxx = value })
-
引入使用模块
define(function (require) { var m1 = require('./module1') var m4 = require('./module4') m1.show() m4.show() })
2.3.2 实现(浏览器端)
Sea.js
http://www.zhangxinxu.com/sp/seajs/
2.4 ES6
2.4.1 规范
2.4.1.1 说明
http://es6.ruanyifeng.com/#docs/module
依赖模块需要编译打包处理
2.4.1.2 语法
导出模块: export
引入模块: import
2.4.2 实现(浏览器端)
-
常规暴露:分别暴露和统一暴露,引入的时候需要使用解构的方式
-
默认暴露:可以暴露任意数据类型,暴露什么数据就接收什么数据
在根目录下创建.babelrc
文件,并添加一下内容
{
"presets": [
"es2015"
]
}
使用Babel将ES6编译为ES5代码
-
babel 源文件夹 -d 目标文件夹
babel js/src -d js/lib
使用Browserify将CommonJS规范打包编译为浏览器可识别的代码
-
browserify 源文件 -o 目标文件
browserify js/lib/main.js -o js/dist/bundle.js
-
browserify必须创建文件夹,babel可以自动创建文件夹
使用Browserify编译打包js
2.4.3 注意
- 在采用分别暴露或统一暴露(常规暴露)的时候,是引入的时候,必须使用解构赋值的方式
三、扩展阅读
- https://github.com/seajs/seajs/issues/588(前端模块化开发那点历史)
- http://zccst.iteye.com/blog/2215317(CommonJS,AMD,CMD区别)
- http://www.zhihu.com/question/20351507/answer/14859415(AMD和CMD 的区别)
- http://www.ruanyifeng.com/blog/2012/10/javascript_module.html(Javascript模块化编程)