webpack 是一個模塊打包工具。它使得模塊相互依賴而且可構建等價於這些模塊的靜態資源。相比於已經存在的模塊打包器(module bundler),webpack的開發動機是實現代碼分包(Code Splitting )和經過模塊化完成代碼的無縫集成。webpack能夠根據項目需求合併代碼,而且支持按需加載。javascript
webpack入門,能夠參看:petehunt的Webpack howtocss
webpack的實現目標是:html
安裝webpack以前,請確認node已經安裝完畢,且npm包管理器可用。vue
1
2
|
npm install webpack -g
|
1
2
|
npm install webpack-dev-server -g
|
在項目的根目錄下運行:java
1
2
|
npm install webpack
|
在項目根目錄下新建webpack.config.js。咱們經過這個文件來處理控制webpack,給出咱們想要的輸出。node
webpack.config.js
的簡單的配置以下:react
1
2
3
4
5
6
7
8
9
|
module.exports = {
context: __dirname + '/src',
entry: './index/index.js',
output: {
path: __dirname + '/build',
filename: 'bundle.js'
}
};
|
項目根目錄運行:jquery
1
2
|
webpack-dev-server --progress --colors
|
此時,訪問: http://localhost:8080/index.bundle.js 便可訪問到編譯以後的js了。webpack
經過webpack打包發佈,運行:git
1
2
|
webpack -p
|
按照咱們上面的webpack.config.js
文件的配置,打包成功以後會生成一個build文件夾,裏面會包含打包好的js文件,集成了全部的依賴庫和業務邏輯代碼,咱們只需將此build文件夾發佈到線上便可。
至此一個完整流程的webpack運行流程梳理完畢,固然webpack還有不少功能來實現咱們開發中所遇到的各類變態需求,在第三章中我抽出了一些項目中經常使用的功能。
配置那些js須要處理,entry
有三種寫法,每一個入口稱爲一個chunk。
entry: "./index/index.js"
:配置模塊會被解析爲模塊,並在啓動時加載。chunk名爲默認爲main
, 具體打包文件名視output
配置而定。
數組entry: ['./src/mod1.js', [...,] './src/index.js']
:全部的模塊會在啓動時 按照配置順序 加載,合併到最後一個模塊會被導出。chunk名默認爲main
對象entry: {index: '...', login : [...] }
:若是傳入Object,則會生成多個入口打包文件, key是chunk名,value能夠是字符串,也但是數組。
例如
1
2
3
4
5
|
entry: {
index: './index/index.js',
login: ['./mod/mod1.js', './index/login.js']
}
|
設置入口配置的文件的輸出規則,經過output
對象實現,經常使用設置:
1
2
3
4
5
6
|
output: {
path: __dirname + '/build',
filename: '[name]-[id].js',
publicPath: '/asstes/'
}
|
其中:
output.path
:指定輸出文件路徑,一般設置爲__dirname + ‘/build’,output.filename
: 輸出文件名稱,有下面列出的四種可選的變量。 filename項的配置能夠是這幾種的任意一種或多種的組合。 如 output.filename = ‘[name]-[id].js’, 則輸出就是 index-1.js、 login-2.js。
[id]
, chunk的id[name]
,chunk名[hash]
, 編譯哈希值[chunkhash]
, chunk的hash值output.publicPath
:設置爲想要的資源訪問路徑。訪問時,則須要經過相似http://localhost:8080/asstes/index-1.js
來訪問資源,若是沒有設置,則默認從站點根目錄加載。
loader是webpack中比較重要的部分,她是處理各種資源的執行者。它們是一系列的函數(運行在node.js中),將資源中的代碼做爲參數,而後返回新的代碼。你能夠用loader告訴webpack能夠加載哪些文件,或者不加載哪些文件。
Loader的特色
安裝loader
1
2
|
npm install xxx-loader --save
|
或者
1
2
|
npm install xxx-loader --save-dev
|
其中,XXX爲webpack支持的loader名,經常使用的有:html、css、jsx、coffee、jade、less、sass、style等。
你能夠經過webpack loader 列表 查看全部支持的loader。固然你能夠本身根據需求建立併發布loader。
配置loader
1
2
3
4
5
6
7
8
9
10
11
12
|
modules: {
loaders: [
{
test: /\.js$/, //匹配但願處理文件的路徑
exclude: /node_modules/, // 匹配不但願處理文件的路徑
loaders: 'xxx-loader?a=x&b=y' //此處xxx-loader 能夠簡寫成xxx , ?後以query方式傳遞給loader參數
},
...
]
}
|
多loader調用示例:
在js中,若是要直接解析某個文件,你能夠採用:
1
2
|
require('jade!./index.jade')
|
若是要解析css,並內聯之,須要使用到分隔符 !
1
2
|
require(!style!css!./style.css)
|
同理,若是要解析less, 轉換成css以後,再內聯之,寫法如:
1
2
|
require('!style!css!less!./style.less!') ; // 此語句的含義是,先調用less-loader解析style.less文件,輸出結果會被css-loader處理, 而後再被style-loader處理
|
同理,在webpack.config.jsp配置文件中,只須要制定處理的loader序列:
即:
1
2
3
4
5
6
7
8
9
|
...
loaders: [
{
test: /\.less$/,
loader: "style!css!less"
}
]
...
|
本章會介紹比較經常使用的loader的配置方法。
在webpack中css默認方案是,將css編譯並經過內聯的方式在html頁面中插入<style>
樣式標籤。固然這遠遠不能知足咱們的要求,webpack提供css-loader模塊用於編譯css文件,而且提供了插件extract-text-webpack-plugin
將css從js代碼中抽出併合並。你能夠訪問此處,查看文檔和例子。
這樣你能夠在模塊中,盡情使用 require(style.css)
, webpack會幫你作解析,合併entry中定義js及其依賴中所用到的全部css,而後生成一個指定的css文件。
配置以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
<br />var ExtractTextPlugin = require('extract-text-webpack-plugin');
...
module: {
loaders: [
{
test: /\.css$/,
loader: ExtractTextPlugin.extract(
"style-loader",
"css-loader?sourceMap"
)
}, {
test: /\.less$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader")
}
]
},
plugins: [
new ExtractTextPlugin("css/[name].css?[hash]-[chunkhash]-[contenthash]-[name]", {
disable: false,
allChunks: true
})
]
...
|
在css中或者js邏輯中,都會涉及到require圖片的狀況,webpack能夠內聯圖片地址到打包js中而且經過require()
返回圖片路徑。固然,不僅是圖片,還有css中用到的iconfont,特殊狀況用到的flash等,均可以類似處理。這裏,咱們須要用到url-loader 或 file-loader。
file-loader
: 將匹配到的文件複製到輸出文件夾,並根據output.publicPath的設置返回文件路徑url-loader
: 相似file-loader ,可是它能夠返回一個DataUrl (base 64)若是文件小於設置的限制值limit
。一樣,這以前,你須要實現配置相關loader。
安裝url-loader
和 file-loader
:
1
2
|
npm install url-loader file-loader --save
|
配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
module:{
loaders:[
{
test: /\.(png|jpg)$/,
loader: 'url-loader?limit=8192' // <= 8kb的圖片base64內聯
},
{
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url?limit=10000&minetype=application/font-woff'
},
{
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url?limit=10&minetype=application/font-woff'
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url?limit=10&minetype=application/octet-stream'
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file'
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url?limit=10&minetype=image/svg+xml'
}
]
}
|
經過向url-loader傳遞參數,若是圖片小於8kb,則base64內聯,大於8kb,則經過output.publishPath配置的前綴將圖片路徑寫入代碼,並提取圖片到輸出目錄。
在React項目中,須要解析JSX和相關JavaScript文件,須要下載loader:
1
2
|
npm install react-hot-loader jsx-loader --save
|
一樣,配置loader:
1
2
3
4
5
6
7
8
9
10
|
...
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'react-hot!jsx-loader?harmony'
}
]
...
|
和React項目相似,若是要解析VUE框架編寫的.vue文件,須要下載loader:
1
2
|
npm install vue-loader --save
|
配置loader:
1
2
3
4
5
6
7
|
loaders: [
{
test: /\.vue$/,
loader: 'vue-loader'
}
]
|
但須要注意的是,若是你的代碼中用到了如jade,less等其餘語法,可能須要提早下載相應loader到本地。vue-loader的介紹能夠查看: vue-loader
babel
可讓咱們在編寫代碼的時候,使用更高級的ECMAScript6
的語法。而後咱們編寫的JS文件能夠被編譯成可被低版本瀏覽器處理的常規代碼。
使用方法
安裝loader:
1
2
|
npm install babel-loader --save
|
配置loader:
1
2
3
4
5
6
7
8
|
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel'
}
]
|
例如:
1
2
3
4
5
6
7
8
9
10
11
|
const a = 1;
console.log(a);
if (true) {
let a = 3;
console.log(a);
}
console.log(a);
|
解析爲:
1
2
3
4
5
6
7
8
9
10
11
|
var a = 1;
console.log(a);
if (true) {
var _a = 3;
console.log(_a);
}
console.log(a);
|
####3.4.1 藉助web_modules引用外部庫
有些時候,咱們用到的第三方庫並無採用CommonJS或AMD規範,也沒有提交到npm。這樣的話,咱們沒法經過npm來下載,並經過require()
來引用這些庫。
webpack給咱們提供了一個很好的實現方式。咱們能夠在項目根目錄下,建立一個叫作web_modules的文件夾,而後將須要用到的第三方庫存放在此處。那麼以後,不須要作任何設置,能夠在咱們的邏輯代碼中使用require(
‘xx-lib.js’)而且使用了。
文件組織以下:
此時,咱們就能夠在業務邏輯中,大膽地使用web_modules中配置的庫了,打包的時候,webpack會自動將web_modules中被用到的庫封裝。
**例如: **
1
2
3
4
|
var director = require('director')
var Router = director.Router();
...
|
當咱們常用React、jQuery等外部第三方庫的時候,一般在每一個業務邏輯JS中都會遇到這些庫。
如咱們須要在各個文件中都是有jQuery的$
對象,所以咱們須要在每一個用到jQuery的JS文件的頭部經過require('jquery')
來依賴jQuery。 這樣作很是繁瑣且重複,所以webpack提供了咱們一種比較高效的方法,咱們能夠經過在配置文件中配置使用到的變量名,那麼webpack會自動分析,而且在編譯時幫咱們完成這些依賴的引入。
webpack.config.js中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
var webpack = require('webpack');
...
plugins: [
new webpack.ProvidePlugin({
'Moment': 'moment',
"$": "jquery",
"jQuery": "jquery",
"window.jQuery": "jquery",
"React": "react"
})
]
...
|
這樣,咱們在JS中,就不須要引入jQuery等經常使用模塊了,直接使用配置的這些變量,webpack就會自動引入配置的庫。
某些狀況,咱們須要在頁面中輸出開發調試內容,可是又不想讓這些調試內容在發佈的時候泄露出去,那麼咱們能夠採用魔力變量(magic globals)來處理。
配置文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
var webpack = require('webpack');
var definePlugin = new webpack.DefinePlugin({
__DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'false')),
__PRERELEASE__: JSON.stringify(JSON.parse(process.env.BUILD_PRERELEASE || 'true'))
});
...
plugins: [
definePlugin
]
...
|
業務邏輯代碼中寫入
按照下面的代碼寫入,咱們就能夠在咱們本身設定的環境下進行更具針對性的調試。好比咱們但願在開發環境下能夠AJAX能夠調試本地mock數據,而後在發佈的時候,能夠正常訪問服務端數據。那麼經過此種方式能夠徹底實現。
1
2
3
4
5
6
7
8
9
10
11
12
|
if (__DEV__) {
console.warn('Extra logging');
//開發環境須要進行的處理
//...
}
if (__PRERELEASE__) {
console.log('prerelease');
//預發環境須要進行的處理
//...
}
|
設置環境命令
要告訴webpack咱們但願當前是什麼環境,只須要在命令中寫入 BUILD_DEV=1 webpck
那麼webpack經過配置,就會將全部咱們引用到的__DEV__
變量設置爲true。
咱們能夠在package.json中事先定義好命令:
1
2
3
4
5
|
"scripts": {
"dev": "BUILD_DEV=1 webpack-dev-server --progress --colors",
"build": "BUILD_PRERELEASE=1 webpack -p"
}
|
那麼就能夠避免輸入冗長的命令了:
開發時輸入:
1
2
|
npm run dev
|
發佈時輸入:
1
2
|
npm run build
|
項目中,對於一些經常使用的組件,站點公用模塊常常須要與其餘邏輯分開,而後合併到同一個文件,以便於長時間的緩存。要實現這一功能,配置參照:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<br />var webpack = require('webpack');
var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
...
entry: {
a: './index/a.js',
b: './idnex/b.js',
c: './index/c.js',
d: './index/d.js'
},
...
plugins: [
new CommonsChunkPlugin('part1.js', ['a', 'b']),
new CommonsChunkPlugin('common.js', ['part1', 'c'])
]
...
|
##4 使用devtool調試
能夠經過在配置中加入devtool
項,選擇預設調試工具來提升代碼調試質量和效率:
eval
– 每一個模塊採用eval
和 //@ sourceURL
來執行source-map
– sourceMap是發散的,和output.sourceMapFilename
協調使用hidden-source-map
– 和source-map相似,可是不會添加一個打包文件的尾部添加引用註釋inline-source-map
– SourceMap以DataUrl的方式插入打包文件的尾部eval-source-map
– 每一個模塊以eval方式執行而且SourceMap以DataUrl的方式添加進evalcheap-source-map
– 去除column-mappings
的SourceMap, 來自於loader中的內容不會被使用。cheap-module-source-map
– 去除column-mappings
的SourceMap, 來自於loader中的SourceMaps被簡化爲單個mapping文件各類模式的對比:
devtool | 構建速度 | 再次構建速度 | 支持發佈版 | 質量 |
---|---|---|---|---|
eval | +++ | +++ | no | 生成代碼 |
cheap-eval-source-map | + | ++ | no | 轉換代碼(lines only) |
cheap-source-map | + | o | yes | 轉換代碼(lines only) |
cheap-module-eval-source-map | o | ++ | no | 源代碼 (lines only) |
cheap-module-source-map | o | – | yes | 源代碼(lines only) |
eval-source-map | — | + | no | 源代碼 |
source-map | — | — | yes | 源代碼 |
爲了方便你們摘取,和補全文章中用於示例的代碼片斷,特將配置文件整理以下,做參考:
配置文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
var webpack = require('webpack');
var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
var ExtractTextPlugin = require('extract-text-webpack-plugin');
//自定義"魔力"變量
var definePlugin = new webpack.DefinePlugin({
__DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'false')),
__PRERELEASE__: JSON.stringify(JSON.parse(process.env.BUILD_PRERELEASE || 'false'))
});
module.exports = {
//上下文
context: __dirname + '/src',
//配置入口
entry: {
a: './view/index/index.js',
b: './view/index/b.js',
vender: ['./view/index/c.js', './view/index/d.js']
},
//配置輸出
output: {
path: __dirname + '/build/',
filename: '[name].js?[hash]',
publicPath: '/assets/',
sourceMapFilename: '[file].map'
},
devtool: '#source-map',
//模塊
module: {
loaders: [
{
//處理javascript
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel'
}, {
test: /\.css$/,
loader: ExtractTextPlugin.extract(
"style-loader",
"css-loader?sourceMap"
)
}, {
test: /\.less$/,
loader: ExtractTextPlugin.extract(
"style-loader",
"css-loader!less-loader"
)
}, {
test: /\.(png|jpg)$/,
loader: 'url-loader?limit=1024'
}, {
//處理vue
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url?limit=10000&minetype=application/font-woff'
},
{
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url?limit=10&minetype=application/font-woff'
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url?limit=10&minetype=application/octet-stream'
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file'
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url?limit=10&minetype=image/svg+xml'
}
]
},
plugins: [
//公用模塊
new CommonsChunkPlugin('common.js', ['a', 'b']),
//設置抽出css文件名
new ExtractTextPlugin("css/[name].css?[hash]-[chunkhash]-[contenthash]-[name]", {
disable: false,
allChunks: true
}),
//定義全局變量
definePlugin,
//設置此處,則在JS中不用相似require('./base')引入基礎模塊, 只要直接使用Base變量便可
//此處一般可用作,對經常使用組件,庫的提早設置
new webpack.ProvidePlugin({
Moment: 'moment', //直接從node_modules中獲取
Base: '../../base/index.js' //從文件中獲取
})
],
//添加了此項,則代表從外部引入,內部不會打包合併進去
externals: {
jquery: 'window.jQuery',
react: 'window.React',
//...
}
};
|