webpack 是當(dāng)下最熱門的前端資源模塊化和打包工具。它可以將許多松散的模塊(如 CommonJs 模塊、 AMD 模塊、 ES6 模塊、CSS、圖片、 JSON、Coffeescript、 LESS 等)按照依賴和規(guī)則打包成符合生產(chǎn)環(huán)境部署的前端資源。當(dāng) webpack 處理應(yīng)用程序時(shí),它會(huì)遞歸地構(gòu)建一個(gè)依賴關(guān)系圖表,其中包含應(yīng)用程序需要的每個(gè)模塊,然后將這些模塊打包成一個(gè)或多個(gè) bundler,由瀏覽器加載
在了解 webpack 使用配置時(shí),我們必須首先要熟悉下面四個(gè)核心概念:
- entry:入口
- output:出口
- loaders:加載器
- plugins:插件
一、entry:入口
在 webpack 執(zhí)行處理應(yīng)用程序時(shí),會(huì)形成一個(gè)依賴關(guān)系圖表。在這個(gè)圖表的起點(diǎn)就是入口起點(diǎn)(entry point),進(jìn)入這個(gè)入口后,webpack 就可以計(jì)算出入口點(diǎn)依賴的模塊和庫。
如何在 webpack.config.js 中配置入口點(diǎn)呢?
單個(gè)入口語法
用法: entry: string |Array<sting>
// webpack.config.js
const config = {
entry: './path/to/my/entry/file.js'
};
module.exports = config;
單個(gè)入口簡寫:
// webpack.config.js
const config = {
entry: {
main: './path/to/my/entry/file.js'
}
};
當(dāng)你想要注入多個(gè)依賴文件時(shí),可以向 entry 屬性傳入一個(gè)數(shù)組,數(shù)組是由文件路徑組成。這樣可以快速地設(shè)置 webpack 的配置,創(chuàng)建“多個(gè)主入口(multi-main entry)”,但這種方法不利于配置的擴(kuò)展。
對象語法
用法:entry: {[entryChunkName: string]: string|Array<string>}
// webpack.config.js
const config = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
}
對象語法雖然繁瑣,但是它是應(yīng)用程序入口最可擴(kuò)展的方式。
**“可擴(kuò)展的 webpack 配置”是指,可重用并且可以與其他配置組合使用。用于將關(guān)注點(diǎn)從環(huán)境、構(gòu)建目標(biāo)、運(yùn)行時(shí)中分離。然后使用專門的工具(如 webpack-merge)將它們合并。
常用場景
1、分離應(yīng)用程序和第三方庫入口
// webpack.config.js
const config = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
};
webpack 創(chuàng)建的依賴圖是彼此完全分離、相互獨(dú)立的,上述寫法比較適用于單頁面應(yīng)用程序。
執(zhí)行 webpack 時(shí),會(huì)使用 commonChunkPlugin 從 bundle 文件中提取 vendor 引用到 vendor bundle,并把引用 vendor 的部分替換為 webpack_require() 調(diào)用。
2、多頁面應(yīng)用程序
// webpack.config.js
const config = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
}
webpack 在多頁面應(yīng)用中,會(huì)使用 commonChunkPlugin 為每個(gè)頁面應(yīng)用創(chuàng)建 bundle 文件,在入口起點(diǎn)中時(shí)每個(gè)頁面都能對代碼和模塊實(shí)現(xiàn)復(fù)用。
二、output:輸出
這是屬性的作用是:控制 webpack 如何向硬盤寫入編譯文件。需要注意的是,即使是存在多個(gè)入口起點(diǎn),也只指定一個(gè)輸出配置。
1、用法
在 output 屬性中需要配置 filename 和 path 兩個(gè)配置項(xiàng):
- filename:輸出文件的文件名
- path:目標(biāo)輸出的目錄,是一個(gè)絕對路徑
// webpack.config.js
const config = {
output: {
filename: 'bundle.js',
path: '/home/proj/public/assets'
}
};
module.exports = config;
此配置將一個(gè)單獨(dú)的 bundle.js 文件輸出到 /home/proj/public/assets 目錄中。
2、多個(gè)入口起點(diǎn)
如果配置中存在多個(gè)入口起點(diǎn),則需要使用一定的標(biāo)識符確保每個(gè)輸出的文件名的唯一性。
// webpack.config.js
{
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name].js',
path: __dirname + '/dist'
}
}
// 寫入到硬盤:./dist/app.js, ./dist/search.js
為了確保每個(gè)輸出 bundle 名稱的唯一性,需要借用一下方式來替換:
// 1、使用入口名稱
filename: "[name].bundle.js"
// 2、使用內(nèi)部 chunk id
filename: "[id].bundle.js"
// 3、使用每次構(gòu)建生成的唯一的 hash
filename: "[name].[hasn].bundle.js"
// 4、使用基于每個(gè) chunk 內(nèi)容的 hash
filename:“[chunkhash].bundle.js”
三、loader:加載器
loader 是用于對模塊的源代碼進(jìn)行轉(zhuǎn)換。在需要加載模塊時(shí)對其做預(yù)處理,它可以將文件從不同的語言(如 typescript)轉(zhuǎn)換為 JavaScript,或?qū)?nèi)聯(lián)圖像轉(zhuǎn)為 data URL,甚至允許你直接在 JavaScript 模塊中 import CSS文件。
1、使用 loader 的三種方式
- 配置(推薦):在 webpack.config.js 文件中指定 loader
- 內(nèi)聯(lián): 在每個(gè) import 語句中顯示指定 loader
- CLI: 在 shell 命令中指定它們
配置:
在 modul.rules 中允許你在 webpack 配置中指定多個(gè)loader。
module: {
rules: [
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true
}
}
]
}
]
}
內(nèi)聯(lián)
import Styles from 'style-loader!css-loader?modules!./styles.css';
使用 ! 將資源中的 loader 分開,分開的每部分都相對于當(dāng)前目錄解析。通過前置所有規(guī)則及使用 !,通過對選項(xiàng)傳遞查詢參數(shù),可以對應(yīng)覆蓋到配置中的任意 loader。
CLI
webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
上述是使用 webpack 命令,對 .jade 文件使用 jade-loader,對 .css 文件使用 style-loader 和 css-loader。
2、loader 所具有的特性
- loader 支持鏈?zhǔn)絺鬟f。能夠?qū)Y源使用流水線(pipeline)。一組鏈?zhǔn)降?loader 將按照相反的順序執(zhí)行。loader 鏈中的第一個(gè)loader 返回值給下一個(gè) loader。在最后一二 loader,返回 webpack 所預(yù)期的 JavaScript。
- loader 可以是同步的,也可以是異步的。
- 運(yùn)行在node.js 中,并且能夠執(zhí)行任何可能的操作。
- 接收查詢參數(shù),用于對 loader 傳遞配置
- 可以使用 options 對象進(jìn)行配置
- 除了使用package.json 常見的 main 屬性,還可以將普通的 你怕嗎 模塊導(dǎo)出為 loader
- 插件可以為 loader 帶來更多特性
- loader 能夠產(chǎn)生而外的任意文件
四、plugins:插件
webpack 中的插件的出現(xiàn),主要是為了實(shí)現(xiàn) loader 無法實(shí)現(xiàn)的功能,是webpack 中核心部分。
webpack 插件是一個(gè)具有 apply 屬性的 JavaScript 對象,apply 屬性會(huì)被 webpack 編譯器調(diào)用,并且編譯器對象可以在整個(gè)編譯生命周期訪問。
用法
在 webpack 配置中,你可以攜帶參數(shù)或者選項(xiàng),想 plugins 屬性中傳入 new 實(shí)例:
1、在配置中傳入 new 實(shí)例
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); //通過 npm 安裝
const webpack = require('webpack'); //訪問內(nèi)置的插件
const path = require('path');
const config = {
entry: './path/to/my/entry/file.js',
output: {
filename: 'my-first-webpack.bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: 'babel-loader'
}
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin(),
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
module.exports = config;
2、Node API 傳入 new 實(shí)例
//