插件(plugins
)
插件是
webpack
的支柱功能。插件目的在于解決loader
無法實現(xiàn)的其他事嘉栓。
webpack
插件是一個具有 apply
屬性的 JavaScript
對象按傅。apply
屬性會被 webpack compiler
調(diào)用,并且 compiler
對象可在整個編譯生命周期訪問。如ConsoleLogOnBuildWebpackPlugin.js
:
class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
//compiler hook 的 tap 方法的第一個參數(shù)衷敌,
//應該是駝峰式命名的插件名稱
compiler.hooks.run.tap(pluginName, compilation => {
console.log("webpack 構建過程開始!");
});
}
}
一些插件簡介:
Name | Description |
---|---|
AggressiveSplittingPlugin | 將原來的 chunk 分成更小的 chunk |
BabelMinifyWebpackPlugin | 使用 babel-minify進行壓縮 |
BannerPlugin | 在每個生成的 chunk 頂部添加 banner |
CommonsChunkPlugin | 提取 chunks 之間共享的通用模塊 |
CompressionWebpackPlugin | 預先準備的資源壓縮版本拓瞪,使用 Content-Encoding 提供訪問服務 |
ContextReplacementPlugin | 重寫 require 表達式的推斷上下文 |
CopyWebpackPlugin | 將單個文件或整個目錄復制到構建目錄 |
DefinePlugin | 允許在編譯時(compile time)配置的全局常量 |
DllPlugin | 為了極大減少構建時間缴罗,進行分離打包 |
EnvironmentPlugin | DefinePlugin 中 process.env 鍵的簡寫方式。 |
ExtractTextWebpackPlugin | 從 bundle 中提取文本(CSS)到單獨的文件 |
HotModuleReplacementPlugin | 啟用模塊熱替換(Enable Hot Module Replacement - HMR) |
HtmlWebpackPlugin | 簡單創(chuàng)建 HTML 文件祭埂,用于服務器訪問 |
I18nWebpackPlugin | 為 bundle 增加國際化支持 |
IgnorePlugin | 從 bundle 中排除某些模塊 |
LimitChunkCountPlugin | 設置 chunk 的最小/最大限制面氓,以微調(diào)和控制 chunk |
LoaderOptionsPlugin | 用于從 webpack 1 遷移到 webpack 2 |
MinChunkSizePlugin | 確保 chunk 大小超過指定限制 |
NoEmitOnErrorsPlugin | 在輸出階段時,遇到編譯錯誤跳過 |
NormalModuleReplacementPlugin | 替換與正則表達式匹配的資源 |
NpmInstallWebpackPlugin | 在開發(fā)時自動安裝缺少的依賴 |
ProvidePlugin | 不必通過 import/require 使用模塊 |
SourceMapDevToolPlugin | 對 source map進行更細粒度的控制 |
EvalSourceMapDevToolPlugin | 對 eval source map 進行更細粒度的控制 |
UglifyjsWebpackPlugin | 可以控制項目中 UglifyJS 的版本 |
ZopfliWebpackPlugin | 通過 node-zopfli 將資源預先壓縮的版本 |
更多第三方插件蛆橡,請查看 awesome-webpack 列表舌界。
用法案例:CommonsChunkPlugin
The CommonsChunkPlugin
已經(jīng)從webpack v4 legato
中移除。想要了解在最新版本中如何處理chunk
泰演,請查看SplitChunksPlugin
(該插件配置過程更為便捷高效)呻拌。
以
element-ui
初始化工程為例看下vendor.js
:
import Vue from 'vue'
import ElementUI from 'element-ui'
由于插件可以攜帶參數(shù)/選項,你必須在 webpack
配置中睦焕,向 plugins
屬性傳入 new
實例柏锄。根據(jù)你的 webpack
用法,這里有多種方式使用插件复亏。
//package.json中引入依賴
"devDependencies": {
...
"html-webpack-plugin": "^2.24.1",
"webpack": "^2.4.1",
...
}
//webpack.config.js中引入
//通過 npm 直接安裝插件
const HtmlWebpackPlugin
= require('html-webpack-plugin');
//訪問webpack內(nèi)置的插件
//CommonsChunkPlugin就是內(nèi)置插件之一
const webpack = require('webpack');
功能:該插件用于提取
chunks
之間共享的通用模塊趾娃。使用CommonsChunkPlugin
從「應用程序bundle
」中提取vendor 引用
(vendor reference
) 到vendor bundle
,并把引用vendor
的部分替換為__webpack_require__()
調(diào)用
Node API
(O(∩_∩)O~缔御,這個是啥)
「
TODO
」即便使用Node API
抬闷,用戶也應該在配置中傳入plugins
屬性。compiler.apply
并不是推薦的使用方式。
//some-node-script.js
//訪問 webpack 運行時(runtime)
const webpack = require('webpack');
const configuration = require('./webpack.config.js');
let compiler = webpack(configuration);
compiler.apply(new webpack.ProgressPlugin());
compiler.run(function(err, stats) {
// ...
});
你知道嗎:以上看到的示例和
webpack
自身運行時(runtime
) 極其類似笤成。wepback
源碼中隱藏有大量使用示例评架,你可以用在自己的配置和腳本中。
官網(wǎng)插件
HtmlWebpackPlugin
根據(jù)配置的入口和出口炕泳,自動生成
index.html
纵诞,且會自動引入相關的依賴。
- 如果你想要了解更多
HtmlWebpackPlugin
插件提供的全部功能和選項培遵,那么你就應該多多熟悉HtmlWebpackPlugin
倉庫浙芙。 - 你還可以看一下
html-webpack-template
,除了默認模板之外籽腕,還提供了一些額外的功能嗡呼。
CleanWebpackPlugin
- 你可能已經(jīng)注意到,由于過去的指南和代碼示例遺留下來皇耗,導致我們的
/dist
文件夾相當雜亂南窗。 -
webpack
會生成文件,然后將這些文件放置在/dist
文件夾中郎楼,但是webpack
無法追蹤到哪些文件是實際在項目中用到的万伤。 - 通常,在每次構建前清理
/dist
文件夾呜袁,是比較推薦的做法壕翩,因此只會生成用到的文件。讓我們完成這個需求傅寡。 -
clean-webpack-plugin
是一個比較普及的管理插件放妈,讓我們安裝和配置下。
npm install clean-webpack-plugin --save-dev
-
webpack.config.js
中配置:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
+ const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
plugins: [
+ new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Output Management'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
- 現(xiàn)在執(zhí)行
npm run build
荐操,再檢查/dist
文件夾芜抒。如果一切順利埂淮,你現(xiàn)在應該不會再看到舊的文件唉锌,只有構建后生成的文件厂僧!
WebpackManifestPlugin
該插件能夠在項目根目錄生成一份
manifest.json
的文件导绷,通過該文件的映射關系可以讓我們知道webpack
是如何追蹤所有模塊并映射到輸出bundle
中的。
//安裝插件:
npm install --save-dev webpack-manifest-plugin
//在 webpack.config.js中引入跨释,大致如下:
var ManifestPlugin = require('webpack-manifest-plugin');
module.exports = {
// ...
plugins: [
new ManifestPlugin()
// ManifestPlugin方法可以接受一些選項參數(shù)options,如
// new ManifestPlugin(options)
]
};
//3.可選參數(shù)如下:
options.fileName 表示要生成文件的名稱官地,默認為manifest.json
options.publicPath 表示生成映射文件的路徑缔俄,默認為output.publicPath
還有其他的參數(shù)見官網(wǎng)
https://github.com/danethurber/webpack-manifest-plugin
HotModuleReplacementPlugin
開發(fā)環(huán)境啟用
HMR
:啟用此功能實際上相當簡單疗绣。而我們要做的毫目,就是更新webpack-dev-server
的配置军俊,和使用webpack
內(nèi)置的HMR
插件
IgnorePlugin
import
或require
調(diào)用時吊骤,忽略以下正則表達式匹配的模塊:
// requestRegExp 匹配(test)資源請求路徑的正則表達式登失。
// contextRegExp (可選)匹配(test)資源上下文(目錄)的正則表達式哈打。
new webpack.IgnorePlugin(
requestRegExp, [contextRegExp]
)
舉例:moment
包
比如我們要使用moment
這個第三方依賴庫,該庫主要是對時間進行格式化讯壶,并且支持多個國家語言料仗。
import moment from 'moment'
//設置語言
moment.locale('zh-cn');
let r = moment().endOf('day').fromNow();
console.log(r);
- 這樣打印出來的就是中文的時間,因為我在使用這個
API
的時候伏蚊,前面設置了語言類型moment.locale
為中文zh-cn
立轧。 - 但是,雖然我設置了語言為中文躏吊,但是在打包的時候氛改,是會將所有語言都打包進去的。這樣就導致包很大颜阐,打包速度又慢
- 所以,最好能夠少打包一些沒用的依賴目錄進去
- 而
moment
的包含./locale/
該字段路徑的文件目錄就是各國語言的目錄吓肋,比如./locale/zh-cn
就是中文語言 - 使用
IgnorePlugin
let webpack = require('webpack');
plugins:[
//moment這個庫中凳怨,如果引用了./locale/目錄的內(nèi)容,
//就忽略掉是鬼,不會打包進去
new webpack.IgnorePlugin(/\.\/locale/,/moment/),
]
- 我們雖然按照上面的方法忽略了包含
./locale/
該字段路徑的文件目錄,但是也使得我們使用的時候不能顯示中文語言了肤舞,所以這個時候可以手動引入中文語言的目錄
import moment from 'moment'
//手動引入所需要的語言包
import 'moment/locale/zh-cn';
moment.locale('zh-cn');
let r = moment().endOf('day').fromNow();
console.log(r);
- 這樣就OK了。既能夠顯示中文均蜜,又把不必要的語言包都忽略打包了
DllPlugin
DLLPlugin
和DLLReferencePlugin
用某種方法實現(xiàn)了拆分bundles
李剖,同時還大大提升了構建的速度(dll
是一種最簡單粗暴并且極其有效的優(yōu)化方式)。
- 用
Webpack
打包的時候囤耳,對于一些不經(jīng)常更新的第三方庫篙顺,比如react
,lodash
充择,我們希望能和自己的代碼分離開德玫,Webpack
社區(qū)有兩種方案
CommonsChunkPlugin
和DLLPlugin
- 對于
CommonsChunkPlugin
:-
webpack
每次打包實際還是需要去處理這些第三方庫,只是打包完之后椎麦,能把第三方庫和我們自己的代碼分開宰僧。 - 且每次工程重新打包,
verdors
也會重新打包观挎,打包的chunkhash
就會改變,導致每次發(fā)布琴儿,vendors
的緩存都會失效。這樣增加了用戶的流量消耗和首屏加載時間嘁捷。
-
- 而
DLLPlugin
則是能把第三方代碼完全分離開造成,即每次只打包項目自身的代碼。引入的第三方包沒有改變就不需要重新打包雄嚣。 DLLPlugin
具體用法:
/**
要使用 DLLPlugin谜疤,需要額外新建一個配置文件。
所以對于用這種方式打包的項目,
一般會有下面兩個配置文件:
webpack.config.js
webpack.dll.config.js
先來看下 webpack.dll.config.js
*/
const webpack = require('webpack')
const library = '[name]_lib'
const path = require('path')
module.exports = {
entry: {
vendors: ['react', 'lodash']
//上面的vendors夷磕,看到有人有的libs
},
output: {
filename: '[name].dll.js',
path: 'dist/',
library
},
plugins: [
new webpack.DllPlugin({
//執(zhí)行的上下文環(huán)境履肃,對之后DllReferencePlugin有用
context: __dirname,
path: path.join(
__dirname, 'dist/[name]-manifest.json'
),
// This must match the output.library option above
name: library
}),
],
}
//再改下 webpack.config.js 文件
const webpack = require('webpack')
module.exports = {
entry: {
app: './src/index'
},
output: {
filename: 'app.bundle.js',
path: 'dist/',
},
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
//下面的vendors有人用libs
manifest: require('./dist/vendors-manifest.json')
})
]
}
/**
manifest: require('./dist/vendors-manifest.json')
這里的路徑要和 webpack.dll.config.js 里面的對應。
然后運行:
*/
$ webpack --config webpack.dll.config.js
$ webpack --config webpack.config.js
//然后你的 html 文件像下面這樣引用
<script src="/dist/vendors.dll.js"></script>
<script src="/dist/app.bundle.js"></script>
/**
上面的用法也存在一些不方便的地方坐桩,
比如在 webpack.config.js 中要明確
指出對應的 manifest.json 文件尺棋。
還有當 DLL 需要更新的時候,
比如 react 升級了绵跷,或者加入新的第三方庫膘螟,
都需要手動像下面這樣編譯一次。
*/
$ webpack --config webpack.dll.config.js
/**
---非官方插件(不需關注碾局,沒有緩存作用了吧荆残?)----
因為上面這些問題,
所以基于官方的 DllReferencePlugin净当,
有一個 Dll Link Plugin内斯。鏈接如下:
www.npmjs.com/package/dll-link-webpack-plugin
使用這個插件,
只需要對 webpack.config.js 作下小小的改動
*/
const webpack = require('webpack')
const DllLinkPlugin = require('dll-link-webpack-plugin')
module.exports = {
// ...
plugins: [
new DllLinkPlugin({
config: require('webpack.dll.config.js')
})
]
}
/**
直接替換掉 DllReferencePlugin像啼,
然后傳入對應的 DLL 配置文件就可以了俘闯。
每次打包的時候,只需要運行
*/
$ webpack --config webpack.config.js
/**
上面的命令便會自動生成對應的 vendors 文件忽冻,
需要更新的時候真朗,也會自動更新。
*/
SplitChunksPlugin
在默認情況下僧诚,
SplitChunksPlugin
僅僅影響按需加載的代碼塊遮婶,因為更改初始塊會影響HTML文件應包含的腳本標記以運行項目。-
webpack
將根據(jù)以下條件自動拆分代碼塊:- 會被共享的代碼塊或者 node_mudules 文件夾中的代碼塊
- 體積大于30KB的代碼塊(在gz壓縮前)
- 按需加載代碼塊時的并行請求數(shù)量不超過5個
- 加載初始頁面時的并行請求數(shù)量不超過3個
//舉例: // 文件一:impvue.js import 'vue' ... // 文件二:index.js // 動態(tài)加載 impvue.js import('./impvue') ... /** 打包之后的結果會創(chuàng)建一個包含 vue 的獨立代碼塊湖笨, 當包含 impvue.js 的原始代碼塊被調(diào)用時蹭睡, 這個獨立代碼塊會并行請求進來。 原因: 1) vue 來自 node_modules 文件夾 2) vue 體積超過30KB 3) 導入調(diào)用時的并行請求數(shù)為2 4) 不影響頁面初始加載 */
我們這樣做的原因是因為赶么,
vue
代碼并不像你的業(yè)務代碼那樣經(jīng)常變動肩豁,把它單獨提取出來就可以和你的業(yè)務代碼分開緩存,極大的提高效率辫呻。SplitChunksPlugin
的默認配置
splitChunks: {
/**
chunks屬性用來選擇分割哪些代碼塊清钥,
可選值有:
'all'(所有代碼塊)
'async'(按需加載的代碼塊)
'initial'(初始化代碼塊)
*/
chunks: "async",
minSize: 30000, // 模塊的最小體積
minChunks: 1, // 模塊的最小被引用次數(shù)
maxAsyncRequests: 5, // 按需加載的最大并行請求數(shù)
maxInitialRequests: 3, // 一個入口最大并行請求數(shù)
automaticNameDelimiter: '~', // 文件名的連接符
name: true,
/**
緩存組是個有趣的功能:
在默認設置中,
會將`node_mudules`中的模塊打包進`vendors`放闺,
引用超過兩次的模塊分配到`default` `bundle` 中祟昭。
更可以通過 `priority` 來設置優(yōu)先級。
*/
cacheGroups: { // 緩存組
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
- 在項目中添加
SplitChunksPlugin
/**
為了方便演示怖侦,我們先安裝兩個類庫: lodash 和 axios篡悟,
npm i lodash axios -S
修改 main.js谜叹,引入 lodash 和axios 并調(diào)用相應方法:
*/
import Modal from './components/modal/modal'
import './assets/style/common.less'
import _ from 'lodash'
import axios from 'axios'
const App = function () {
let div = document.createElement('div')
div.setAttribute('id', 'app')
document.body.appendChild(div)
let dom = document.getElementById('app')
let modal = new Modal()
dom.innerHTML = modal.template({
title: '標題',
content: '內(nèi)容',
footer: '底部'
})
}
const app = new App()
console.log(_.camelCase('Foo Bar'))
axios.get('aaa')
/**
-----------------------------
使用SplitChunksPlugin不需要安裝任何依賴,
只需在 webpack.config.js 中的 config對象
添加 optimization 屬性:
*/
optimization: {
splitChunks: {
chunks: 'initial',
automaticNameDelimiter: '.',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: 1
}
}
},
//一般都配合runtimeChunkPlugin使用
runtimeChunk: {
name: entrypoint => `manifest.${entrypoint.name}`
}
}
/**
配置 runtimeChunk 會給每個入口添加一個只包含runtime的額外的代碼塊搬葬,
name 的值也可以是字符串荷腊,不過這樣就會給每個入口添加相同的 runtime,
配置為函數(shù)時急凰,返回當前的entry對象女仰,即可分入口設置不同的runtime。
*/
/**
我們再安裝一個 webpack-bundle-analyzer抡锈,
這個插件會清晰的展示出打包后的各個bundle所依賴的模塊:
引入:
*/
const BundleAnalyzerPlugin =
require('webpack-bundle-analyzer').BundleAnalyzerPlugin
//使用疾忍,在plugins數(shù)組中添加即可:
new BundleAnalyzerPlugin()
- 可以看看
Webpack4
之SplitChunksPlugin
這里提及的問題
BannerPlugin
為每個
chunk
文件頭部添加banner
(注釋/版權)。
new webpack.BannerPlugin(options)
//options選項:
{
banner: string, // 其值為字符串床三,將作為注釋存在
raw: boolean, // 如果值為 true一罩,將直出,不會被作為注釋
entryOnly: boolean, // 如果值為 true撇簿,將只在入口 chunks 文件中添加
test: string | RegExp | Array,
include: string | RegExp | Array,
exclude: string | RegExp | Array,
}
CopyWebpackPlugin
:拷貝靜態(tài)文件
將單個文件或整個目錄直接從源目錄拷貝到構建目錄.
//config:配置了一些參數(shù)
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
},
//上面的static目錄先不管聂渊,
//我們先看這個,文件中是一些客戶可自行修改的配置
//獨立出來补疑,方便修改
{
from: path.resolve(config.directory.root, 'sysconfig.js'),
to: 'sysconfig.js'
},
])
打包好的工程下:
ExtractTextWebpackPlugin
:分離CSS
文件
MiniCssExtractPlugin
這個呢歧沪?
const ExtractTextPlugin
= require("extract-text-webpack-plugin");
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
}
]
},
plugins: [
new ExtractTextPlugin("styles.css"),
/**
我看我們的工程中是這樣配置的
具體的后續(xù)再好好看下:
new ExtractTextPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css'),
allChunks: true,
}),
*/
]
}
它會將所有的入口
chunk(entry chunks)
中引用的*.css
歹撒,移動到獨立分離的CSS
文件莲组。因此,你的樣式將不再內(nèi)嵌到JS bundle
中暖夭,而是會放到一個單獨的CSS
文件(即styles.css
)當中锹杈。 如果你的樣式文件大小較大,這會做更快提前加載迈着,因為CSS bundle
會跟JS bundle
并行加載竭望。
再來看個CSS優(yōu)化
(壓縮)相關的另一個插件optimize-css-assets-webpack-plugin
:
/**這個插件可以接受下列配置(均為可選):
assetNameRegExp: 正則,用于匹配需要優(yōu)化的資源名裕菠。默認值是 /\.css$/g
cssProcessor: 用于壓縮和優(yōu)化CSS 的處理器咬清,默認是 cssnano.這是一個函數(shù),
應該按照 cssnano.process 接口(接受一個CSS和options參數(shù)奴潘,返回一個Promise)
canPrint: {bool} 表示插件能夠在console中打印信息旧烧,默認值是true
*/
// webpack4+
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// webpack4
module.exports = {
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourcMap: true
}),
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.optimize\.css$/g,
cssProcessor: require('cssnano'),
cssProcessorOptions: { safe: true, discardComments: { removeAll: true } },
canPrint: true
}),
],
},
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
}),
]
};
//webpack3中一般配合 ExtractTextPlugin一起使用。
UglifyjsWebpackPlugin
此插件使用
uglify-js
進行js
文件的壓縮画髓。
- 下面說明是來自:關閉開發(fā)環(huán)境的代碼壓縮
UglifyJsPlugin
- 開發(fā)環(huán)境是不需要去壓縮代碼掘剪,主要是因為太耗性能了,每修改一個地方就要花幾秒去等待頁面渲染奈虾,非常浪費開發(fā)時間夺谁,解決辦法就是配置不同的環(huán)境變量
- 去在開發(fā)環(huán)境的時候不要這個
UglifyJsPlugin
插件廉赔,為此,webpack4
又增加了新的Mode
匾鸥,且默認值是production
蜡塌;而且更新后的webpack
默認是有UglifyJsPlugin
這個配置的 - 也就是說在不設置任何環(huán)境變量的情況下,始終會有壓縮代碼的行為出現(xiàn)扫腺,導致編譯極其耗時岗照,那我的解決辦法就是在
package.json
文件啟動時設置環(huán)境變量:
Tree Shaking
:一個術語,通常用于描述移除JavaScript
上下文中的未引用代碼(dead-code)
笆环。新的webpack 4
正式版本攒至,擴展了這個檢測能力,通過package.json
的sideEffects
屬性作為標記躁劣,向compiler
提供提示迫吐,表明項目中的哪些文件是pure(純的 ES2015 模塊)
,由此可以安全地刪除文件中未使用的部分账忘。
- 這種方式是通過
package.json
的sideEffects
屬性來實現(xiàn)的志膀。
{
"name": "your-project",
"sideEffects": false
}
- 如果你的代碼確實有一些副作用,那么可以改為提供一個數(shù)組:
{
"name": "your-project",
"sideEffects": [
"./src/some-side-effectful-file.js"
]
}
- 從
webpack 4
開始鳖擒,也可以通過mode
配置選項輕松切換到壓縮輸出溉浙,只需設置為production
。 - 配置
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
mode: "production"
};
DefinePlugin
DefinePlugin
允許創(chuàng)建一個在編譯時可以配置的全局常量蒋荚。這可能會對開發(fā)模式和發(fā)布模式的構建允許不同的行為非常有用戳稽。如果在開發(fā)構建中,而不在發(fā)布構建中執(zhí)行日志記錄期升,則可以使用全局常量來決定是否記錄日志惊奇。這就是DefinePlugin
的用處,設置它播赁,就可以忘記開發(fā)和發(fā)布構建的規(guī)則颂郎。
new webpack.DefinePlugin({
/**
在vue-cli創(chuàng)建的項目中,
凡是src下的文件容为,都可以訪問到下面這些變量乓序,如VERSION,
例如main.js坎背,App.vue等等
*/
PRODUCTION: JSON.stringify(true),
VERSION: JSON.stringify("5fa3b9"),
BROWSER_SUPPORTS_HTML5: true,
TWO: "1+1",
//根據(jù)process.env.NODE_ENV區(qū)分環(huán)境,引入配置文件
process.env: {NODE_ENV: "development"},
})
EnvironmentPlugin
: 是一個通過DefinePlugin
來設置process.env
環(huán)境變量的快捷方式替劈。
new webpack.EnvironmentPlugin(['NODE_ENV', 'DEBUG'])
//上面的寫法和下面這樣使用 DefinePlugin 的效果相同:
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.env.DEBUG': JSON.stringify(process.env.DEBUG)
})
HashedModuleIdsPlugin
該插件會根據(jù)模塊的相對路徑生成一個四位數(shù)的
hash
作為模塊id
, 建議用于生產(chǎn)環(huán)境。
//其他具體說明再看看
new webpack.HashedModuleIdsPlugin({
hashFunction: 'sha256',
hashDigest: 'hex',
hashDigestLength: 20
})
ZipPlugin
(好像官網(wǎng)沒列)
發(fā)布的時候可以使用 壓縮插件將資源(圖片沼瘫,配置文件等)壓縮成一個
.zip
文件
//參數(shù)中配置了需要將工程打包
if (config.build.productionToZip) {
const ZipPlugin = require('zip-webpack-plugin')
webpackConfig.plugins.push(
new ZipPlugin({
path: config.build.assetsZipRoot,
filename: 'build.zip',
extension: 'zip',
})
)
}
ModuleConcatenationPlugin
-
webpack2
處理后的每個模塊均被一個函數(shù)包裹抬纸,如下:
/* 50 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
window.lib = {}
...
/* harmony default export */ __webpack_exports__["a"] = (window.lib);
/***/ }),
- 這樣會帶來一個問題:降低瀏覽器中
JS
執(zhí)行效率,這主要是閉包函數(shù)降低了JS
引擎解析速度耿戚。 - 于是webpack團隊參考
Closure Compiler
和Rollup JS
湿故,將一些有聯(lián)系的模塊阿趁,放到一個閉包函數(shù)里面去,通過減少閉包函數(shù)數(shù)量從而加快JS
的執(zhí)行速度坛猪。 -
webpack3
通過設置ModuleConcatenationPlugin
使用這個新特性:
module.exports = {
plugins: [
new webpack.optimize.ModuleConcatenationPlugin()
]
}
- 記住脖阵,此插件僅適用于由
webpack
直接處理的ES6
模塊。在使用轉譯器(transpiler
)時墅茉,你需要禁用對模塊的處理(例如Babel
中的modules
選項)命黔。
NpmInstallWebpackPlugin
在開發(fā)時自動安裝缺少的依賴:
package.json
中需要配置了才會自動安裝哦
//安裝
npm install --save-dev npm-install-webpack-plugin
//用法
//不要忘記引入哦
const NpmInstallPlugin = require('npm-install-webpack-plugin')
//插件配置:
plugins: [
new NpmInstallPlugin()
],
//相當于:
plugins: [
new NpmInstallPlugin({
// 使用 --save 或者 --save-dev
dev: false,
// 安裝缺少的 peerDependencies
peerDependencies: true,
// 減少控制臺日志記錄的數(shù)量
quiet: false,
// npm command used inside company, yarn is not supported yet
npm: 'tnpm'
});
],
//可以提供一個 Function 來動態(tài)設置 dev:
plugins: [
new NpmInstallPlugin({
dev: function(module, path) {
return [
"babel-preset-react-hmre",
"webpack-dev-middleware",
"webpack-hot-middleware",
].indexOf(module) !== -1;
},
}),
],
ProvidePlugin
自動加載模塊,而不必到處
import
或require
就斤。
//要自動加載 jquery悍募,我們可以將兩個變量都指向對應的 node 模塊:
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
//然后在我們?nèi)我庠创a中:
$('#item'); // <= 起作用
jQuery('#item'); // <= 起作用
//使用:Lodash Map
new webpack.ProvidePlugin({
_map: ['lodash', 'map']
})
//使用:Vue.js
new webpack.ProvidePlugin({
Vue: ['vue/dist/vue.esm.js', 'default']
})
LimitChunkCountPlugin
當你在編寫代碼時,可能已經(jīng)添加了許多代碼分離點(
code split point
)來實現(xiàn)按需加載(load stuff on demand
)洋机。在編譯完之后坠宴,你可能會注意到有一些很小的chunk
- 這產(chǎn)生了大量HTTP
請求開銷。幸運的是绷旗,此插件可以通過合并的方式喜鼓,后處理你的chunk
,以減少請求數(shù)衔肢。
//改善`chunk`傳輸?shù)牟寮?
//LimitChunkCountPlugin
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 5, // 必須大于或等于 1
minChunkSize: 1000
})
/**MinChunkSizePlugin:
通過合并小于 minChunkSize 大小的 chunk庄岖,
將 chunk 體積保持在指定大小限制以上。
*/
new webpack.optimize.MinChunkSizePlugin({
// Minimum number of characters
minChunkSize: 10000
})
/**
AggressiveSplittingPlugin可以將 bundle拆分成更小的chunk角骤,
直到各個 chunk 的大小達到 option 設置的 maxSize隅忿。
它通過目錄結構將模塊組織在一起。
*/
new webpack.optimize.AggressiveSplittingPlugin({
minSize: 30000, // 字節(jié)启搂,分割點硼控。默認:30720
maxSize: 50000, // 字節(jié)刘陶,每個文件最大字節(jié)胳赌。默認:51200
chunkOverhead: 0, // 默認:0
entryChunkMultiplicator: 1, // 默認:1
})
SourceMapDevToolPlugin
生成source map
的兩種配置
- 配置
devtool
//最簡單的生成source map的方式是,如下配置webpack.config.js匙隔,
const path = require('path');
module.exports = {
devtool: 'source-map',
entry: {
index: path.resolve(__dirname, 'src/index.js'),
},
output: {
devtoolModuleFilenameTemplate: '[resource-path]',
path: path.resolve(__dirname, 'dist/'),
filename: 'index.js',
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
query: { presets: ['@babel/preset-env'] }
}
},
]
},
};
/**
其中疑苫,devtool默認值為false,
配置為source-map表示以獨立的文件形式生成source map纷责。
因此捍掺,dist/ 文件夾下,會產(chǎn)生兩個文件再膳,
index.js
index.js.map
index.js文件末尾挺勿,webpack會自動添加一行注釋,
//# sourceMappingURL=index.js.map
瀏覽器解析到這里喂柒,會自動根據(jù)index.js的相對路徑不瓶,請求map文件并加載它禾嫉。
*/
SourceMapDevToolPlugin
/**
除了直接配置devtool之外,
還可以使用webpack官方插件SourceMapDevToolPlugin蚊丐,
進行更細粒度的source map配置熙参。
*/
const path = require('path');
const webpack = require('webpack');
module.exports = {
// devtool: 'source-map',
entry: {
index: path.resolve(__dirname, 'src/index.js'),
},
output: {
// devtoolModuleFilenameTemplate: '[resource-path]',
path: path.resolve(__dirname, 'dist/'),
filename: 'index.js',
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
query: { presets: ['@babel/preset-env'] }
}
},
]
},
plugins: [
new webpack.SourceMapDevToolPlugin({
filename: '[file].map',
moduleFilenameTemplate: '[resource-path]',
append: '\n//# sourceMappingURL=http://127.0.0.1:8080/dist/[url]'
}),
],
};
/**
以上配置中,我們注釋掉了
devtool和devtoolModuleFilenameTemplate麦备,
將它們配置到了SourceMapDevToolPlugin中孽椰。
這樣配置,dist/目錄最后也會生成兩個文件凛篙,
index.js
index.js.map
由于我們使用了該插件的append功能黍匾,
修改了sourceMappingURL地址,
因此呛梆,index.js末尾source map文件的地址就變成了膀捷,
//# sourceMappingURL=http://127.0.0.1:8080/dist/index.js.map
*/
- 注:這里值得一提的是
同時配置devtool和SourceMapDevToolPlugin是不行的,
index.js文件末尾會被添加兩行sourceMappingURL削彬,
//# sourceMappingURL=http://127.0.0.1:8080/dist/index.js.map
//# sourceMappingURL=index.js.map
而且map文件的內(nèi)容也不正確全庸,是一個空的map文件,
-
EvalSourceMapDevToolPlugin
:對 eval source map 進行更細粒度的控制 -
webpack——devtool
里的7
種SourceMap
模式
我們先來看看文檔對這7
種模式的解釋:
模式 | 解釋 |
---|---|
eval | 每個module會封裝到 eval 里包裹起來執(zhí)行融痛,并且會在末尾追加注釋 //@ sourceURL. |
source-map | 生成一個SourceMap文件. |
hidden-source-map | 和 source-map 一樣壶笼,但不會在 bundle 末尾追加注釋. |
inline-source-map | 生成一個 DataUrl 形式的 SourceMap 文件. |
eval-source-map | 每個module會通過eval()來執(zhí)行,并且生成一個DataUrl形式的SourceMap |
cheap-source-map | 生成一個沒有列信息(column-mappings)的SourceMaps文件雁刷,不包含loader的 sourcemap(譬如 babel 的 sourcemap) |
cheap-module-source-map | 生成一個沒有列信息(column-mappings)的SourceMaps文件覆劈,同時 loader 的 sourcemap 也被簡化為只包含對應行的。 |
- 注1:webpack 不僅支持這 7 種沛励,
而且它們還是可以任意組合上面的eval责语、inline、hidden關鍵字目派,
就如文檔所說坤候,你可以設置 souremap 選項為:
cheap-module-inline-source-map。
- 注2:如果你的modules里面已經(jīng)包含了SourceMaps企蹭,
你需要用source-map-loader 來和合并生成一個新的 SourceMaps白筹。
還有很多其他的,需要時自行搜索學習即可
......