寫在前面
模塊化構建會讓項目的拓展性、代碼複用性和可維護性大大提高,初期可能會增加一些管理的工作量。但是對長遠來說絕對是值得的,一個良好的模塊化方案會讓維護工作變得輕鬆,這個好處項目越進展到後來越明顯。而且模塊化構建的框架和工具很多,RequireJS
、SeaJS
、Grunt
、Gulp
等,這些雖然成熟穩定但並不是我們今天的主題,既然是採用react
開發webApp,那麼模塊化當然是選webpack
。
webpack的優勢
1、支持CommonJs和AMD模塊,意思也就是我們基本可以無痛遷移舊項目
2、支持模塊加載器和插件機制,可對模塊靈活定製。babel-loader更是有效支持ES6。
3、可以通過配置,打包成多個文件。有效利用瀏覽器的緩存功能提升性能。
4、將樣式文件和圖片等靜態資源也可視爲模塊進行打包。配合loader加載器,可以支持sass,less等CSS預處理器。
5、內置有source map,即使打包在一起依舊方便調試。
webpack入門
首先介紹webpack
的配置文件webpack.config.js
var webpack=require('webpack');
module.exports={
entry:[
'webpack/hot/onlu-dev-server',
'./js/app.js'
],
output:{
path:'./build',
filename:'bundle.js'
},
module:{
leaders:[
{test:/\.js?$/,leaders:['react-hot','babel'],exclude:/node_modules/},
{test:/\.js$/,exclude:/node_modules/,loader:/'babel-loader'},
{test:/\.css$/,loader:'style!css'},
{test:/\.less/,loader:'style-loader!css-loader!less-loader'}
],
},
resolve:{
extensions:['','.js','.json']
},
plugins:[
new webpack.NoErrorsPlugin()
]
}
webpack.config.js
文件通常放在項目的根目錄裏,它本身也是一個標準的Common.js
規範的模塊。在導出的配置對象中有幾個關鍵的參數:
entry
entry
可以說個字符串或數組或者是對象。當entry
是個字符串的時候用來定義入口文件。
entry:'./js/main.js'
當entry
是個數組的時候,裏面同樣包含入口文件,另外一個參數可以用來配置webpack
提供的一個靜態資源服務器如webpack-dev-server
,它會監控項目中每一個文件的變化,實時進行構建,並且自動刷新頁面,
entry:[
'webpack/hot/only-dev-server',
'./js/app.js'
]
當entry
是一個對象的時候,我們可以將不同的文件構建成不同的文件,按需使用,比如:
entry:{
hello:'./js/hello.js',
form:'./js/form.js'
}
output
output
是個對象,用戶定義構建後的文件的輸出。其中包含path
和filename
:
output:{
path:'./build',
filename:'bundle.js'
}
當我們在entry
中定義構建多個文件時,filename
可以對應地更改爲[name].bundle.js
。
module
關於模塊的加載相關,我們就定義在module.loaders
中,這裏通過正則表達式去匹配不同後綴的文件名。然後它們定義不同的加載器,比如說給less文件定義三個串聯的加載器(用!
連接)
moudle:{
loaders:[
{test:/\.js?$/,loaders:['react-hot','babel'],exclude:/node_modules/},
{test:/\.js$/,exclude:/node_modules/,loader:'babel-loader'},
{test:/\.css$/,loader:'style!css'},
{test:/\.less$/,loader:'style-loader!css-loader!less-loader'}
]
}
除此之外,我們還可以用來定義 png
、jpg
這樣的圖片資源在小於10k時自動處理爲base64圖片的加載器。
{test:/\.(png|jpg)$/,loader:'url-loader?limit=10000'}
給css
和less
還有圖片添加了loader
之後,我們不僅可以像在node
中那樣require
進來了。就像這樣:
require('./bootstrap.css');
require('./myapp.less');
var img=document.createElement('img');
img.src=require('./glyph.png');
注意: 這樣
require
進來的文件會內聯到[name].bundle.js
中。如果我們需要把保留require
寫法又想把css
文件單獨拿出來,可以使用extract-text-webpack-plugin
插件。
$ npm install extract-text-webpack-plugin --save-dev
var ExtractTextPlugin =require('extract-text-webpack-plugin');
module.exports={
plugins:[
new ExtractTextPlugin("[name].css");
]
}
在上面的示例代碼中配置的第一個loader
是react-hot
的加載器,它可以實現react
組件的熱替換,我們已經在entry
參數中配置了webpack/hot/only-dev-server
,所以我們只要啓動 webpack
時開啓-hot
參數既可以使用react-hot-loader
了,在package.json
中這樣定義:
"script":{
"start":"webpack-dev-server --hot --progress --colors",
"build":"webpack --progress --colors"
}
resolve
webpack
在構建包的時候會按目錄的文件進行查找,resolve
屬性中的extensions
數組中用於配置程序可有自動替換哪些文件的後綴,比如:
resolve:{
extensions:['','.js','.json']
}
然後我們想要加載一個js
文件時,只要require('common')
就可以加載common.js
文件了。
plugin
webpack
提供了豐富的組件來滿足不同的需求,當然如果你足夠牛也可以自己編寫插件。這裏介紹比較常用的 NoErrorsPlugin
,它能跳過編譯時出錯的代碼並記錄,是編譯後運行的包不會發生錯誤。
plugins:[
new webpack.NoErrorsPlugin()
]
externals
當我們想在項目中require
一些其他的類庫或者API,而又不想讓這些類庫的源碼構建到運行時的文件中,就可以通過配置externals
參數來解決這個問題,比如jQuery類庫
externals:{
"jquery":'jQuery'
}
這樣我們就可以放心在項目中使用這些API了
var jQuery=require('jquery');
context
當我們在require一個模塊的時候,如果require
中包含變量,想這樣:
require("./mods/"+name+".js");
那麼在編譯的時候是不能知道具體的模塊的。但這個時候webpack
也會幫我們分析:
1. 分析目錄:'./mods'
;
2. 提取正則表達式:/^.*\.js$/
;
於是這個時候爲了更好地配合webpack
進行編譯,我們可以給它指明路徑,像在cake-webpack-config
中所做的那樣:
var currentBase=progress.cwd();
var context=abcOptions.options.context?abcOptions.options.context:path.isAbsolute(entryDir)?enentryDir:path.join(currentBase,entryDir);
讓webpack和gulp強強聯手
webpack
與gulp
並不矛盾,甚至一起使用會得到最大化的效益。大致的思路是這樣:
使用webpack
進行assets
編譯,使用gulp
的流快速對其他資源進行打包。
關於工具的定位
webpack
的定位是module bundler
,作爲模塊化工具,它的競爭對手其實是browserify
,而不是gulp
。
功能和使用方式上的不同
webpack 提供了一些非常使用的功能,像我們之前用到的那些,如圖片的處理、resolve
的處理、分開構建等,配置相當簡單。gulp
想要使用這些功能的時候我們可以在webpack
裏先配置好,做到強強聯手!
寫在後面
@參考 推酷 webpack前端模塊加載工具
@參考 博客園 前端模塊化工具-webpack
@我的技術博客 Jafeney.com