做者:lzg9527javascript
https://juejin.cn/post/6844904193589772301css
何爲插件(Plugin)?專一處理 webpack 在編譯過程當中的某個特定的任務的功能模塊,能夠稱爲插件。html
Plugin 是一個擴展器,它豐富了 webpack 自己,針對是 loader 結束後,webpack 打包的整個過程,它並不直接操做文件,而是基於事件機制工做,會監聽 webpack 打包過程當中的某些節點,執行普遍的任務。前端
Plugin 的特色vue
-
是一個獨立的模塊 -
模塊對外暴露一個 js 函數 -
函數的原型 (prototype)
上定義了一個注入compiler
對象的apply
方法apply
函數中須要有經過compiler
對象掛載的webpack
事件鉤子,鉤子的回調中能拿到當前編譯的compilation
對象,若是是異步編譯插件的話能夠拿到回調callback
-
完成自定義子編譯流程並處理 complition
對象的內部數據 -
若是異步編譯插件的話,數據處理完成後執行 callback
回調。
下面介紹 18 個經常使用的 webpack 插件。java
本文在gitthub作了收錄:node
https://github.com/Michael-lzg/my--article/blob/master/webpack/%E6%80%BB%E7%BB%9318%E4%B8%AAwebpack%E6%8F%92%E4%BB%B6.mdreact
HotModuleReplacementPlugin
模塊熱更新插件。Hot-Module-Replacement
的熱更新是依賴於 webpack-dev-server
,後者是在打包文件改變時更新打包文件或者 reload 刷新整個頁面,HRM
是隻更新修改的部分。jquery
HotModuleReplacementPlugin
是webpack
模塊自帶的,因此引入webpack
後,在plugins
配置項中直接使用便可。webpack
const webpack = require('webpack')
plugins: [
new webpack.HotModuleReplacementPlugin(), // 熱更新插件
]
html-webpack-plugin
生成 html 文件。將 webpack 中entry
配置的相關入口 chunk
和 extract-text-webpack-plugin
抽取的 css 樣式 插入到該插件提供的template
或者templateContent
配置項指定的內容基礎上生成一個 html 文件,具體插入方式是將樣式link
插入到head
元素中,script
插入到head
或者body
中。
const HtmlWebpackPlugin = require('html-webpack-plugin')
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.join(__dirname, '/index.html'),
minify: {
// 壓縮HTML文件
removeComments: true, // 移除HTML中的註釋
collapseWhitespace: true, // 刪除空白符與換行符
minifyCSS: true, // 壓縮內聯css
},
inject: true,
}),
]
inject 有四個選項值
-
true:默認值, script
標籤位於html
文件的body
底部 -
body: script
標籤位於html
文件的body
底部(同 true) -
head: script
標籤位於head
標籤內 -
false:不插入生成的 js 文件,只是單純的生成一個 html
文件
多頁應用打包
有時,咱們的應用不必定是一個單頁應用,而是一個多頁應用,那麼如何使用 webpack 進行打包呢。
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: {
index: './src/index.js',
login: './src/login.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[hash:6].js',
},
//...
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html', //打包後的文件名
}),
new HtmlWebpackPlugin({
template: './public/login.html',
filename: 'login.html', //打包後的文件名
}),
],
}
若是須要配置多個 HtmlWebpackPlugin
,那麼 filename
字段不可缺省,不然默認生成的都是 index.html
。
可是有個問題,index.html
和 login.html
會發現,都同時引入了 index.f7d21a.js
和 login.f7d21a.js
,一般這不是咱們想要的,咱們但願 index.html
中只引入 index.f7d21a.js
,login.html
只引入 login.f7d21a.js
。
HtmlWebpackPlugin
提供了一個 chunks
的參數,能夠接受一個數組,配置此參數僅會將數組中指定的 js 引入到 html 文件中
module.exports = {
//...
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html', //打包後的文件名
chunks: ['index'],
}),
new HtmlWebpackPlugin({
template: './public/login.html',
filename: 'login.html', //打包後的文件名
chunks: ['login'],
}),
],
}
這樣執行 npm run build
,能夠看到 index.html
中僅引入了 index 的 js 文件,而 login.html
中也僅引入了 login 的 js 文件。
clean-webpack-plugin
clean-webpack-plugin
用於在打包前清理上一次項目生成的 bundle 文件,它會根據 output.path
自動清理文件夾;這個插件在生產環境用的頻率很是高,由於生產環境常常會經過 hash 生成不少 bundle 文件,若是不進行清理的話每次都會生成新的,致使文件夾很是龐大。
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, '/index.html'),
}),
new CleanWebpackPlugin(), // 所要清理的文件夾名稱
]
extract-text-webpack-plugin
將 css 成生文件,而非內聯 。該插件的主要是爲了抽離 css 樣式,防止將樣式打包在 js 中引發頁面樣式加載錯亂的現象
const ExtractTextPlugin = require('extract-text-webpack-plugin')
plugins: [
// 將css分離到/dist文件夾下的css文件夾中的index.css
new ExtractTextPlugin('css/index.css'),
]
mini-css-extract-plugin
將 CSS 提取爲獨立的文件的插件,對每一個包含 css 的 js 文件都會建立一個 CSS 文件,支持按需加載 css 和 sourceMap
。只能用在 webpack4 中,對比另外一個插件 extract-text-webpack-plugin 有如下特色:
-
異步加載 -
不重複編譯,性能更好 -
更容易使用 -
只針對 CSS
這個插件應該只用在生產環境配置,而且在 loaders
鏈中不使用 style-loader
, 並且這個插件暫時不支持 HMR
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
module: {
rules: [
{
test: /\.(le|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
},
},
'css-loader',
'postcss-loader',
'less-loader',
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css',
chunkFilename: 'css/[id].[contenthash:8].css',
}),
],
}
purifycss-webpack
有時候咱們 css 寫得多了或者重複了,這就形成了多餘的代碼,咱們但願在生產環境進行去除。
const path = require('path')
const PurifyCssWebpack = require('purifycss-webpack') // 引入PurifyCssWebpack插件
const glob = require('glob') // 引入glob模塊,用於掃描所有html文件中所引用的css
module.exports = merge(common, {
plugins: [
new PurifyCssWebpack({
paths: glob.sync(path.join(__dirname, 'src/*.html')),
}),
],
})
optimize-css-assets-webpack-plugin
咱們但願減少 css 打包後的體積,能夠用到 optimize-css-assets-webpack-plugin
。
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin") // 壓縮css代碼
optimization: {
minimizer: [
// 壓縮css
new OptimizeCSSAssetsPlugin({})
]
UglifyJsPlugin
uglifyJsPlugin
是 vue-cli
默認使用的壓縮代碼方式,用來對 js 文件進行壓縮,從而減少 js 文件的大小,加速 load 速度。它使用的是單線程壓縮代碼,打包時間較慢,因此能夠在開發環境將其關閉,生產環境部署時再把它打開。
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
plugins: [
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false
}
},
sourceMap: true, //是否啓用文件緩存
parallel: true //使用多進程並行運行來提升構建速度
})
ParallelUglifyPlugin
開啓多個子進程,把對多個文件壓縮的工做分別給多個子進程去完成,每一個子進程其實仍是經過 UglifyJS
去壓縮代碼,可是變成了並行執行。
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin')
plugins: [
new ParallelUglifyPlugin({
//cacheDir 用於配置緩存存放的目錄路徑。
cacheDir: '.cache/',
sourceMap: true,
uglifyJS: {
output: {
comments: false,
},
compress: {
warnings: false,
},
},
}),
]
terser-webpack-plugin
Webpack4.0 默認是使用 terser-webpack-plugin
這個壓縮插件,在此以前是使用 uglifyjs-webpack-plugin
,二者的區別是後者對 ES6 的壓縮不是很好,同時咱們能夠開啓 parallel
參數,使用多進程壓縮,加快壓縮。
const TerserPlugin = require('terser-webpack-plugin') // 壓縮js代碼
optimization: {
minimizer: [
new TerserPlugin({
parallel: 4, // 開啓幾個進程來處理壓縮,默認是 os.cpus().length - 1
cache: true, // 是否緩存
sourceMap: false,
}),
]
}
NoErrorsPlugin
報錯但不退出 webpack 進程。編譯出現錯誤時,使用 NoEmitOnErrorsPlugin
來跳過輸出階段。這樣能夠確保輸出資源不會包含錯誤。
plugins: [new webpack.NoEmitOnErrorsPlugin()]
compression-webpack-plugin
全部現代瀏覽器都支持 gzip
壓縮,啓用 gzip
壓縮可大幅縮減傳輸資源大小,從而縮短資源下載時間,減小首次白屏時間,提高用戶體驗。
gzip 對基於文本格式文件的壓縮效果最好(如:CSS、JavaScript 和 HTML),在壓縮較大文件時每每可實現高達 70-90% 的壓縮率,對已經壓縮過的資源(如:圖片)進行 gzip 壓縮處理,效果很很差。
const CompressionPlugin = require('compression-webpack-plugin')
plugins: [
new CompressionPlugin({
// gzip壓縮配置
test: /\.js$|\.html$|\.css/, // 匹配文件名
threshold: 10240, // 對超過10kb的數據進行壓縮
deleteOriginalAssets: false, // 是否刪除原文件
}),
]
固然,這個方法還須要後端配置支持。
DefinePlugin
咱們能夠經過 DefinePlugin
能夠定義一些全局的變量,咱們能夠在模塊當中直接使用這些變量,無需做任何聲明,DefinePlugin
是 webpack
自帶的插件。
plugins: [
new webpack.DefinePlugin({
DESCRIPTION: 'This Is The Test Text.',
}),
]
// 直接引用
console.log(DESCRIPTION)
ProvidePlugin
自動加載模塊。任什麼時候候,當 identifier
被看成未賦值的變量時, module 就會自動被加載,而且 identifier
會被這個 module 輸出的內容所賦值。這是 webpack 自帶的插件。
module.exports = {
resolve: {
alias: {
jquery: './lib/jquery',
},
},
plugins: [
//提供全局的變量,在模塊中使用無需用require引入
new webpack.ProvidePlugin({
$: 'jquery',
React: 'react',
}),
],
}
DLLPlugin
這是在一個額外的獨立的 webpack 設置中建立一個只有 dll 的 bundle(dll-only-bundle)
。這個插件會生成一個名爲 manifest.json
的文件,這個文件是用來讓 DLLReferencePlugin
映射到相關的依賴上去的。
使用步驟以下
一、在 build 下建立 webpack.dll.config.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
entry: {
vendor: [
'vue-router',
'vuex',
'vue/dist/vue.common.js',
'vue/dist/vue.js',
'vue-loader/lib/component-normalizer.js',
'vue',
'axios',
'echarts',
],
},
output: {
path: path.resolve('./dist'),
filename: '[name].dll.js',
library: '[name]_library',
},
plugins: [
new webpack.DllPlugin({
path: path.resolve('./dist', '[name]-manifest.json'),
name: '[name]_library',
}),
// 建議加上代碼壓縮插件,不然dll包會比較大。
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
},
}),
],
}
二、在 webpack.prod.conf.js
的 plugin 後面加入配置
new webpack.DllReferencePlugin({
manifest: require('../dist/vendor-manifest.json'),
})
三、package.json
文件中添加快捷命令(build:dll)
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"lint": "eslint --ext .js,.vue src",
"build": "node build/build.js",
"build:dll": "webpack --config build/webpack.dll.conf.js"
}
生產環境打包的時候先npm run build:dll
命令會在打包目錄下生成 vendor-manifest.json
文件與 vendor.dll.js 文件。而後npm run build
生產其餘文件。
四、根目錄下的入口 index.html
加入引用
<script type="text/javascript" src="./vendor.dll.js"></script>
HappyPack
HappyPack
能讓 webpack 把任務分解給多個子進程去併發的執行,子進程處理完後再把結果發送給主進程。要注意的是 HappyPack
對 file-loader
、url-loader
支持的不友好,因此不建議對該 loader 使用。
一、HappyPack 插件安裝
npm i -D happypack
二、webpack.base.conf.js
文件對 module.rules 進行配置
module: {
rules: [
{
test: /\.js$/,
use: ['happypack/loader?id=babel'],
include: [resolve('src'), resolve('test')],
exclude: path.resolve(__dirname, 'node_modules'),
},
{
test: /\.vue$/,
use: ['happypack/loader?id=vue'],
},
]
}
三、在生產環境 webpack.prod.conf.js
文件進行配置
const HappyPack = require('happypack')
// 構造出共享進程池,在進程池中包含5個子進程
const HappyPackThreadPool = HappyPack.ThreadPool({ size: 5 })
plugins: [
new HappyPack({
// 用惟一的標識符id,來表明當前的HappyPack是用來處理一類特定的文件
id: 'babel',
// 如何處理.js文件,用法和Loader配置中同樣
loaders: ['babel-loader?cacheDirectory'],
threadPool: HappyPackThreadPool,
}),
new HappyPack({
id: 'vue', // 用惟一的標識符id,來表明當前的HappyPack是用來處理一類特定的文件
loaders: [
{
loader: 'vue-loader',
options: vueLoaderConfig,
},
],
threadPool: HappyPackThreadPool,
}),
]
注意,當項目較小時,多線程打包反而會使打包速度變慢。
copy-webpack-plugin
咱們在 public/index.html
中引入了靜態資源,可是打包的時候 webpack 並不會幫咱們拷貝到 dist 目錄,所以 copy-webpack-plugin
就能夠很好地幫我作拷貝的工做了。
const CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = {
plugins: [
new CopyWebpackPlugin({
patterns: [
{
from: 'public/js/*.js',
to: path.resolve(__dirname, 'dist', 'js'),
flatten: true,
},
],
}),
],
}
IgnorePlugin
這是 webpack 內置插件,它的做用是:忽略第三方包指定目錄,讓這些指定目錄不要被打包進去。
好比咱們要使用 moment
這個第三方依賴庫,該庫主要是對時間進行格式化,而且支持多個國家語言。雖然我設置了語言爲中文,可是在打包的時候,是會將全部語言都打包進去的。這樣就致使包很大,打包速度又慢。對此,咱們能夠用 IgnorePlugin
使得指定目錄被忽略,從而使得打包變快,文件變小。
const Webpack = require('webpack')
plugins: [
//moment這個庫中,若是引用了./locale/目錄的內容,就忽略掉,不會打包進去
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)
「1」"2"請各位帥哥美女多多支持帥編,回覆便可加入前端技術交流羣,回覆便可領取 500G 前端乾貨
以爲不錯,請點個在看呀
本文分享自微信公衆號 - 前端開發社區(pt1173179243)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。