webpack
是一個當下最流行的前端資源的模塊打包器。當 webpack
處理應用程序時,它會遞歸地構建一個依賴關係圖(dependency graph
),其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成少許的bundle
- 一般只有一個,由瀏覽器加載。css
它是高度可配置的,咱們先理解四個核心概念:入口(entry
)、輸出(output
)、loader、插件(plugins
)html
webpack 建立應用程序全部依賴的關係圖。圖的起點被稱之爲入口起點(entry point
)。入口起點告訴 webpack 從哪裏開始,並根據依賴關係圖肯定須要打包的內容。能夠將應用程序的入口起點認爲是根上下文或 APP第一個啓動文件。前端
簡單規則:每一個 HTML 頁面都有一個入口起點。單頁應用(SPA):一個入口起點,多頁應用(MPA):多個入口起點。node
用法:entry: string | Arrary<string>
webpack
//webpack.config.js module.exports = { entry: './src/index.js' };
entry
屬性的單個入口語法,在擴展配置的時候有失靈活性。它是下面的簡寫:web
//webpack.config.js module.exports = { entry: { main: './src/index.js' } };
向entry
傳入一個數組時候,將建立"多個主入口(multi-main entry)"。在你想要多個依賴文件一塊兒注入,而且將他們的依賴導向(graph)到一個"chunk"時候,傳入數組的方式就頗有用。shell
//webpack.config.js module.exports = { entry: [ './src/index.js', 'babel-polyfill', ] };
用法: entry: {[entryChunkName: string]: string|Array<string>}
npm
//webpack.config.js module.export = { entry: { app: './src/app.js', vendors: './src/vendors.js' } };
對象語法會比較繁瑣。然而,這是應用程序中定義入口的最可擴展的方式。json
這個配置告訴咱們 webpack 從 app.js
和 vendors.js
開始建立依賴圖。這些依賴圖是彼此徹底分離、互相獨立的。這種方式比較常見於,只有一個入口起點(不包括 vendor
,vendor
通常都是動態加載的第三方模塊。動態加載的模塊不是入口起點。)的單頁應用程序(single page application)中。不過,爲了支持提供更佳 vendor
分離能力的 DllPlugin
。 官方如今不太建議將第三方模塊放到entry.vendors
中。api
對象語法,更常見的應該是多入口應用程序-多頁應用(MPA)。
//webpack.config.js module.export = { entry: { home: "./home.js", about: "./about.js", contact: "./contact.js" } };
此配置,告訴 webpack,咱們 須要 3 個獨立分離的依賴關係圖.
在多頁應用中,每當頁面跳轉時,服務器將爲你獲取一個新的 HTML 文檔。頁面從新加載新文檔,而且資源被從新下載。
根據經驗:每一個 HTML 文檔只使用一個入口起點。
將全部的資源(assets)歸攏在一塊兒後,還須要告訴 webpack 在哪裏打包應用程序。webpack 的 output
屬性描述瞭如何處理歸攏在一塊兒的代碼(bundled code)。output
選項能夠控制webpack如何向硬盤寫入編譯文件。注意,即便能夠存在多個entry
起點,但只指定一個output
配置。
在 webpack 中配置output
屬性的最低要求是,將它的值設置爲一個對象,包括如下兩點:
filename
用於輸出文件的文件名。path
的絕對路徑。//webpack.config.js module.exports = { entry: './src/index.js', output: { path: './home/proj/public/assets', filename: 'bundle.js' } };
此配置將一個單獨的 bundle.js
文件輸出到 ./home/proj/public/assets
目錄中。
若是配置建立了多個單獨的 "chunk"
(例如,使用多個入口起點或使用像 CommonsChunkPlugin
這樣的插件),則應該使用佔位符來確保每一個文件具備惟一的名稱。
{ entry: { app: './src/app.js', search: './src/search.js' }, output: { filename: '[name].js', //使用佔位符 path: __dirname + '/dist' } } // 寫入到硬盤:./dist/app.js, ./dist/search.js
webpack的目標是,讓webpack聚焦於項目中的全部資源(asset), 而瀏覽器不須要關注考慮這些。 webpack把每一個文件(.css
, .html
, .scss
, .jpg
, etc.
)都做爲模塊處理。然而webpack自身只理解JavaScript。
webpack loader 在文件被添加到依賴圖中時,將文件源代碼轉換爲模塊。
loader
可使你在import
或"加載"模塊時預處理文件。所以,loader
相似於其餘構建工具中「任務(task)」,並提供了處理前端構建步驟的強大方法。
在更高層面,在webpack的配置中loader
有兩個目標:
loader
進行轉換的那些文件。(test
屬性)use
屬性)//webpack.config.js const path = require('path'); module.exports = { entry: './path/to/my/entry/file.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'my-first-webpack.bundle.js' }, module: { rules: [ { test: /\.txt$/, use: 'raw-loader' } ] } };
以上配置中,對一個單獨的 module
對象定義了 rules
屬性,裏面包含兩個必須屬性:test
和use
。這至關於告訴 webpack 編譯器,當碰到「在 require()/import
語句中被解析爲 .txt
的路徑」時,在對它打包以前,先使用 raw-loader
轉換一下。
在webpack配置中定義
loader
時,要定義在module.rules
中,而不是rules
。若是不這麼作,webpack會給出嚴重警告
例如,你可使用loader
告訴webpack加載css
文件,或者將TypeScript轉爲JavaScript。爲此,首先安裝相對應的loader
:
npm install -D css-loader npm install -D ts-loader
而後指示webpack對每一個.css
使用css-loader
, 以及對全部.ts
文件使用ts-loader
:
module.exports = { module: { rules: [ { test: /\.css$/, use: 'css-loader' }, { test: /\.ts$/, use: 'ts-loader' } ] } };
根據配置選項,下面的規範定義了同等的loader
用法:
{test: /\.css$/, use: 'css-loader'} // 等同於 {test: /\.css$/, use: [{ loader: 'css-loader' }]} // 等同於 {test: /\.css$/, loader: 'css-loader'}
module.rules.loader
是 module.rules.use: [ { loader } ]
的簡寫。
在應用程序中,有三種使用loader的方式:
imort
語句中顯示指定loader。shell
命令中指定它們。module.rules
容許你在 webpack 配置中指定多個 loader
。 這是展現loader
的一種簡明方式,而且有助於使代碼變得簡潔。同時讓你對各個loader
有個全局概覽:
module: { rules: [{ test: /\.css$/, use: [ 'style-loader', { loader: 'scss-loader' }, { loader: 'css-loader', options: { modules: true } } ] }] }
能夠在 import
語句或任何等效於 "import" 的方式中指定 loader。使用 !
將資源中的 loader 分開。分開的每一個部分都相對於當前目錄解析。
import Styles from 'style-loader!css-loader?modules!./styles.css'
經過前置全部規則及使用!
, 能夠對應覆蓋到配置中的任意loader
。
選項能夠傳遞查詢參數,例如 ?key=value&foo=bar
,或者一個 JSON 對象,例如 ?{"key":"value","foo":"bar"}
。
儘量使用
module.rules
,由於這樣能夠減小源碼中的代碼量,而且能夠在出錯時,更快地調試和定位 loader 中的問題。
你也能夠經過CLI
使用loader:
webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
這會對 .jade
文件使用 jade-loader
,對 .css
文件使用 style-loader
和 css-loader
。
options
對象進行配置。package.json
常見的 main
屬性,還能夠將普通的 npm 模塊導出爲loader,作法是在 package.json
裏定義一個 loader
字段。loader 遵循標準的模塊解析。多數狀況下,loader 將從模塊路徑(一般將模塊路徑認爲是npm install
, node_modules
)解析。
loader 模塊須要導出爲一個函數,而且使用 Node.js 兼容的 JavaScript 編寫。一般使用 npm 來管理,也能夠將自定義 loader 做爲應用程序中的文件。按照約定,loader 一般被命名爲 xxx-loader(例如 json-loader
)。
插件是 wepback 的支柱功能。webpack 自身也是構建於-你在 webpack 配置中用到的相同的插件系統之上!
插件目的在於解決 loader沒法實現的其餘事。
因爲loader僅在每一個文件的基礎上執行轉換,而插件(plugins) 經常使用於(但不限於)在打包模塊的 「compilation」 和 「chunk」 生命週期執行操做和自定義功能。想要使用一個插件,你只須要 require()
它,而後把它添加到 plugins
數組中。
多數插件能夠經過選項(option)自定義。你也能夠在一個配置文件中由於不一樣目的而屢次使用同一個插件,這時須要經過使用 new 來建立它的一個實例。
webpack 插件是一個具備 apply
屬性的 JavaScript 對象。apply
屬性會被 webpack compiler 調用,而且 compiler
對象可在整個編譯生命週期訪問。經過Function.prototype.apply
方法,你能夠把任意函數做爲插件傳遞(this
將指向compiler
)。咱們能夠在配置中使用這樣的方式來內聯自定義插件。
//ConsoleLogOnBuildWebpackPlugin.js function ConsoleLogOnBuildWebpackPlugin() { }; ConsoleLogOnBuildWebpackPlugin.prototype.apply = function(compiler) { compiler.plugin('run', function(compiler, callback) { console.log("webpack 構建過程開始!!!"); callback(); }); };
因爲插件能夠攜帶參數/選項,你必須在webpack配置中,向plugins
屬性中傳入new
實例。
根據webpack的用法,能夠有多種方式使用插件。可是,經過配置的方式使用是比較推薦的作法。
//webpack.config.js const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm const webpack = require('webpack'); //to access built-in plugins const path = require('path'); const config = { entry: './path/to/my/entry/file.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'my-first-webpack.bundle.js' }, module: { rules: [ { test: /\.txt$/, use: 'raw-loader' } ] }, plugins: [ new webpack.optimize.UglifyJsPlugin(), new HtmlWebpackPlugin({template: './src/index.html'}) ]0 }; module.exports = config;
即使使用 Node API,用戶也應該在配置中傳入 plugins 屬性。compiler.apply
並非推薦的使用方式。
// some-node-script.js const webpack = require('webpack'); //訪問 webpack 運行時(runtime) const configuration = require('./webpack.config.js'); let compiler = webpack(configuration); compiler.apply(new webpack.ProgressPlugin()); compiler.run(function(err, stats) { // ... });
以上就是webpack中比較重要的四個概念,在平時開發過程當中會常常遇到。裏面還能夠有不少的詳細配置,須要咱們在項目開發的過程當中慢慢了解。