以表誠意,先附上一份配置全解:css
const path = require('path');
module.exports = {
// entry 表示 入口,Webpack 執行構建的第一步將從 Entry 開始,可抽象成輸入。
// 類型能夠是 string | object | array
entry: './app/entry', // 只有1個入口,入口只有1個文件
entry: ['./app/entry1', './app/entry2'], // 只有1個入口,入口有2個文件
entry: { // 有2個入口
a: './app/entry-a',
b: ['./app/entry-b1', './app/entry-b2']
},
// 如何輸出結果:在 Webpack 通過一系列處理後,如何輸出最終想要的代碼。
output: {
// 輸出文件存放的目錄,必須是 string 類型的絕對路徑。
path: path.resolve(__dirname, 'dist'),
// 輸出文件的名稱
filename: 'bundle.js', // 完整的名稱
filename: '[name].js', // 當配置了多個 entry 時,經過名稱模版爲不一樣的 entry 生成不一樣的文件名稱
filename: '[chunkhash].js', // 根據文件內容 hash 值生成文件名稱,用於瀏覽器長時間緩存文件
// 發佈到線上的全部資源的 URL 前綴,string 類型
publicPath: '/assets/', // 放到指定目錄下
publicPath: '', // 放到根目錄下
publicPath: 'https://cdn.example.com/', // 放到 CDN 上去
// 導出庫的名稱,string 類型
// 不填它時,默認輸出格式是匿名的當即執行函數
library: 'MyLibrary',
// 導出庫的類型,枚舉類型,默認是 var
// 能夠是 umd | umd2 | commonjs2 | commonjs | amd | this | var | assign | window | global | jsonp ,
libraryTarget: 'umd',
// 是否包含有用的文件路徑信息到生成的代碼裏去,boolean 類型
pathinfo: true,
// 附加 Chunk 的文件名稱
chunkFilename: '[id].js',
chunkFilename: '[chunkhash].js',
// JSONP 異步加載資源時的回調函數名稱,須要和服務端搭配使用
jsonpFunction: 'myWebpackJsonp',
// 生成的 Source Map 文件名稱
sourceMapFilename: '[file].map',
// 瀏覽器開發者工具裏顯示的源碼模塊名稱
devtoolModuleFilenameTemplate: 'webpack:///[resource-path]',
// 異步加載跨域的資源時使用的方式
crossOriginLoading: 'use-credentials',
crossOriginLoading: 'anonymous',
crossOriginLoading: false,
},
// 配置模塊相關
module: {
rules: [ // 配置 Loader
{
test: /\.jsx?$/, // 正則匹配命中要使用 Loader 的文件
include: [ // 只會命中這裏面的文件
path.resolve(__dirname, 'app')
],
exclude: [ // 忽略這裏面的文件
path.resolve(__dirname, 'app/demo-files')
],
use: [ // 使用那些 Loader,有前後次序,從後往前執行
'style-loader', // 直接使用 Loader 的名稱
{
loader: 'css-loader',
options: { // 給 html-loader 傳一些參數
}
}
]
},
],
noParse: [ // 不用解析和處理的模塊
/special-library\.js$/ // 用正則匹配
],
},
// 配置插件
plugins: [
],
// 配置尋找模塊的規則
resolve: {
modules: [ // 尋找模塊的根目錄,array 類型,默認以 node_modules 爲根目錄
'node_modules',
path.resolve(__dirname, 'app')
],
extensions: ['.js', '.json', '.jsx', '.css'], // 模塊的後綴名
alias: { // 模塊別名配置,用於映射模塊
// 把 'module' 映射 'new-module',一樣的 'module/path/file' 也會被映射成 'new-module/path/file'
'module': 'new-module',
// 使用結尾符號 $ 後,把 'only-module' 映射成 'new-module',
// 可是不像上面的,'module/path/file' 不會被映射成 'new-module/path/file'
'only-module$': 'new-module',
},
alias: [ // alias 還支持使用數組來更詳細的配置
{
name: 'module', // 老的模塊
alias: 'new-module', // 新的模塊
// 是不是隻映射模塊,若是是 true 只有 'module' 會被映射,若是是 false 'module/inner/path' 也會被映射
onlyModule: true,
}
],
symlinks: true, // 是否跟隨文件軟連接去搜尋模塊的路徑
descriptionFiles: ['package.json'], // 模塊的描述文件
mainFields: ['main'], // 模塊的描述文件裏的描述入口的文件的字段名稱
enforceExtension: false, // 是否強制導入語句必需要寫明文件後綴
},
// 輸出文件性能檢查配置
performance: {
hints: 'warning', // 有性能問題時輸出警告
hints: 'error', // 有性能問題時輸出錯誤
hints: false, // 關閉性能檢查
maxAssetSize: 200000, // 最大文件大小 (單位 bytes)
maxEntrypointSize: 400000, // 最大入口文件大小 (單位 bytes)
assetFilter: function(assetFilename) { // 過濾要檢查的文件
return assetFilename.endsWith('.css') || assetFilename.endsWith('.js');
}
},
devtool: 'source-map', // 配置 source-map 類型
context: __dirname, // Webpack 使用的根目錄,string 類型必須是絕對路徑
// 配置輸出代碼的運行環境
target: 'web', // 瀏覽器,默認
target: 'webworker', // WebWorker
target: 'node', // Node.js,使用 `require` 語句加載 Chunk 代碼
target: 'async-node', // Node.js,異步加載 Chunk 代碼
target: 'node-webkit', // nw.js
target: 'electron-main', // electron, 主線程
target: 'electron-renderer', // electron, 渲染線程
externals: { // 使用來自 JavaScript 運行環境提供的全局變量
jquery: 'jQuery'
},
stats: { // 控制檯輸出日誌控制
assets: true,
colors: true,
errors: true,
errorDetails: true,
hash: true,
},
devServer: { // DevServer 相關的配置
proxy: { // 代理到後端服務接口
'/api': 'http://localhost:3000'
},
contentBase: path.join(__dirname, 'public'), // 配置 DevServer HTTP 服務器的文件根目錄
compress: true, // 是否開啓 gzip 壓縮
historyApiFallback: true, // 是否開發 HTML5 History API 網頁
hot: true, // 是否開啓模塊熱替換功能
https: false, // 是否開啓 HTTPS 模式
},
profile: true, // 是否捕捉 Webpack 構建的性能信息,用於分析什麼緣由致使構建性能不佳
cache: false, // 是否啓用緩存提高構建速度
watch: true, // 是否開始
watchOptions: { // 監聽模式選項
// 不監聽的文件或文件夾,支持正則匹配。默認爲空
ignored: /node_modules/,
// 監聽到變化發生後會等300ms再去執行動做,防止文件更新太快致使從新編譯頻率過高
// 默認爲300ms
aggregateTimeout: 300,
// 判斷文件是否發生變化是不停的去詢問系統指定文件有沒有變化,默認每隔1000毫秒詢問一次
poll: 1000
},
}
複製代碼
在Webpack裏一切文件都是模塊,經過Loader
轉換文件,經過Plugin
注入鉤子,最後輸出由多個模塊組合成的文件,Webpack專一於構建模塊化項目。 這樣的好處是能清晰的描述出各個模塊之間的依賴關係,以方便Webpack對模塊進行組合和打包。通過Webpack處理,最終會輸出瀏覽器能使用的靜態資源。html
Webpack的優勢:node
const path = require('path');
module.exports = {
// JavaScript 執行入口文件
entry: './main.js',
output: {
// 把全部依賴的模塊合併輸出到一個 bundle.js 文件
filename: 'bundle.js',
// 輸出文件都放到 dist 目錄下
path: path.resolve(__dirname, './dist'),
},
module: {
rules: [
{
// 用正則去匹配要用該 loader 轉換的 CSS 文件
test: /\.css$/,
use: ['style-loader', 'css-loader?minimize'],
}
]
}
};
複製代碼
Loader能夠看做具備文件轉換功能的翻譯員,配置裏的module.rules數組配置了一組規則,告訴Webpack在遇到哪些文件時使用哪些Loaer去加載和轉換。 注意:react
給Loader傳入屬性的方式除了querystring
,還能夠經過配置options
jquery
use: [
'style-loader',
{
loader: 'css-lader',
options: {
minimize: true
}
}
]
複製代碼
除了在webpack.config.js
文件中配置Loader,還能夠在源碼中指定用什麼Loader去處理文件,好比webpack
require('style-loader!css-loader?minimize!./main.css')
複製代碼
Plugin是用來擴展Webpack功能的,經過在構建流程裏注入鉤子實現,它給Webpack帶來了極大的靈活性。web
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
// JavaScript 執行入口文件
entry: './main.js',
output: {
// 把全部依賴的模塊合併輸出到一個 bundle.js 文件
filename: 'bundle.js',
// 把輸出文件都放到 dist 目錄下
path: path.resolve(__dirname, './dist'),
},
module: {
rules: [
{
// 用正則去匹配要用該 loader 轉換的 CSS 文件
test: /\.css$/,
use: ExtractTextPlugin.extract({
// 轉換 .css 文件須要使用的 Loader
use: ['css-loader'],
}),
}
]
},
plugins: [
new ExtractTextPlugin({ //把注入到bundle.js文件的css提取到單獨的文件
// 從 .js 文件中提取出來的 .css 文件的名稱
filename: `[name]_[contenthash:8].css`,
}),
]
};
複製代碼
Webpack經過plugins屬性來配置須要使用的插件列表,plugins是一個數組,黎綿的每一項都是插件的一個實例,在實例化一個組件時能夠經過構造函數傳入這個組件支持的配置屬性。正則表達式
實際開發中可能會須要:json
DevServer會啓動一個HTTP服務器用於服務網頁請求,同時會幫助啓動Webpack,並接收Webpack發出的文件變動信號,經過WebSocket
協議自動刷新網頁作到實時預覽。後端
須要安裝webpack-dev-server
模塊
若是嘗試修改 index.html 文件並保存,你會發現這並不會觸發以上機制,致使這個問題的緣由是 Webpack 在啓動時會以配置裏的 entry 爲入口去遞歸解析出 entry 所依賴的文件,只有 entry 自己和依賴的文件纔會被 Webpack 添加到監聽列表裏。 而 index.html 文件是脫離了 JavaScript 模塊化系統的,因此 Webpack 不知道它的存在。
模塊熱更新能作到在不從新加載整個網頁的狀況下,經過將被更新過的模塊替換老的模塊,再從新執行一次來實現實時預覽。 開啓模塊熱更新,只要在啓動DevServer時帶上--hot
參數便可。
調試工具能夠經過Source Map映射代碼,實如今源代碼上斷點調試。 啓動webpack時帶上--devtool source-map
參數便可。
Webpack啓動後會從Entry
裏配置的Module
開始遞歸解析Entry依賴的全部Module。每找到一個Module,就會根據配置的Loader
去找對應的轉換規則,對Module進行轉換後,再解析出當前Module依賴的Module。這些模塊會以Entry爲單位進行分組,一個Entry和其全部依賴的Module被分到一個組就是一個Chunk
,最後Webpack會把全部Chunk轉換成文件輸出。在整個流程中Webpack會在恰當的時機執行Plugin
裏定義的邏輯。
配置Webpack的方式:
entry是配置模塊的入口,可抽象成輸入,能夠是string, array, object, 是必填項。
Webpack在尋找相對路徑的文件時是以執行啓動Webpack時所在的當前目錄context
爲根目錄,若是要修改該默認配置,能夠:
module.exports = {
context: path.resolve(__dirname, 'app') //context必須是一個絕對路徑的字符串
}
複製代碼
Webpack會爲每一個生成的Chunk取一個名稱
假如項目裏有多個頁面須要爲每一個頁面的入口配置一個Entry,但這些頁面的數量可能會不斷增加,則這時Entry的配置會受到其餘因素的影響致使不能寫成靜態的值,解決方法是把Entry設置成一個函數去動態返回上面所說的配置:
// 同步函數
entry: () => {
return {
a:'./pages/a',
b:'./pages/b',
}
};
// 異步函數
entry: () => {
return new Promise((resolve)=>{
resolve({
a:'./pages/a',
b:'./pages/b',
});
});
};
複製代碼
output配置如何輸出最終想要的代碼,它是一個object。
output的配置項:
配置輸出文件的名稱,若是有多個Chunk須要輸出時,須要藉助模板和變量:
filename: '[name].js'
複製代碼
內置變量除了name,還有id,hash,chunkhash
配置輸出文件存放在本地的目錄,必須是string類型的絕對路徑
path: path.resolve(__dirname, 'dist_[hash]')
複製代碼
在複雜的項目裏可能會有構建一些資源須要異步加載,加載這些異步資源須要對應的URL地址。
舉個例子,須要把構建出的資源文件上傳到CDN服務上,以利於加快頁面的打開速度:
filename: '[name]_[chunkhash: 8].js'
publicPath: 'https://cdn.xxx/xxx/'
複製代碼
這時發佈到線上的html在引入js文件時:
<script src='https://cdn.example.com/assets/a_12345678.js'></script>
複製代碼
Webpack輸出的部分代碼塊可能須要異步架子,而異步加載是經過JSONP方式實現的,JSONP原理是動態的向html中插入一個<script src="url"></script>
標籤去加載異步資源。
script標籤的crossorigin屬性能夠取如下值:
一般用設置crossorigin來獲取異步加載的腳本執行時的詳細錯誤信息。
當用Webpack去構建一個能夠被其餘模塊導入使用的庫時須要用到它們。
rules配置模塊的讀取和解析規則
use
配置項來應用Loadermodule: {
rules: [
{
// 命中 JavaScript 文件
test: /\.js$/,
// 用 babel-loader 轉換 JavaScript 文件
// ?cacheDirectory 表示傳給 babel-loader 的參數,用於緩存 babel 編譯結果加快從新編譯速度
use: ['babel-loader?cacheDirectory'],
// 只命中src目錄裏的js文件,加快 Webpack 搜索速度
include: path.resolve(__dirname, 'src')
},
{
// 命中 SCSS 文件
test: /\.scss$/,
// 使用一組 Loader 去處理 SCSS 文件。
// 處理順序爲從後到前,即先交給 sass-loader 處理,再把結果交給 css-loader 最後再給 style-loader。
use: ['style-loader', 'css-loader', 'sass-loader'],
// 排除 node_modules 目錄下的文件
exclude: path.resolve(__dirname, 'node_modules'),
},
{
// 對非文本文件採用 file-loader 加載
test: /\.(gif|png|jpe?g|eot|woff|ttf|svg|pdf)$/,
use: ['file-loader'],
},
]
}
複製代碼
在Loader須要傳入不少參數時,能夠經過一個Object來描述:
use: [
{
loader:'babel-loader',
options:{
cacheDirectory:true,
},
// enforce:'post' 的含義是把該 Loader 的執行順序放到最後
// enforce 的值還能夠是 pre,表明把 Loader 的執行順序放到最前面
enforce:'post'
},
// 省略其它 Loader
]
複製代碼
test, include, exclude 還支持數組:
{
test:[
/\.jsx?$/,
/\.tsx?$/
],
include:[
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'tests'),
],
exclude:[
path.resolve(__dirname, 'node_modules'),
path.resolve(__dirname, 'bower_modules'),
]
複製代碼
可讓Webpack忽略對部分沒采用模塊化的文件的遞歸解析和處理,提升構建性能。
// 使用正則表達式
noParse: /jquery|chartjs/
// 使用函數,從 Webpack 3.0.0 開始支持
noParse: (content)=> {
// content 表明一個模塊的文件路徑
// 返回 true or false
return /jquery|chartjs/.test(content);
}
複製代碼
注意被忽略掉的文件不該該包含import, require, define等模塊化語句,否則會致使構建出的代碼中包含沒法再瀏覽器環境下執行的模塊化語句。
和noParse配置項的區別在於parser能夠精確到語法層面,而noParse只能控制哪些文件不被解析。
module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader'],
parse: {
amd: false, //禁用AMD
commonjs: false, // 禁用 CommonJS
system: false, // 禁用 SystemJS
harmony: false, // 禁用 ES6 import/export
requireInclude: false, // 禁用 require.include
requireEnsure: false, // 禁用 require.ensure
requireContext: false, // 禁用 require.context
browserify: false, // 禁用 browserify
requireJs: false, // 禁用 requirejs
}
}
]
}
複製代碼
Resolve配置Webpack如何尋找模塊所對應的文件。Webpack內置JS模塊化語法解析功能,默認會採用模塊化標準里約定好的規則去尋找。
經過別名把原導入路徑映射成一個新的導入路徑。
resolve:{
alias: {
components: './src/components/'
}
}
複製代碼
當你經過 import Button from 'components/button'
導入時,實際上被 alias 等價替換成了 import Button from './src/components/button'
alias還支持$符號來縮小範圍到只命中以關鍵字結尾的導入語句
resolve:{
alias:{
'react$': '/path/to/react.min.js'
}
}
複製代碼
有一些第三方模塊會針對不一樣環境提供幾份代碼,該配置項決定Webpack優先採用哪份代碼。
在導入語句沒帶文件後綴時,Webpack會自動帶上後綴去嘗試訪問文件是否存在,默認是:
extensions: ['.js', '.json']
複製代碼
配置Webpack去哪些目錄下尋找第三方模塊,默認只會去node_modules目錄下找
假如哪些被大量導入的模塊都在./src/components
目錄下:
modules: ['./src/components', 'node_modules']
複製代碼
這樣你就可簡單經過import 'button'
導入
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
module.exports = {
plugins: [
// 全部頁面都會用到的公共代碼提取到 common 代碼塊中
new CommonsChunkPlugin({
name: 'common',
chunks: ['a', 'b']
}),
]
};
複製代碼
使用Plugin的難點在於掌握Plugin自己提供的配置項
啓用DevServer的模塊熱更新功能。
配置是否自動注入這個代理客戶端到將運行在頁面裏的Chunk中,默認是自動注入。 若是開啓inline,DevServer會在構建完變化後的代碼時經過代理客戶端控制網頁刷新 若是關閉inline,DevServer將沒法直接控制要開發的玩野,這時它會經過iframe的方式去運行要開發的網頁。
配置DevServer HTTP服務器的文件根目錄,默認狀況下爲當前執行目錄,一般是項目根目錄。假如你想把項目根目錄下的public目錄設置成DevServer服務器的文件根目錄:
devServer: {
contentBase: paht.join(__dirname, 'public')
}
複製代碼
DevServer服務器經過HTTP服務暴露出的文件分爲兩類:
contentBase只能用來配置暴露本地文件的規則,能夠經過contentBase: false
來關閉暴露本地文件。
該配置項能夠在HTTP響應中注入一些HTTP響應頭:
devServer: {
headers: {
'X-foo':'bar'
}
}
複製代碼
用於配置DevServer服務監聽的地址
配置一個白名單列表,只有HTTP請求的HOST在列表裏才正常返回
allowedHosts: [
// 匹配單個域名
'host.com',
'sub.host.com',
// host2.com 和全部的子域名 *.host2.com 都將匹配
'.host2.com'
]
複製代碼
默認使用HTTP協議服務,它也能經過HTTPS協議服務,要切換HTTPS服務也很簡單:
devServer: {
https: true
}
複製代碼
DevServer會自動爲你生成一份HTTPS證書,也能夠本身配置:
devServer:{
https: {
key: fs.readFileSync('path/to/server.key'),
cert: fs.readFileSync('path/to/server.crt'),
ca: fs.readFileSync('path/to/ca.pem')
}
}
複製代碼
該配置決定是否啓用gzip壓縮,默認爲false
target配置項可讓webpack構建出針對不一樣運行環境的代碼,target能夠是如下之一:
web:針對瀏覽器,默認選項,全部代碼集中在一個文件裏 node: 針對Node.js,使用require語句加載chunk代碼 async-node: 針對Node.js,異步加載chunk代碼 webworker: 針對WebWorker electron-main: 針對Electron主線程 elertron-renderer: 針對Electron渲染線程
配置Webpack如何生成Source Map, 默認值是false,想爲構建出的代碼生成Source Map能夠:
module.export = {
devtool: 'source-map'
}
複製代碼
它支持監聽文件更新,在文件發生變化時從新編譯,默認是關閉的:
module.export = {
watch: true
}
複製代碼
在使用DevServer時,監聽模式默認是開啓的
watchOptions配置項能夠更靈活的控制監聽模式:
module.export = {
// 只有在開啓監聽模式時,watchOptions 纔有意義
// 默認爲 false,也就是不開啓
watch: true,
// 監聽模式運行時的參數
// 在開啓監聽模式時,纔有意義
watchOptions: {
// 不監聽的文件或文件夾,支持正則匹配
// 默認爲空
ignored: /node_modules/,
// 監聽到變化發生後會等300ms再去執行動做,防止文件更新太快致使從新編譯頻率過高
// 默認爲 300ms
aggregateTimeout: 300,
// 判斷文件是否發生變化是經過不停的去詢問系統指定文件有沒有變化實現的
// 默認每隔1000毫秒詢問一次
poll: 1000
}
}
複製代碼
配置Webpack要構建的代碼中使用了哪些不用被打包的模塊,也就是說這些模板是外部環境提供的,Webpack在打包時能夠忽略它們。
經過Externals能夠告訴Webpack JavaScript運行環境已經內置了那些全局變量,針對這些全局變量不用打包進代碼中而是直接使用全局變量:
module.export = {
externals: {
// 把導入語句裏的 jquery 替換成運行環境裏的全局變量 jQuery
jquery: 'jQuery'
}
}
複製代碼
用來告訴Webpack如何去尋找Loader
module.exports = {
resolveLoader:{
// 去哪一個目錄下尋找 Loader
modules: ['node_modules'],
// 入口文件的後綴
extensions: ['.js', '.json'],
// 指明入口文件位置的字段
mainFields: ['loader', 'main']
}
}
複製代碼
該配置項一般用於加載本地的Loader
除了經過導出一個Object來描述Webpack所需的配置外,還有其餘更靈活的方式。
在大多數時候你須要從同一份源碼中構建出多份代碼,一份用於開發時,一份用於發佈線上。
若是採用導出一個Object來描述Webpack所需的配置的文件,須要寫兩個文件。在啓動時經過webpack --config webpack.config.js
來指定使用哪一個配置文件。
採用導出一個Function的方式,能經過JavaScript靈活的控制配置,作到只用一個配置文件就能完成以上要求。
const path = require('path');
const UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin');
module.exports = function (env = {}, argv) {
const plugins = [];
const isProduction = env['production'];
// 在生成環境才壓縮
if (isProduction) {
plugins.push(
// 壓縮輸出的 JS 代碼
new UglifyJsPlugin()
)
}
return {
plugins: plugins,
// 在生成環境不輸出 Source Map
devtool: isProduction ? undefined : 'source-map',
};
}
複製代碼
在運行 Webpack 時,會給這個函數傳入2個參數,分別是:
env:當前運行時的 Webpack 專屬環境變量,env 是一個 Object。讀取時直接訪問 Object 的屬性,設置它須要在啓動 Webpack 時帶上參數。例如啓動命令是 webpack --env.production --env.bao=foo
時,則 env 的值是 {"production":"true","bao":"foo"}
。 argv:表明在啓動 Webpack 時全部經過命令行傳入的參數,例如 --config、--env、--devtool,能夠經過 webpack -h 列出全部 Webpack 支持的命令行參數。 就以上配置文件而言,在開發時執行命令 webpack 構建出方便調試的代碼,在須要構建出發佈到線上的代碼時執行 webpack --env.production
構建出壓縮的代碼。
module.exports = function(env = {}, argv) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
// ...
})
}, 5000)
})
}
複製代碼
Wepack支持導出一個數組,數組彙總能夠包含每份配置,而且每份配置都會執行一遍構建。
module.exports = [
// 採用 Object 描述的一份配置
{
// ...
},
// 採用函數描述的一份配置
function() {
return {
// ...
}
},
// 採用異步函數描述的一份配置
function() {
return Promise();
}
]
複製代碼
這特別適合用Webpack構建一個要上傳到Npm倉庫的庫,由於庫中可能須要包含多種模塊化格式的代碼,例如CommonJS, UMD
從前面的配置看來選項不少,一般可用以下經驗去判斷如何配置Webpack: