AMD(异步模块定义)是为浏览器环境设计的,因为 CommonJS 模块系统是同步加载的,当前浏览器环境还没有准备好同步加载模块的条件。
AMD 定义了一套 JavaScript 模块依赖异步加载标准,来解决同步加载的问题。
模块通过 `define` 函数定义在闭包中,格式如下:
```js
define(id?: String, dependencies?: String[], factory: Function|Object);
```
`id` 是模块的名字,它是可选的参数。
`dependencies` 指定了所要依赖的模块列表,它是一个数组,也是可选的参数,每个依赖的模块的输出将作为参数一次传入 `factory` 中。如果没有指定 `dependencies`,那么它的默认值是 `["require", "exports", "module"]`。
```js
define(function(require, exports, module) {})
```
`factory` 是最后一个参数,它包裹了模块的具体实现,它是一个函数或者对象。如果是函数,那么它的返回值就是模块的输出接口或值。
一些用例:
定义一个名为 `myModule` 的模块,它依赖 `jQuery` 模块:
```js
define('myModule', ['jquery'], function($) {
// $ 是 jquery 模块的输出
$('body').text('hello world');
});
// 使用
define(['myModule'], function(myModule) {});
```
注意:在 webpack 中,模块名只有局部作用域,在 Require.js 中模块名是全局作用域,可以在全局引用。
定义一个没有 `id` 值的匿名模块,通常作为应用的启动函数:
```js
define(['jquery'], function($) {
$('body').text('hello world');
});
```
依赖多个模块的定义:
```js
define(['jquery', './math.js'], function($, math) {
// $ 和 math 一次传入 factory
$('body').text('hello world');
});
```
模块输出:
```js
define(['jquery'], function($) {
var HelloWorldize = function(selector){
$(selector).text('hello world');
};
// HelloWorldize 是该模块输出的对外接口
return HelloWorldize;
});
```
在模块定义内部引用依赖:
```js
define(function(require) {
var $ = require('jquery');
$('body').text('hello world');
});
----------------------------------------------------------------------------------------------------
# CommonJS 规范
CommonJS 是以在浏览器环境之外构建 JavaScript 生态系统为目标而产生的项目,比如在服务器和桌面环境中。
这个项目最开始是由 Mozilla 的工程师 Kevin Dangoor 在2009年1月创建的,当时的名字是 ServerJS。
> 我在这里描述的并不是一个技术问题,而是一件重大的事情,让大家走到一起来做决定,迈出第一步,来建立一个更大更酷的东西。 —— Kevin Dangoor's [What Server Side JavaScript needs](http://www.blueskyonmars.com/2009/01/29/what-server-side-javascript-needs/)
2009年8月,这个项目改名为 CommonJS,以显示其 API 的更广泛实用性。CommonJS 是一套规范,它的创建和核准是开放的。这个规范已经有很多版本和具体实现。CommonJS 并不是属于 ECMAScript TC39 小组的工作,但 TC39 中的一些成员参与 CommonJS 的制定。2013年5月,Node.js 的包管理器 NPM 的作者 Isaac Z. Schlueter 说 [CommonJS 已经过时,Node.js 的内核开发者已经废弃了该规范](https://github.com/nodejs/node-v0.x-archive/issues/5132#issuecomment-15432598)。
CommonJS 规范是为了解决 JavaScript 的作用域问题而定义的模块形式,可以使每个模块它自身的命名空间中执行。该规范的主要内容是,模块必须通过 `module.exports` 导出对外的变量或接口,通过 `require()` 来导入其他模块的输出到当前模块作用域中。
一个直观的例子:
```js
// moduleA.js
module.exports = function( value ){
return value * 2;
}
```
```js
// moduleB.js
var multiplyBy2 = require('./moduleA');
var result = multiplyBy2(4);
```
CommonJS 是同步加载模块,但其实也有浏览器端的实现,其原理是现将所有模块都定义好并通过 `id` 索引,这样就可以方便的在浏览器环境中解析了,可以参考 [require1k](https://github.com/Stuk/require1k) 和 [tiny-browser-require](https://github.com/ruanyf/tiny-browser-require) 的源码来理解其解析(resolve)的过程。
更多关于 CommonJS 规范的内容请查看 [http://wiki.commonjs.org/wiki/CommonJS](http://wiki.commonjs.org/wiki/CommonJS)。
----------------------------------------------------------------------------------------------
# 配置文件
Webpack 在执行的时候,除了在命令行传入参数,还可以通过指定的配置文件来执行。默认情况下,会搜索当前目录的 `webpack.config.js` 文件,这个文件是一个 node.js 模块,返回一个 json 格式的配置信息对象,或者通过 `--config` 选项来指定配置文件。
继续我们的案例,在根目录创建 `package.json` 来添加 webpack 需要的依赖:
```js
{
"name": "webpack-example",
"version": "1.0.0",
"description": "A simple webpack example.",
"main": "bundle.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"webpack"
],
"author": "zhaoda",
"license": "MIT",
"devDependencies": {
"css-loader": "^0.21.0",
"style-loader": "^0.13.0",
"webpack": "^1.12.2"
}
}
```
```bash
# 如果没有写入权限,请尝试如下代码更改权限
chflags -R nouchg .
sudo chmod 775 package.json
```
别忘了运行 `npm install`。
然后创建一个配置文件 `webpack.config.js`:
```js
var webpack = require('webpack')
module.exports = {
entry: './entry.js',
output: {
path: __dirname,
filename: 'bundle.js'
},
module: {
loaders: [
{test: /\.css$/, loader: 'style!css'}
]
}
}
```
同时简化 `entry.js` 中的 `style.css` 加载方式:
```js
require('./style.css')
```
最后运行 `webpack`,可以看到 webpack 通过配置文件执行的结果和上一章节通过命令行 `webpack entry.js bundle.js --module-bind 'css=style!css'` 执行的结果是一样的。
-----------------------------------------------------------------------------
# 开发环境
当项目逐渐变大,webpack 的编译时间会变长,可以通过参数让编译的输出内容带有进度和颜色。
```bash
$ webpack --progress --colors
```
如果不想每次修改模块后都重新编译,那么可以启动监听模式。开启监听模式后,没有变化的模块会在编译后缓存到内存中,而不会每次都被重新编译,所以监听模式的整体速度是很快的。
```bash
$ webpack --progress --colors --watch
```
当然,使用 `webpack-dev-server` 开发服务是一个更好的选择。它将在 localhost:8080 启动一个 express 静态资源 web 服务器,并且会以监听模式自动运行 webpack,在浏览器打开 http://localhost:8080/ 或 http://localhost:8080/webpack-dev-server/ 可以浏览项目中的页面和编译后的资源输出,并且通过一个 socket.io 服务实时监听它们的变化并自动刷新页面。
```bash
# 安装
$ npm install webpack-dev-server -g
# 运行
$ webpack-dev-server --progress --colors
```
网友评论