該思惟導圖是根據<<深刻淺出webpack>>
章節大綱總結出來的。經過閱讀這本書梳理webpack所包含的知識點,瞭解了webpack(版本爲4.X)的相關配置,以及loader和plugin的原理以及編寫。思惟導圖可以很形象的描述出各知識點之間的關係,同時也能加深知識點在咱們心中的印象。畫此思惟導圖的目的也是爲了供之後本身複習用的。javascript
3.1 Entrycss
構建的入口,Webpack 執行構建的第一步將從 Entry 開始,可抽象成輸入。經過搜尋及遞歸找出全部入口所依賴的模塊。Entry 主要有 String、Array 和 Object 三種類型。若是爲 Array 類型時,搭配 output.library 配置項使用時,只有數組裏的最後一個入口文件的模塊會被導出。html
module.exports={
entry:'./app/entry', //入口模塊的文件路徑,能夠是相對路徑。
entry:['./app/entry1', './app/entry2'],//入口模塊的文件路徑,能夠是相對路徑。只有1個入口,兩個入口文件
entry:{
a: './app/entry-a', b: ['./app/entry-b1', './app/entry-b2']
//配置多個入口,每一個入口生成一個 Chunk。兩個入口。
},
}
複製代碼
有時候因爲項目須要,可能須要構建多個頁面入口。除了上面的靜態頁面入口配置,還能夠動態配置頁面入口。通常有以下兩種方式。前端
//同步函數
entry: () => {
return {
index: "@/pages/index",
user: "@pages/user"
};
};
//異步函數
entry: () => {
return new Promise((resolve)=>{
resolve({
a:'./pages/a',
b:'./pages/b',
});
});
};
複製代碼
3.2 Output:vue
配置如何輸出最終想要的代碼。output 是一個 object,裏面包含一系列配置項,下面分別介紹它們。java
module.exports={
...
output:{
//若是隻有一個輸出文件,則能夠把它寫成靜態不變的。
filename:'bundle.js',
//多個 Chunk 要輸出時,能夠根據 Chunk 的名稱來區分輸出的文件名
filename: '[name].js',//能夠將[name]當作字符串模板函數。該name爲內置的哈希值。
chunkFilename:[name].js,
path: path.resolve(__dirname, 'dist');
publicPath:'https://cdn.example.com/assets/',
libraryTarget:var
}
}
複製代碼
內置變量主要有如下這些:node
3.3 Modulereact
模塊,在 Webpack 裏一切皆模塊,一個模塊對應着一個文件。Webpack 會從配置的 Entry 開始遞歸找出全部依賴的模塊。主要有這些配置項。jquery
module.exports={
...
module:{
//讓 Webpack 忽略對部分沒采用模塊化的文件的遞歸解析和處理。
noParse: /jquery|chartjs/
// 從 webpack 3.0.0 開始,也能夠是函數
noParse: function(content) {
return /jquery|lodash/.test(content);
},
rules:[
{
test: /\.js$/,//轉碼執行後綴的文件,通常是正則表達式。可爲數組
use: ['babel-loader?cacheDirectory'],//?cacheDirectory 表示傳給 babel-loader 的參數,用於緩存 babel 編譯結果加快從新編譯速度。是loader 屬性的簡寫方式.(如:use: [ { loader: "style-loader "} ])。
include:path.resolve(__dirname,"src"),//只命中src文件夾下的就是文件。可爲數組
//解析選項對象。能夠更細粒度的配置哪些模塊語法要解析哪些不解析
parser:{
amd: false, // 禁用 AMD
commonjs: false, // 禁用 CommonJS
system: false, // 禁用 SystemJS
harmony: false, // 禁用 ES2015 Harmony import/export
requireInclude: false, // 禁用 require.include
requireEnsure: false, // 禁用 require.ensure
requireContext: false, // 禁用 require.context
browserify: false, // 禁用特殊處理的 browserify bundle
requireJs: false, // 禁用 requirejs.*
node: false, // 禁用 __dirname, __filename, module, require.extensions, require.main 等。
node: {...} // 在模塊級別(module level)上從新配置 node 層(layer)
},
exclude:path.resolve(__dirname,'node_modules'),//排除node_module文件夾下的js文件。可爲數組。
},
{
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'),
},
{
test: /\.js$/
use:[
loader:'babel-loader',
//在 Loader 須要傳入不少參數時,你還能夠經過一個 Object 來描述。
options:{
cacheDirectory:true,
},
// enforce:'post' 的含義是把該 Loader 的執行順序放到最後。 enforce 的值還能夠是 pre,表明把 Loader 的執行順序放到最前面
enforce:'post'
]
},
//loader還能夠採用鏈式寫法。loader從右到左的被調用
{
test:/\.css$/
use: [
'style-loader',
{
loader: 'css-loader',
//
options: {
importLoaders: 1
}
},
{
loader: 'less-loader',
options: {
noIeCompat: true
}
}
]
}
]
}
}
複製代碼
3.4 Resolvewebpack
Resolve 配置 Webpack 如何尋找模塊所對應的文件。設置模塊如何被解析。
module.exports={
...
resolve:{
//經過別名來把原導入路徑映射成一個新的導入路徑
alias:{
'components': './src/components/',
'@':"./src",
~:"./src",
'vue$': 'vue/dist/vue.esm.js',
}
//指定一個字段,例如 browser(瀏覽器環境),根據此規範進行解析。只會使用找到的第一個
aliasFields:['browser', 'main']
descriptionFiles:["package.json"],//描述文件
enforceExtension:false,//是否強制擴展名
extensions:[".js",".json"],//自動解析的擴展,導入語句沒帶文件後綴時,Webpack 會自動帶上後綴後去嘗試訪問文件是否存在.
modules:['./src/components','node_modules'],//告訴 webpack 解析模塊時應該搜索的目錄。絕對路徑和相對路徑都能使用。
}
}
複製代碼
3.5 Plugins
用於以各類方式自定義 webpack 構建過程。經過在webpack構建過程當中,經過在特定的事件階段,注入相應的邏輯來達到想要的效果。
module.exports={
...
plugins:[
// 顯示出被替換模塊的名稱
new NamedModulesPlugin(),
//定義全局環境變量的值
new DefinePlugin({
// 定義 NODE_ENV 環境變量爲 production
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
//清除文件夾(在打包時使用)
new CleanWebpackPlugin(['dist']),
//生成模板文件,生成默認開始頁面的文件,默認爲index.html
new HtmlWebpackPlugin({
title: 'Output Management',
filename:"index.html",
template:"index.html",
inject:true,//將全部的資源注入到template指定的index.html中。
}),
//壓縮代碼(只在生產環境下使用)
new UglifyJSPlugin({
cache:true,//是否使文件緩存
parallel: true,//並行壓縮代碼
sourceMap:true,//是否爲打包後的代碼生成源碼
compress: {
// 在UglifyJs刪除沒有用到的代碼時不輸出警告
warnings: false,
// 刪除全部的 `console` 語句,能夠兼容ie瀏覽器
drop_console: true,
// 內嵌定義了可是隻用到一次的變量
collapse_vars: true,
// 提取出出現屢次可是沒有定義成變量去引用的靜態值
reduce_vars: true,
dead_code:true,//刪除無用代碼
},
output: {
// 最緊湊的輸出
beautify: false,
// 刪除全部的註釋
comments: false,
}
}),
//Scope Hoisting 做用域提高,使得代碼體積更小,內存開銷也更小 ,
new ModuleConcatenationPlugin(),
//在 Webpack 輸出最終的代碼以前,對這些代碼進行優化
new PrepackWebpackPlugin(),
// 生成動態連接庫文件,通常會單獨新建dll.config.js文件,調用此插件,把一些公共經常使用的第三方模塊打包成一個動態連接庫。動態連接庫只須要編譯一次,在以後的構建過程當中被動態連接庫包含的模塊將不會在從新編譯,而是直接使用動態連接庫中的代碼。
new DllPlugin({
// 動態連接庫的全局變量名稱,須要和 output.library 中保持一致
// 該字段的值也就是輸出的 manifest.json 文件 中 name 字段的值
// 例如 react.manifest.json 中就有 "name": "_dll_react"
name: '_dll_[name]',
// 描述動態連接庫的 manifest.json 文件輸出時的文件名稱
path: path.join(__dirname, 'dist', '[name].manifest.json'),
}),
// 告訴 Webpack 使用了哪些動態連接庫
new DllReferencePlugin({
// 描述 react 動態連接庫的文件內容
manifest: require('./dist/react.manifest.json'),
}),
// 該插件的做用就是實現模塊熱替換,實際上當啓動時帶上 `--hot` 參數,會注入該插件,生成 .hot-update.json 文件。
new HotModuleReplacementPlugin(),
//自動加載模塊,而沒必要處處 import 或 require 。
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
]
}
複製代碼
3.6 DevServer
此配置項爲webpack-dev-server的專有配置項。除了在DevServer中進行配置外,還能夠經過命令行參數傳入。
module.exports={
...
devServer:{
hot:true,//是否啓用 webpack 的模塊熱替換功能。DevServer 默認的行爲是在發現源代碼被更新後會經過自動刷新整個頁面來作到實時預覽,開啓模塊熱替換功能後將在不刷新整個頁面的狀況下經過用新模塊替換老模塊來作到實時預覽。
inline:true,//DevServer 的實時預覽功能依賴一個注入到頁面裏的代理客戶端去接受來自 DevServer 的命令和負責刷新網頁的工做。inline 用於配置是否自動注入這個代理客戶端到將運行在頁面裏的 Chunk 裏去,默認是會自動注入。
contentBase:"",//配置 DevServer HTTP 服務器的文件根目錄。 默認狀況下爲當前執行目錄,一般是項目根目錄.
//能夠在 HTTP 響應中注入一些 HTTP 響應頭,
headers:{
'X-foo':'bar'
},
host:127.0.0.1,//配置監聽地址
port:8080,//配置監聽端口號
open:true,//是否自動打開瀏覽器,
openPage:"index.html",//配置瀏覽器自啓時的網頁
allowedHosts: [
'host.com',
'subdomain.host.com',
'subdomain2.host.com',
'host2.com'
],//配置一個白名單列表,只有 HTTP 請求的 HOST 在列表裏才正常返回
compress:true,//是否開啓gzip壓縮。默認爲false
//展現編譯信息
overlay: {
warnings: true,
errors: true
},
quiet:true,//啓用 quiet 後,除了初始啓動信息以外的任何內容都不會被打印到控制檯。這也意味着來自 webpack 的錯誤或警告在控制檯不可見。
//設置前端代理,訪問後臺
stats:"errors-only",//控制展現webpack構建信息
proxy:{
"/api": "http://localhost:3000",//表示後端服務接口地址爲http://localhost:3000/api
},
//配置多個代理路徑
proxy: [{
context: ["/auth", "/api"],
target: "http://localhost:3000",
}],
public:"myapp.test:80",//當啓用內聯模式時(inline:true),內聯的客戶端腳本所在的目錄。
public:"/assets/",//此路徑下的打包文件可在瀏覽器中訪問.http://localhost:8080/assets/bundle.js能夠範圍打包後的bundle.js文件。
}
}
複製代碼
3.7 其餘常見配置項
module.exports={
...
devtool:"cheap-source-map", //轉換過的代碼(僅限行)
devtool:"cheap-source-map",//原始源代碼
//開發環境的配置
devtool:"eval",//生成後的代碼 ,每一個模塊相互分離,並用模塊名稱進行註釋。
devtool:"eval-source-map",//原始源代碼
devtool:"cheap-eval-source-map",//轉換過的代碼(僅限行),它會忽略源自 loader 的 source map,而且僅顯示轉譯後的代碼
devtool:"cheap-module-eval-source-map",//原始源代碼(僅限行),源自 loader 的 source map 會獲得更好的處理結果
//生產環境的配置
devtool:(none),//省略該項配置 //打包後的代碼,全部生成的代碼視爲一大塊代碼。你看不到相互分離的模塊。
devtool:"source-map", //原始源代碼,便於調試。它爲 bundle 添加了一個引用註釋,以便開發工具知道在哪裏能夠找到它。
devtool:"hidden-source-map",//與 source-map 相同,但不會爲 bundle 添加引用註釋。若是你只想 source map 映射那些源自錯誤報告的錯誤堆棧跟蹤信息,但不想爲瀏覽器開發工具暴露你的 source map,這個選項會頗有用。
devtool:"nosources-source-map",//建立的 source map 不包含 sourcesContent(源代碼內容)。它能夠用來映射客戶端上的堆棧跟蹤,而無須暴露全部的源代碼。
target:"web",//默認值,瀏覽器環境
target:"node",//node環境
watch:true,//在使用 DevServer 時,監聽模式默認是開啓的。
//在watch配置爲true時,下面的配置項纔會生效。
watchOptions:{
ignored: /node_modules/,//不監聽的文件夾
aggregateTimeout:300,//監聽到變化發生後會等300ms再去執行動做,防止文件更新太快致使從新編譯頻率過高
poll:1000,//多久輪詢一次
}
}
複製代碼
//在index.html之外聯腳本的方式引入腳本文件
<script
src="https://code.jquery.com/jquery-3.1.0.js"
integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
crossorigin="anonymous">
</script>
//在配置文件中就能夠經過以下配置,不講jquery打包。
module.exports={
...
externals: {
//string類型
$: 'jQuery',
//Array類型
subtract: ['./math', 'subtract'],//表示的是。用subtract去代替./math/subtract方法。
//Object類型
lodash : {
commonjs: "lodash",
amd: "lodash",
root: "_" // 指向全局變量
}
}
}
複製代碼
module.exports={
performance:{
maxEntrypointSize: 400000,//默認值是:250000 (bytes)。入口起點文件的最大致積。控制 webpack 什麼時候生成性能提示.
maxAssetSize:100000,//資源(asset)是從 webpack 生成的任何文件,控制 webpack 什麼時候生成性能提示。默認值是:250000 (bytes)。
hints:false | "error" | "warning",//打開或關閉提示。此屬性默認設置爲 "warning"。能夠以提醒或錯誤的方式提醒你文件大小是否超過你設置的大小。
//對提示文件進行一個過濾。
assetFilter: function(assetFilename) {
return assetFilename.endsWith('.js');
}
},
stas:{
// `webpack --colors` 等同於
colors: false,
// 添加錯誤的詳細信息(就像解析日誌同樣)
errorDetails: true,
// 添加時間信息
timings: true,
// 添加 webpack 版本信息
version: true,
},
//如下是默認值。從 webpack 3.0.0 開始,node 選項可能被設置爲 false,以徹底關閉 NodeStuffPlugin 和 NodeSourcePlugin 插件。
node:{
console: false,// 什麼都不提供。預期獲取此對象的代碼,可能會由於獲取不到此對象,觸發 ReferenceError 而崩潰
global: true,//爲true時表示提供 polyfill。
process: true,
__filename: "mock",//提供 mock 實現預期接口,但功能不多或沒有。
__dirname: "mock",
Buffer: true,
setImmediate: true,
}
}
複製代碼
3.8 總體配置
module.exports={
context:__dirname, // Webpack 使用的根目錄,入口文件所處的目錄的絕對路徑的字符串。
/********entry配置*******/
entry:'./app/entry', //入口模塊的文件路徑,能夠是相對路徑。
entry:['./app/entry1', './app/entry2'],//入口模塊的文件路徑,能夠是相對路徑。只有1個入口,兩個入口文件
entry:{
a: './app/entry-a', b: ['./app/entry-b1', './app/entry-b2']
//配置多個入口,每一個入口生成一個 Chunk。兩個入口。
},
//同步函數
entry: () => {
return {
index: "@/pages/index",
user: "@pages/user"
};
};
//異步函數
entry: () => {
return new Promise((resolve)=>{
resolve({
a:'./pages/a',
b:'./pages/b',
});
});
},
/********entry配置*******/
/********output配置*******/
output:{
//若是隻有一個輸出文件,則能夠把它寫成靜態不變的。
filename:'bundle.js',
//多個 Chunk 要輸出時,能夠根據 Chunk 的名稱來區分輸出的文件名
filename: '[name].js',//能夠將[name]當作字符串模板函數。該name爲內置的哈希值。
filename: '[chunkhash].js', // 根據文件內容 hash 值生成文件名稱,用於瀏覽器長時間緩存文件
chunkFilename:[name].js,//配置無入口的 Chunk 在輸出時的文件名稱。常見的會在運行時生成 Chunk 場景有在使用 CommonChunkPlugin、使用 import('path/to/module') 動態加載等時。
sourceMapFilename: "[file].map",//此選項會向硬盤寫入一個輸出文件,只在 devtool 啓用了 SourceMap 選項時才使用。
path: path.resolve(__dirname, 'dist');//輸出文件存放在本地的目錄
publicPath:'https://cdn.example.com/assets/',//加載異步資源對應的 URL 地址。
publicPath:"/dist",//放到指定目錄下
publicPath:"",//放到根目錄下
//配置以何種方式導出庫。注意,此選項與分配給 output.library 的值一同使用
libraryTarget:"var",//(默認值)當 library 加載完成,入口起點的返回值將分配給一個變量:
libraryTarget: "this",//入口起點的返回值將分配給 this 的一個屬性(此名稱由 output.library 定義)
libraryTarget: "window",//分配給 window 對象
libraryTarget: "global",//分配給 global 對象
libraryTarget: "commonjs",//入口起點的返回值將使用 output.library 中定義的值,分配給 exports 對象。
libraryTarget: "commonjs2",//入口起點的返回值將分配給 module.exports 對象
libraryTarget: "amd",//將你的 library 暴露爲 AMD 模塊。
libraryTarget: "umd",//將你的 library 暴露爲全部的模塊定義下均可運行的方式
library: "MyLibrary",
...
},
/********output配置*******/
/********module配置*******/
module:{
//讓 Webpack 忽略對部分沒采用模塊化的文件的遞歸解析和處理。
noParse: /jquery|chartjs/
// 從 webpack 3.0.0 開始,也能夠是函數
noParse: function(content) {
return /jquery|lodash/.test(content);
},
rules:[
{
test: /\.js$/,//轉碼執行後綴的文件,通常是正則表達式。可爲數組
use: ['babel-loader?cacheDirectory'],//?cacheDirectory 表示傳給 babel-loader 的參數,用於緩存 babel 編譯結果加快從新編譯速度。是loader 屬性的簡寫方式.(如:use: [ { loader: "style-loader "} ])。
include:path.resolve(__dirname,"src"),//只命中src文件夾下的就是文件。可爲數組
//解析選項對象。能夠更細粒度的配置哪些模塊語法要解析哪些不解析
parser:{
amd: false, // 禁用 AMD
commonjs: false, // 禁用 CommonJS
system: false, // 禁用 SystemJS
harmony: false, // 禁用 ES2015 Harmony import/export
requireInclude: false, // 禁用 require.include
requireEnsure: false, // 禁用 require.ensure
requireContext: false, // 禁用 require.context
browserify: false, // 禁用特殊處理的 browserify bundle
requireJs: false, // 禁用 requirejs.*
node: false, // 禁用 __dirname, __filename, module, require.extensions, require.main 等。
node: {...} // 在模塊級別(module level)上從新配置 node 層(layer)
},
exclude:path.resolve(__dirname,'node_modules'),//排除node_module文件夾下的js文件。可爲數組。
},
{
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'),
},
{
test: /\.js$/,
//use等同loaders
use:[
loader:'babel-loader',
//在 Loader 須要傳入不少參數時,你還能夠經過一個 Object 來描述。
options:{
cacheDirectory:true,
},
// enforce:'post' 的含義是把該 Loader 的執行順序放到最後。 enforce 的值還能夠是 pre,表明把 Loader 的執行順序放到最前面
enforce:'post'
]
},
//loader還能夠採用鏈式寫法。loader從右到左的被調用
{
test:/\.css$/
use: [
'style-loader',
{
loader: 'css-loader',
//
options: {
importLoaders: 1
}
},
{
loader: 'less-loader',
options: {
noIeCompat: true
}
}
]
}
]
},
// 配置插件
plugins: [
//定義全局環境變量的值
new DefinePlugin({
// 定義 NODE_ENV 環境變量爲 production
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
//清除文件夾(在打包時使用)
new CleanWebpackPlugin(['dist']),
//生成模板文件,生成默認開始頁面的文件,默認爲index.html
new HtmlWebpackPlugin({
title: 'Output Management',
filename:"index.html",
template:"index.html",
inject:true,//將全部的資源注入到template指定的index.html中。
}),
//壓縮代碼(只在生產環境下使用)
new UglifyJSPlugin({
cache:true,//是否使文件緩存
parallel: true,//並行壓縮代碼
sourceMap:true,//是否爲打包後的代碼生成源碼
compress: {
// 在UglifyJs刪除沒有用到的代碼時不輸出警告
warnings: false,
// 刪除全部的 `console` 語句,能夠兼容ie瀏覽器
drop_console: true,
// 內嵌定義了可是隻用到一次的變量
collapse_vars: true,
// 提取出出現屢次可是沒有定義成變量去引用的靜態值
reduce_vars: true,
dead_code:true,//刪除無用代碼
},
output: {
// 最緊湊的輸出
beautify: false,
// 刪除全部的註釋
comments: false,
}
}),
//Scope Hoisting 做用域提高,使得代碼體積更小,內存開銷也更小 ,
new ModuleConcatenationPlugin(),
//在 Webpack 輸出最終的代碼以前,對這些代碼進行優化
new PrepackWebpackPlugin(),
// 生成動態連接庫文件,通常會單獨新建dll.config.js文件,調用此插件,把一些公共經常使用的第三方模塊打包成一個動態連接庫。動態連接庫只須要編譯一次,在以後的構建過程當中被動態連接庫包含的模塊將不會在從新編譯,而是直接使用動態連接庫中的代碼。
new DllPlugin({
// 動態連接庫的全局變量名稱,須要和 output.library 中保持一致
// 該字段的值也就是輸出的 manifest.json 文件 中 name 字段的值
// 例如 react.manifest.json 中就有 "name": "_dll_react"
name: '_dll_[name]',
// 描述動態連接庫的 manifest.json 文件輸出時的文件名稱
path: path.join(__dirname, 'dist', '[name].manifest.json'),
}),
// 告訴 Webpack 使用了哪些動態連接庫
new DllReferencePlugin({
// 描述 react 動態連接庫的文件內容
manifest: require('./dist/react.manifest.json'),
}),
// 該插件的做用就是實現模塊熱替換,實際上當啓動時帶上 `--hot` 參數,會注入該插件,生成 .hot-update.json 文件。
new HotModuleReplacementPlugin(),
//自動加載模塊,而沒必要處處 import 或 require 。
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
],
// 配置尋找模塊的規則
resolve:{
//經過別名來把原導入路徑映射成一個新的導入路徑
alias:{
'components': './src/components/',
'@':"./src",
~:"./src",
'vue$': 'vue/dist/vue.esm.js',
}
//指定一個字段,例如 browser(瀏覽器環境),根據此規範進行解析。只會使用找到的第一個
aliasFields:['browser', 'main']
descriptionFiles:["package.json"],//描述文件
enforceExtension:false,//是否強制擴展名
extensions:[".js",".json"],//自動解析的擴展,導入語句沒帶文件後綴時,Webpack 會自動帶上後綴後去嘗試訪問文件是否存在.
modules:['./src/components','node_modules'],//告訴 webpack 解析模塊時應該搜索的目錄。絕對路徑和相對路徑都能使用。
},
//開發模式下的服務器配置
devServer:{
hot:true,//是否啓用 webpack 的模塊熱替換功能。DevServer 默認的行爲是在發現源代碼被更新後會經過自動刷新整個頁面來作到實時預覽,開啓模塊熱替換功能後將在不刷新整個頁面的狀況下經過用新模塊替換老模塊來作到實時預覽。
inline:true,//DevServer 的實時預覽功能依賴一個注入到頁面裏的代理客戶端去接受來自 DevServer 的命令和負責刷新網頁的工做。inline 用於配置是否自動注入這個代理客戶端到將運行在頁面裏的 Chunk 裏去,默認是會自動注入。
contentBase:"",//配置 DevServer HTTP 服務器的文件根目錄。 默認狀況下爲當前執行目錄,一般是項目根目錄.
//能夠在 HTTP 響應中注入一些 HTTP 響應頭,
headers:{
'X-foo':'bar'
},
host:127.0.0.1,//配置監聽地址
port:8080,//配置監聽端口號
open:true,//是否自動打開瀏覽器,
openPage:"index.html",//配置瀏覽器自啓時的網頁
allowedHosts: [
'host.com',
'subdomain.host.com',
'subdomain2.host.com',
'host2.com'
],//配置一個白名單列表,只有 HTTP 請求的 HOST 在列表裏才正常返回
compress:true,//是否開啓gzip壓縮。默認爲false
//展現編譯信息
overlay: {
warnings: true,
errors: true
},
quiet:true,//啓用 quiet 後,除了初始啓動信息以外的任何內容都不會被打印到控制檯。這也意味着來自 webpack 的錯誤或警告在控制檯不可見。
//設置前端代理,訪問後臺
stats:"errors-only",//控制展現webpack構建信息
proxy:{
"/api": "http://localhost:3000",//表示後端服務接口地址爲http://localhost:3000/api
},
//配置多個代理路徑
proxy: [{
context: ["/auth", "/api"],
target: "http://localhost:3000",
}],
public:"myapp.test:80",//當啓用內聯模式時(inline:true),內聯的客戶端腳本所在的目錄。
public:"/assets/",//此路徑下的打包文件可在瀏覽器中訪問.http://localhost:8080/assets/bundle.js能夠範圍打包後的bundle.js文件。
},
//source map配置
devtool:"cheap-source-map", //轉換過的代碼(僅限行)
devtool:"cheap-source-map",//原始源代碼
//開發環境的配置
devtool:"eval",//生成後的代碼 ,每一個模塊相互分離,並用模塊名稱進行註釋。
devtool:"eval-source-map",//原始源代碼
devtool:"cheap-eval-source-map",//轉換過的代碼(僅限行),它會忽略源自 loader 的 source map,而且僅顯示轉譯後的代碼
devtool:"cheap-module-eval-source-map",//原始源代碼(僅限行),源自 loader 的 source map 會獲得更好的處理結果
//生產環境的配置
devtool:(none),//省略該項配置 //打包後的代碼,全部生成的代碼視爲一大塊代碼。你看不到相互分離的模塊。
devtool:"source-map", //原始源代碼,便於調試。它爲 bundle 添加了一個引用註釋,以便開發工具知道在哪裏能夠找到它。
devtool:"hidden-source-map",//與 source-map 相同,但不會爲 bundle 添加引用註釋。若是你只想 source map 映射那些源自錯誤報告的錯誤堆棧跟蹤信息,但不想爲瀏覽器開發工具暴露你的 source map,這個選項會頗有用。
devtool:"nosources-source-map",//建立的 source map 不包含 sourcesContent(源代碼內容)。它能夠用來映射客戶端上的堆棧跟蹤,而無須暴露全部的源代碼。
externals: { // 使用來自 JavaScript 運行環境提供的全局變量
//string類型
$: 'jQuery',
//Array類型
subtract: ['./math', 'subtract'],//表示的是。用subtract去代替./math/subtract方法。
//Object類型
lodash : {
commonjs: "lodash",
amd: "lodash",
root: "_" // 指向全局變量
}
},
// 配置輸出代碼的運行環境
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, 渲染線程
//開啓監聽模式
watch:true,//在使用 DevServer 時,監聽模式默認是開啓的。
//在watch配置爲true時,下面的配置項纔會生效。
watchOptions:{
ignored: /node_modules/,//不監聽的文件夾
aggregateTimeout:300,//監聽到變化發生後會等300ms再去執行動做,防止文件更新太快致使從新編譯頻率過高
poll:1000,//多久輪詢一次
}
stats: { // 控制檯輸出日誌控制,webpack構建時的統計信息。
assets: true,//添加資源信息
colors: true,// `webpack --colors` 等同於
errors: true,//輸出錯誤信息
errorDetails: true,//// 添加錯誤的詳細信息(就像解析日誌同樣)
hash: true,//添加 compilation 的哈希值
version:true,//添加尾巴爬蟲庫版本信息
performance: true,// 當文件大小超過 `performance.maxAssetSize` 時顯示性能提示
modules: true,// 添加構建模塊信息,
// 添加時間信息
timings: true,
},
// 輸出文件性能檢查配置,這些選項能夠控制 webpack 如何通知「資源(asset)和入口起點超過指定文件限制」。
performance:{
maxEntrypointSize: 400000,//默認值是:250000 (bytes)。入口起點文件的最大致積。控制 webpack 什麼時候生成性能提示.
maxAssetSize:100000,//資源(asset)是從 webpack 生成的任何文件,控制 webpack 什麼時候生成性能提示。默認值是:250000 (bytes)。
hints:false | "error" | "warning",//打開或關閉提示。此屬性默認設置爲 "warning"。能夠以提醒或錯誤的方式提醒你文件大小是否超過你設置的大小。
//對提示文件進行一個過濾。
assetFilter: function(assetFilename) {
return assetFilename.endsWith('.js');
}
},
//配置是否 polyfill 或 mock 某些 Node.js 全局變量和模塊。這可使最初爲 Node.js 環境編寫的代碼,在其餘環境(如瀏覽器)中運行。此功能由 webpack 內部的 NodeStuffPlugin 插件提供。
node:{
console: false,// 什麼都不提供。預期獲取此對象的代碼,可能會由於獲取不到此對象,觸發 ReferenceError 而崩潰
global: true,//爲true時表示提供 polyfill。
process: true,
__filename: "mock",//提供 mock 實現預期接口,但功能不多或沒有。
__dirname: "mock",
Buffer: true,
setImmediate: true,
}
}
複製代碼
3.9 多種配置類型
配置文件除了以Object的形式輸出之外,還能夠以function或者promise的形式輸出,同時還能夠導出多個配置對象。
//以對象的形式,須要寫多個配置文件以適應"開發和生產"模式
module.exports={
entry:"app.js",
output:{
},
...
},
//導出多個配置對象
module.exports=[{
output: {
filename: './dist-amd.js',
libraryTarget: 'amd'
},
entry: './app.js',
mode: 'production',
}, {
output: {
filename: './dist-commonjs.js',
libraryTarget: 'commonjs'
},
entry: './app.js',
mode: 'production',
}]
//以function的形式,採用導出一個 Function 的方式,能經過 JavaScript 靈活的控制配置,作到只用寫一個配置文件就能完成以上要求。
module.exports=function(env={},args){
const isProduction=env["production"];
const plugins=[];
//返回的仍是那些配置文件
return {
plugins: plugins,
// 在生成環境不輸出 Source Map
devtool: isProduction ? undefined : 'source-map',
};
}
//以promise的形式導出
module.exports=function(env={},args){
return new Promise(resolve,reject){
setTimeout(() => {
resolve({
entry: './app.js',
/* ... */
})
}, 5000)
}
}
複製代碼
以函數的形式導出配置文件時。
4.1 開發環境下的優化
1)、縮小文件搜索範圍(主要是對配置項中的module和resolve配置項進行優化)
module.exports={
//一、優化module配置項中的查找範圍
module:{
//一、忽略對部分沒采用模塊化的文件的遞歸解析處理,這樣作的好處是能提升構建性能。
noParse:/jQuery|ChartJS/,
rules:[
test: /\.js$/,
use:["babel-loader"]
include:path.resolve(__dirname, 'src'),//二、縮小搜索範圍
]
},
//二、縮小resolve模塊搜索範圍
resolve: {
// 一、使用絕對路徑指明第三方模塊存放的位置,以減小搜索步驟
// 其中 __dirname 表示當前工做目錄,也就是項目根目錄
modules: [path.resolve(__dirname, 'node_modules')],
//二、在明確第三方模塊的入口文件描述字段時。能夠只採用 main(單個字段) 字段做爲入口文件描述字段,以減小搜索步驟。
mainFields: ['main'],
alias:{
"@":"./src",//三、經過配置別名來跳過耗時的遞歸解析操做。
}
//四、這個列表越長,或者正確的後綴在越後面,就會形成嘗試的次數越多
extensions: ['.js', '.json']
},
}
複製代碼
2)、使用動態連接庫(DllPlugin)
//新建一個dll.config.js文件,跟日常的配置文件同樣
const DllPlugin = require('webpack/lib/DllPlugin');
module.export={
entry:{
vender:["vue","axios","vue-router","vuex"]
},
output:{
path:resolve(__dirname,"../src/static"),
filename:"[name].js",
library:"[name]_library"
}
plugins: [
// 接入 DllPlugin
new DllPlugin({
// 動態連接庫的全局變量名稱,須要和 output.library 中保持一致
// 該字段的值也就是輸出的 manifest.json 文件 中 name 字段的值
// 例如 react.manifest.json 中就有 "name": "_dll_react"
name: '_dll_[name]',
// 描述動態連接庫的 manifest.json 文件輸出時的文件名稱
path: path.join(__dirname, 'dist', '[name].manifest.json'),
}),
],
}
//在開發或生產環境配置文件中
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
module.exports={
...
plugins:[
new DllReferencePlugin({
// 描述 react 動態連接庫的文件內容
manifest: require('./dist/vender.manifest.json'),
}),
]
}
複製代碼
3)、使用HappyPack(並行loader去轉換代碼)
//它把任務分解給多個子進程去併發的執行,子進程處理完後再把結果發送給主進程。
const HappyPack = require('happypack');
module.exports={
module:{
rules:[
{
test: /\.js$/,
// 把對 .js 文件的處理轉交給 id 爲 babel 的 HappyPack 實例
use: ['happypack/loader?id=babel'],
// 排除 node_modules 目錄下的文件,node_modules 目錄下的文件都是採用的 ES5 語法,不必再經過 Babel 去轉換
exclude: /node_modules/,
},{
// 把對 .css 文件的處理轉交給 id 爲 css 的 HappyPack 實例
test: /\.css$/,
use: ['happypack/loader?id=css'],
}
]
},
plugins:[
new HappyPack({
// 用惟一的標識符 id 來表明當前的 HappyPack 是用來處理一類特定的文件
id: 'babel',
// 如何處理 .js 文件,用法和 Loader 配置中同樣
loaders: ['babel-loader?cacheDirectory'],
// ... 其它配置項
}),
new HappyPack({
// 用惟一的標識符 id 來表明當前的 HappyPack 是用來處理一類特定的文件
id: 'css',
// 如何處理 .js 文件,用法和 Loader 配置中同樣
loaders: ['css-loader'],
// ... 其它配置項
}),
]
}
複製代碼
1)、使用自動刷新
文件監聽:在發現源碼文件發生變化時,自動從新構建出新的輸出文件。是 webpack 模塊提供的。
文件監聽原理:Webpack 中監聽一個文件發生變化的原理是定時的去獲取這個文件的最後編輯時間,每次都存下最新的最後編輯時間,若是發現當前獲取的和最後一次保存的最後編輯時間不一致,就認爲該文件發生了變化。
自動刷新的原理:webpack 模塊負責監聽文件,webpack-dev-server 模塊則負責刷新瀏覽器。 在使用 webpack-dev-server 模塊去啓動 webpack 模塊時,webpack 模塊的監聽模式默認會被開啓。
控制瀏覽器刷新有三種方法:
1、藉助瀏覽器擴展去經過瀏覽器提供的接口刷新,WebStorm IDE 的 LiveEdit 功能就是這樣實現的。
2、往要開發的網頁中注入代理客戶端代碼,經過代理客戶端去刷新整個頁面。(DevServer默認採用的,爲輸出的每一個chunk注入代理客戶端,是經過inline屬性來控制的。)
3、把要開發的網頁裝進一個 iframe 中,經過刷新 iframe 去看到最新效果。
module.exports = {
// 只有在開啓監聽模式時,watchOptions 纔有意義
// 默認爲 false,也就是不開啓
watch: true,
// 監聽模式運行時的參數
// 在開啓監聽模式時,纔有意義
watchOptions: {
// 不監聽的文件或文件夾,支持正則匹配
// 默認爲空
ignored: /node_modules/,
// 監聽到變化發生後會等300ms再去執行動做,防止文件更新太快致使從新編譯頻率過高
// 默認爲 300ms
//值越大性能越好,由於這能下降從新構建的頻率。
aggregateTimeout: 300,
// 判斷文件是否發生變化是經過不停的去詢問系統指定文件有沒有變化實現的
// 默認每隔1000毫秒詢問一次
//值越大越好,由於這能下降檢查的頻率。
poll: 1000,
}
}
複製代碼
2)、開啓模塊熱加載
模塊熱加載原理:當一個源碼發生變化時,只從新編譯發生變化的模塊,再用新輸出的模塊替換掉瀏覽器中對應的老模塊。
優勢:
1、實時預覽反應更快,等待時間更短。
2、不刷新瀏覽器,並且能保留當前網頁的運行狀態。
module.exports={
devServer:{
hot:true,
}
}
當子模塊發生更新時,更新事件會一層層往上傳遞,直到有某層的文件接受了當前變化的模塊,若是事件一直往上拋到最外層都沒有文件接受它,就會直接刷新網頁。
優化模塊熱更新:在main.js中注入以下代碼。
if (module.hot) {
module.hot.accept(['./AppComponent'], callback);
//'./AppComponent':表示監聽的模塊;callback表示回調。
}
module.exports = {
plugins: [
// 顯示出被替換模塊的名稱
new NamedModulesPlugin(),
],
};
注意:
1、關閉默認的 inline 模式手動注入代理客戶端的優化方法不能用於在使用模塊熱替換的狀況下。
2、監聽更少的文件,忽略掉 node_modules 目錄下的文件。
複製代碼
4.2 生產環境下的優化
1)、區分環境
2)、壓縮代碼
1、這裏壓縮的是ES6代碼。
const UglifyESPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
plugins: [
new UglifyESPlugin({
// 多嵌套了一層,用於壓縮ES6代碼
uglifyOptions: {
compress: {
// 在UglifyJs刪除沒有用到的代碼時不輸出警告
warnings: false,
// 刪除全部的 `console` 語句,能夠兼容ie瀏覽器
drop_console: true,
// 內嵌定義了可是隻用到一次的變量
collapse_vars: true,
// 提取出出現屢次可是沒有定義成變量去引用的靜態值
reduce_vars: true,
},
output: {
// 最緊湊的輸出
beautify: false,
// 刪除全部的註釋
comments: false,
}
}
})
]
}
2、壓縮css代碼
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
module: {
rules: [
{
test: /\.css$/,// 增長對 CSS 文件的支持
// 提取出 Chunk 中的 CSS 代碼到單獨的文件中
use: ExtractTextPlugin.extract({
// 經過 minimize 選項壓縮 CSS 代碼
use: ['css-loader?minimize']
}),
},
]
},
plugins: [
new ExtractTextPlugin({
filename: `[name]_[contenthash:8].css`,// 給輸出的 CSS 文件名稱加上 Hash 值
}),
],
};
複製代碼
3)、使用CDN進行加速
CDN 又叫內容分發網絡,經過把資源部署到世界各地,用戶在訪問時按照就近原則從離用戶最近的服務器獲取資源,從而加速資源的獲取速度。
使用CDN要注意的問題:
1、針對 HTML 文件:不開啓緩存,把 HTML 放到本身的服務器上,而不是 CDN 服務上,同時關閉本身服務器上的緩存。
2、針對靜態的 JavaScript、CSS、圖片等文件:開啓 CDN 和緩存,上傳到 CDN 服務上去,同時給每一個文件名帶上由文件內容算出的 Hash 值。帶上 Hash 值的緣由是文件名會隨着文件內容而變化,只要文件發生變化其對應的 URL 就會變化,它就會被從新下載,不管緩存時間有多長。
Webpack 實現 CDN 的接入要注意一下幾點:
1、靜態資源的導入 URL 須要變成指向 CDN 服務的絕對路徑的 URL 而不是相對於 HTML 文件的 URL。
2、靜態資源的文件名稱須要帶上有文件內容算出來的 Hash 值,以防止被緩存。
3、不一樣類型的資源放到不一樣域名的 CDN 服務上去,以防止資源的並行加載被阻塞。
在webpack中的基本配置以下:
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const htmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 省略 entry 配置...
output: {
// 給輸出的 JavaScript 文件名稱加上 Hash 值
filename: '[name]_[chunkhash:8].js',
path: path.resolve(__dirname, './dist'),
// 指定存放 JavaScript 文件的 CDN 目錄 URL
publicPath: '//js.cdn.com/id/',
},
module: {
rules: [
{
// 增長對 CSS 文件的支持
test: /\.css$/,
// 提取出 Chunk 中的 CSS 代碼到單獨的文件中
use: ExtractTextPlugin.extract({
// 壓縮 CSS 代碼
use: ['css-loader?minimize'],
// 指定存放 CSS 中導入的資源(例如圖片)的 CDN 目錄 URL
publicPath: '//img.cdn.com/id/'
}),
},
]
},
plugins: [
// 使用 WebPlugin 自動生成 HTML
new htmlWebpackPlugin({
// HTML 模版文件所在的文件路徑
template: './template.html',
// 輸出的 HTML 的文件名稱
filename: 'index.html',
// 指定存放 CSS 文件的 CDN 目錄 URL
stylePublicPath: '//css.cdn.com/id/',
}),
new ExtractTextPlugin({
// 給輸出的 CSS 文件名稱加上 Hash 值
filename: `[name]_[contenthash:8].css`,
}),
// 省略代碼壓縮插件配置...
],
};
複製代碼
4)、使用Tree-Shaking刪除無用的代碼
Tree Shaking 能夠用來剔除 JavaScript 中用不上的死代碼。它依賴靜態的 ES6 模塊化語法。
Tree Shaking的侷限性在於:
1、不會對entry入口文件作 Tree Shaking。
2、不會對異步分割出去的代碼作 Tree Shaking。
想要是Tree Shaking起做用,須要作到這幾步。
1、修改.babelrc 文件
{
"presets": [
[
"env",
{
"modules": false
}
]
]
}
2、使用代碼壓縮(在命令行中加上--optimize-minimize)
module.exports={
resolve: {
// 針對 Npm 中的第三方模塊優先採用 jsnext:main 中指向的 ES6 模塊化語法的文件(Tree Shaking只對ES6模塊化語法的文件起做用,因此須要以下配置。)
mainFields: ['jsnext:main', 'browser', 'main']
},
plugins:[
new UglifyJSPlugin()
]
}
複製代碼
5)、進行按需加載(使用import())
6)、提取公共代碼
module.exports={
...
optimization:{
splitChunks: {
cacheGroups:{ // 這裏開始設置緩存的
vendor: { // key 爲entry中定義的 入口名稱
priority: 1, // 緩存組優先級
chunks: "all",
test: /[\\/]node_modules[\\/]babel-runtime/,
name: 'babel-runtime',
}
}
},
}
}
複製代碼
1)、開啓 Scope Hoisting(較少函數聲明語句)
Scope Hoisting 可讓 Webpack 打包出來的代碼文件更小、運行的更快, 它又譯做 "做用域提高"。Scope Hoisting 的實現原理其實很簡單:分析出模塊之間的依賴關係,儘量的把打散的模塊合併到一個函數中去,但前提是不能形成代碼冗餘。 所以只有那些被引用了一次的模塊才能被合併。所以源碼必須採用 ES6 模塊化語句,否則它將沒法生效。
使用Scope Hoisting的好處:
1、代碼體積更小,由於函數聲明語句會產生大量代碼;
2、代碼在運行時由於建立的函數做用域更少了,內存開銷也隨之變小。
const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
module.exports = {
resolve: {
// 針對 Npm 中的第三方模塊優先採用 jsnext:main 中指向的 ES6 模塊化語法的文件
mainFields: ['jsnext:main', 'browser', 'main']
},
plugins: [
// 開啓 Scope Hoisting
new ModuleConcatenationPlugin(),
],
};
複製代碼
後記:至於webpack的原理及loader和plugin的原理及編寫這裏就不在囉嗦了。這樣的資料網上一搜一大把。這片文檔主要是對webpack的配置及優化作了一些總結。資料來源主要是《升入淺出webpack》和webpack的官網。