AMD(異步模塊定義)是為瀏覽器環(huán)境設(shè)計(jì)的抖苦,因?yàn)?CommonJS 模塊系統(tǒng)是同步加載的贪绘,當(dāng)前瀏覽器環(huán)境還沒有準(zhǔn)備好同步加載模塊的條件。
AMD 定義了一套 JavaScript 模塊依賴異步加載標(biāo)準(zhǔn)受扳,來解決同步加載的問題序无。
模塊通過 `define` 函數(shù)定義在閉包中验毡,格式如下:
```js
define(id?: String, dependencies?: String[], factory: Function|Object);
```
`id` 是模塊的名字,它是可選的參數(shù)帝嗡。
`dependencies` 指定了所要依賴的模塊列表晶通,它是一個(gè)數(shù)組,也是可選的參數(shù)丈探,每個(gè)依賴的模塊的輸出將作為參數(shù)一次傳入 `factory` 中录择。如果沒有指定 `dependencies`拔莱,那么它的默認(rèn)值是 `["require", "exports", "module"]`碗降。
```js
define(function(require, exports, module) {})
```
`factory` 是最后一個(gè)參數(shù),它包裹了模塊的具體實(shí)現(xiàn)塘秦,它是一個(gè)函數(shù)或者對(duì)象讼渊。如果是函數(shù),那么它的返回值就是模塊的輸出接口或值尊剔。
一些用例:
定義一個(gè)名為 `myModule` 的模塊爪幻,它依賴 `jQuery` 模塊:
```js
define('myModule', ['jquery'], function($) {
// $ 是 jquery 模塊的輸出
$('body').text('hello world');
});
// 使用
define(['myModule'], function(myModule) {});
```
注意:在 webpack 中,模塊名只有局部作用域须误,在 Require.js 中模塊名是全局作用域挨稿,可以在全局引用。
定義一個(gè)沒有 `id` 值的匿名模塊京痢,通常作為應(yīng)用的啟動(dòng)函數(shù):
```js
define(['jquery'], function($) {
$('body').text('hello world');
});
```
依賴多個(gè)模塊的定義:
```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 是該模塊輸出的對(duì)外接口
return HelloWorldize;
});
```
在模塊定義內(nèi)部引用依賴:
```js
define(function(require) {
var $ = require('jquery');
$('body').text('hello world');
});
----------------------------------------------------------------------------------------------------
# CommonJS 規(guī)范
CommonJS 是以在瀏覽器環(huán)境之外構(gòu)建 JavaScript 生態(tài)系統(tǒng)為目標(biāo)而產(chǎn)生的項(xiàng)目奶甘,比如在服務(wù)器和桌面環(huán)境中。
這個(gè)項(xiàng)目最開始是由 Mozilla 的工程師 Kevin Dangoor 在2009年1月創(chuàng)建的祭椰,當(dāng)時(shí)的名字是 ServerJS臭家。
> 我在這里描述的并不是一個(gè)技術(shù)問題疲陕,而是一件重大的事情,讓大家走到一起來做決定钉赁,邁出第一步蹄殃,來建立一個(gè)更大更酷的東西。 —— Kevin Dangoor's [What Server Side JavaScript needs](http://www.blueskyonmars.com/2009/01/29/what-server-side-javascript-needs/)
2009年8月你踩,這個(gè)項(xiàng)目改名為 CommonJS诅岩,以顯示其 API 的更廣泛實(shí)用性。CommonJS 是一套規(guī)范带膜,它的創(chuàng)建和核準(zhǔn)是開放的按厘。這個(gè)規(guī)范已經(jīng)有很多版本和具體實(shí)現(xiàn)。CommonJS 并不是屬于 ECMAScript TC39 小組的工作钱慢,但 TC39 中的一些成員參與 CommonJS 的制定逮京。2013年5月,Node.js 的包管理器 NPM 的作者 Isaac Z. Schlueter 說 [CommonJS 已經(jīng)過時(shí)束莫,Node.js 的內(nèi)核開發(fā)者已經(jīng)廢棄了該規(guī)范](https://github.com/nodejs/node-v0.x-archive/issues/5132#issuecomment-15432598)懒棉。
CommonJS 規(guī)范是為了解決 JavaScript 的作用域問題而定義的模塊形式,可以使每個(gè)模塊它自身的命名空間中執(zhí)行览绿。該規(guī)范的主要內(nèi)容是策严,模塊必須通過 `module.exports` 導(dǎo)出對(duì)外的變量或接口,通過 `require()` 來導(dǎo)入其他模塊的輸出到當(dāng)前模塊作用域中饿敲。
一個(gè)直觀的例子:
```js
// moduleA.js
module.exports = function( value ){
return value * 2;
}
```
```js
// moduleB.js
var multiplyBy2 = require('./moduleA');
var result = multiplyBy2(4);
```
CommonJS 是同步加載模塊妻导,但其實(shí)也有瀏覽器端的實(shí)現(xiàn),其原理是現(xiàn)將所有模塊都定義好并通過 `id` 索引怀各,這樣就可以方便的在瀏覽器環(huán)境中解析了倔韭,可以參考 [require1k](https://github.com/Stuk/require1k) 和 [tiny-browser-require](https://github.com/ruanyf/tiny-browser-require) 的源碼來理解其解析(resolve)的過程。
更多關(guān)于 CommonJS 規(guī)范的內(nèi)容請(qǐng)查看 [http://wiki.commonjs.org/wiki/CommonJS](http://wiki.commonjs.org/wiki/CommonJS)瓢对。
----------------------------------------------------------------------------------------------
# 配置文件
Webpack 在執(zhí)行的時(shí)候寿酌,除了在命令行傳入?yún)?shù),還可以通過指定的配置文件來執(zhí)行硕蛹。默認(rèn)情況下醇疼,會(huì)搜索當(dāng)前目錄的 `webpack.config.js` 文件,這個(gè)文件是一個(gè) node.js 模塊法焰,返回一個(gè) json 格式的配置信息對(duì)象秧荆,或者通過 `--config` 選項(xiàng)來指定配置文件。
繼續(xù)我們的案例埃仪,在根目錄創(chuàng)建 `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
# 如果沒有寫入權(quán)限乙濒,請(qǐng)嘗試如下代碼更改權(quán)限
chflags -R nouchg .
sudo chmod? 775 package.json
```
別忘了運(yùn)行 `npm install`。
然后創(chuàng)建一個(gè)配置文件 `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'}
]
}
}
```
同時(shí)簡化 `entry.js` 中的 `style.css` 加載方式:
```js
require('./style.css')
```
最后運(yùn)行 `webpack`贵试,可以看到 webpack 通過配置文件執(zhí)行的結(jié)果和上一章節(jié)通過命令行 `webpack entry.js bundle.js --module-bind 'css=style!css'` 執(zhí)行的結(jié)果是一樣的琉兜。
-----------------------------------------------------------------------------
# 開發(fā)環(huán)境
當(dāng)項(xiàng)目逐漸變大凯正,webpack 的編譯時(shí)間會(huì)變長,可以通過參數(shù)讓編譯的輸出內(nèi)容帶有進(jìn)度和顏色豌蟋。
```bash
$ webpack --progress --colors
```
如果不想每次修改模塊后都重新編譯廊散,那么可以啟動(dòng)監(jiān)聽模式。開啟監(jiān)聽模式后梧疲,沒有變化的模塊會(huì)在編譯后緩存到內(nèi)存中允睹,而不會(huì)每次都被重新編譯,所以監(jiān)聽模式的整體速度是很快的幌氮。
```bash
$ webpack --progress --colors --watch
```
當(dāng)然缭受,使用 `webpack-dev-server` 開發(fā)服務(wù)是一個(gè)更好的選擇。它將在 localhost:8080 啟動(dòng)一個(gè) express 靜態(tài)資源 web 服務(wù)器该互,并且會(huì)以監(jiān)聽模式自動(dòng)運(yùn)行 webpack米者,在瀏覽器打開 http://localhost:8080/ 或 http://localhost:8080/webpack-dev-server/ 可以瀏覽項(xiàng)目中的頁面和編譯后的資源輸出,并且通過一個(gè) socket.io 服務(wù)實(shí)時(shí)監(jiān)聽它們的變化并自動(dòng)刷新頁面宇智。
```bash
# 安裝
$ npm install webpack-dev-server -g
# 運(yùn)行
$ webpack-dev-server --progress --colors
```