【注】本文原發自此處,轉載請註明出處。css
本文譯自【Webpack-The Confusing Parts】原文html
本文已同步發表在個人博客node
webpack
是當前最受歡迎的模塊管理器(module bundler
),對於使用React
開發的項目來講堪稱神器。固然,對於使用其餘框架,好比Angular
或者Backbone
等的開發者來講,webpack
也是種很好的工具。react
第一次配置webpack.config.js
時,有不少地方使我很困惑。在使用了webpack
一段時間後,我認識到正是這些地方讓webpack
如此強大和迷人。jquery
webpack
核心理念webpack
中,不只js
文件能夠做爲一個模塊,其餘文件(css
,images
,html
)均可以做爲模塊。這就是說,你能夠在其餘文件中加載這些模塊,require('myJSfile.js')
,或者require('myCSSfile.css')
。這意味着咱們將任意文件拆分紅便於管理的小文件,而後經過在其餘文件中加載這些小文件來達到重複利用的目的。Load only "what" you need and "when" you need
)—— 通常狀況下打包工具會將咱們全部的模塊打包生成一個最終的文件bundle.js
。可是在實際應用中,bundle.js
一般會很大(10M~15M),須要很長時間才能加載完成。webpack
提供了多種code splitting
的方法,會生成過個打包後的文件,且支持按需加載。這樣咱們只有在須要用到某個模塊的時候纔會異步加載該模塊。如今咱們來看下這些使人困惑的部分。webpack
首先要明確的一點是,webpack
有不少特性,有些只在開發環境使用,還有些只在生產環境使用,固然還有在生產環境和開發環境均可以使用的。以下圖所示:es6
因此一般咱們會有兩個
config
文件,以針對開發環境和生產環境做不一樣配置。
在package.json
作以下配置:web
"scripts": { //npm run build to build production bundles "build": "webpack --config webpack.config.prod.js", //npm run dev to generate development bundles and run dev. server "dev": "webpack-dev-server" }
webpack CLI
Vs webpack-dev-server
須要知道webpack
提供了兩個接口npm
webpack
命令行工具(webpack CLI tool
) —— 默認使用這種方式,無需單獨安裝,被集成在webpack
中。webpack-dev-server
—— node.js
服務器,須要單獨安裝能夠經過命令行添加參數,也能夠經過配置文件(默認爲webpack.config.js
),webpack
打包時會讀取這些配置。json
最初學習
webpack
時你可能用的就是命令行方式,以後大部分使用命令行的場景爲生產環境打包。
使用方法
方法 1: //全局安裝 npm install webpack --g //在命令行使用 $ webpack //<--Generates bundle using webpack.config.js 方法 2 : //本地安裝並保存在package.json中 npm install webpack --save //在scripts中添加 "scripts": { "build": "webpack --config webpack.config.prod.js -p", ... } //按如下方式運行 "npm run build"
webpack-dev-server
(適用於開發環境構建)webpack-dev-server
是一個基於Express
的node
服務器,默認使用8080
端口。這個方式的優勢是它提供了瀏覽器熱加載(Hot Module Replacement
)。
使用方法
方法一: //全局安裝 npm install webpack-dev-server -g //在命令行使用 $ webpack-dev-server --inline --hot 方法二: //添加到package.json中 "script": { "start": "webpack-dev-server --inline --hot", ... } //在命令行使用 $ npm start 在瀏覽器中打開 http://localhost:8080/
webpack
和webpack-dev-server
選項須要注意的一點是,像inline
和hot
這些選項,只有webpack-dev-server
有;而另外一些好比hide-modules
是單獨爲webpack
命令行方式提供的選項。
webpack-dev-server
參數爲webpack-dev-server
提供參數有兩種方式。
webpack.config.js
中的devServer
CLI
選項使用方法
//經過CLI $ webpack-dev-server --hot --inline //經過webpack.config.js devServer: { inline: true, hot: true }
我發現經過devServer
設置的配置項(hot: true, inline: true
)有時不起做用。因此我更喜歡使用CLI
的方式,在package.json
中添加以下代碼:
package.json { "script": { "start": "webpack-dev-server --hot --inline" } }
注意不要
同時設置devServer
中hot: true
和CLI
中--hot
"hot"
Vs "inline"
inline
模式會觸發頁面的動態重載(live reloading
);hot
模式會觸發頁面的熱加載(hot Module Replacement
),這種模式只重載頁面中變化了的部分。若是同時設置了inline
和hot
,webpack-dev-server
會先嚐試HMR
,若是HMR
失敗了,則重載整個頁面。
//當代碼發生變化時,如下3種方式都會從新打包,可是: //1. 不會重載頁面 $ webpack-dev-server //2. 會重載整個頁面 $ webpack-dev-server --inline //3. HMR, 若失敗則加載整個頁面 $ webpack-dev-server --inline --hot
entry
(String
Vs Array
Vs Object
)entry
指出了打包入口文件,支持字符串
,數組
和對象
三種形式。這三種形式有何區別呢?
若是爲單一入口文件,也就是說入口文件只有一個,那這三種方式會獲得相同的結果。
entry
— Array
如有多個入口文件,且彼此獨立,那麼可使用數組方式。好比入口文件爲a.js
,b.js
,使用數組方式會將b.js
的內容追加到bundle.js
的內容後。
一個很常見的場景就是在html
文件加入統計代碼,好比googleAnalytics.js
,就能夠用數組的方式告知webpack
將其打包到bundle.js
末尾,以下:
entry
— Object
這種方式主要針對多頁面應用(指包含多個html
文件)。這種方式可使webpack
根據這個對象一次就打包出多個文件。
以下這種配置能夠打包出兩個js
文件:indexEntry.js
和profileEntry.js
,能夠分別在index.html
和profile.html
中引入。
{ entry: { "indexEntry": "./public/src/index.js", "profileEntry": "./public/src/profile.js" }, output: { path: "/dist", filename: "[name].js" //indexEntry.js & profileEntry.js } }
使用方法
//profile.html <script src="dist/profileEntry.js"></script> //index.html <script src="dist/indexEntry.js"></script>
注: output
中name
對應的是entry
中的屬性名。
entry
— 結合使用array
和object
能夠在object
內部再使用array
方式。好比以下配置:
{ entry: { "vendor": ['jquery', 'analytics.js', 'optimizely.js'], "index": "./public/src/index.js", "profile": "./public/src/profile.js" }, output: { path: "/dist", filename: "[name].js" //vendor.js, index.js & profile.js } }
output
— path
和publicPath
output
設定了打包生成文件的路徑。它有兩個屬性path
和publicPath
。path
告知webpack
將打包生成後的文件存儲於什麼路徑,好比咱們但願將文件打包到dist
文件夾下,只需設置path
爲/dist
便可;publicPath
用於在生產環境打包時更新文件(包括css
、html
)中的url
。
以下配置:
//開發環境config entry: __dirname + "/app/main.js", output: { path: __dirname + "/public", //開發環境中不須要使用publicPath, 除非你的靜態資源好比圖片等沒有存儲在本地開發環境。 //publicPath: "http://mycdn.com", filename: "bundle.js" } //生產環境config entry: __dirname + "/app/main.js", output: { path: __dirname + "/public", //publicPath: 一些插件(url-loader, file-loader, HtmlWebpackPlugin等) //在生成圖片,樣式表等的url路徑時會用到該配置 //好比: //.image { // background-image: url('./test/png'); //} //按以下配置打包後會變成: //.image { // background-image: url('http://mycdn.com/test.png'); //} publicPath: "http://mycdn.com/", filename: "bundle.js" }
舉個例子,在你的css
文件中,用到了./test.png
這個url
去加載本地的圖片。可是在生產環境中,這張圖片test.png
會存儲在cdn
服務器上。這樣若是仍是用./test.png
就會訪問不到該圖片,必須把文件中全部的url
手動改爲cdn
的路徑才能在生產環境使用。
webpack
爲咱們提供的publicPath
這個屬性使咱們能夠很方便地處理這類問題。只須要將publicPath
設置爲生產環境的路徑,這些識別publicPath
的插件,好比url-loader
,就會自動爲咱們處理好url
。以下圖所示:
//開發環境,server和image都在本地 .image { background-image: url('./test.png'); } //生產環境, server在HeroKu服務器上,而image在cdn上 .image { background-image: url('https://someCDN/test.png'); }
(譯者注:
publicPath
還用於指定在使用webpack-dev-server
時,如何訪問其暫存於內存中的打包後的文件。)
Loaders And Chaining Loaders
)加載器是一些node
模塊,能夠加載(load
)或者引入(import
)各類類型的文件使其轉化成瀏覽器支持的文件格式,包括js
,css
等等。
好比:可使用babel-loader
將使用ES6
寫的js
文件轉換爲瀏覽器支持的ES5
格式。以下:
module { loaders: [ { test: /\.js$/, //檢測js文件,若是是,則對其使用loader處理 exclude: /node_modules/, //不對node_modules下文件處理 loader: 'babel' //使用babel (對babel-loader的簡寫) } ] }
對同一種類型的文件能夠鏈式運用多個加載器。鏈式調用爲從右向左,經過!
分割加載器。
舉例:咱們有一個css
文件myCSSFile.css
,咱們想將這個文件中的內容轉換成<style>CSS content</style>
的形式插入到咱們的html
頁面中。可使用兩個加載器css-loader
和style-loader
來達成以上目的:
modules: { loaders: [ { test: /\.css$/, loader: 'style!css' //style-loader!css-loader的簡寫 } ] }
以下展現了其原理:
一、webpack
查找模塊中依賴的css
文件。也就是說,webpack
會檢查js
文件中是否引用了myCSSFile.css
。若是找到了依賴,webpack
會先用css-loader
對其進行處理。
二、css-loader
會加載全部的css
和這個css
的依賴(好比@import otherCSS
),並將css
的內容處理爲JSON
數據格式。而後將結果傳給style-loader
進行處理。
三、style-loader
會對接收到的json
數據進行處理,並將其處理爲style
標籤——<style>CSS contents</style>
,而後插入到html
頁面中。
能夠向loaders
傳遞各類參數進行配置。
在如下這個例子中,咱們對url-loader
進行了配置:小於1024字節的圖片將會被轉爲爲base64
格式,而大於1024字節的圖片仍是使用圖片url
。有兩種方式進行配置:
//方式1 使用'?' { test: /\.png$/, loader: "url-loader?limit=1024" } //方式2 使用'query'屬性 { test: /\.png$/, loader: "url-loader", query: {limit: 1024} }
.babelrc
文件使用babel-loader
的話,須要配置presets
才能正確轉化,包括將es6
轉換爲es5
,將JSX
轉爲js
。能夠經過以下方式設置參數
module: { loaders: [ { test: /\.jsx?$/, exclude: /(node_modules|bower_components)/, loader: 'babel', query: { presets: ['react', 'es2015'] } } ] }
可是在不少項目中babel
的配置可能會比較大,因此能夠單獨在babel
的配置文件.babelrc
中配置。若是有.babelrc
,babel-loader
會自動加載該文件。
以下:
//webpack.config.js module: { loaders: [ { test: /\.jsx?$/, exclude: /(node_modules|bower_components)/, loader: 'babel' } ] } //.babelrc { "presets": ["react", "es2015"] }
Plugins
)插件是一些node
模塊,能夠對生成的打包文件進行處理。
好比,uglifyJSPlugin
插件能夠對打包後獲得的bundle.js
進行壓縮處理,減少文件體積。extract-text-webpack-plugin
運用了css-loader
和style-loader
將全部的css
統一處理並根據結果生成一個單獨的css
文件(style.css
),將文件連接插入到html
文件中。
//webpack.config.js //獲取全部的css文件,並將其內容整合,生成一個單獨的css文件'style.css' var ETP = require('extract-text-webpack-plugin'); module: { loaders: [ { test: /\.css$/, loader: ETP.extract('style-loader', 'css-loader') } ] }, plugins: [ new ExtractTextPlugin("style.css") ]
注:
若是你只是想使用內聯css
樣式,在html
頁面中加入style
標籤,能夠只用css
和style
加載器。以下:
module: { loaders: [ { test: /\.css$/, loader: 'style!css' } ] }
Loaders Vs Plugins
)能夠看到,加載器做用於單獨的文件,在bundle
生成以前完成;
插件做用於bundle
或chunk
,一般是在bundle
生成過程的最後進行。一些插件好比commonsChunksPlugins
甚至會影響bundle
如何生成。(譯者注
:該插件用於提取出各個模塊中引用的相同模塊,下篇文章code splitting
中會詳細說明)
Resolving File Extensions
)不少webpack
配置文件中都包含一個resolve extensions
的屬性,其中包含一個空字符串。這個空字符串就是用於正確加載不含後綴的文件的。好比:require('./myJSFile')
或 import myJSFile from './myJSFile'
。
{ resolve: { extensions: ['', '.js', '.jsx'] } }
注: 翻譯水平有限,若有問題還但願你們能不吝賜教,但願和你們共同進步。
(本文完)