【面试】815- 面试官常问的 webpack 插件
Plugin
?何為插件(Plugin)?專注處理 webpack 在編譯過程中的某個特定的任務(wù)的功能模塊,可以稱為插件。plugin 是一個擴展器,它豐富了 webpack 本身,針對是 loader 結(jié)束后,webpack 打包的整個過程,它并不直接操作文件,而是基于事件機制工作,會監(jiān)聽 webpack 打包過程中的某些節(jié)點,執(zhí)行廣泛的任務(wù)。
?Plugin 的特點
是一個獨立的模塊
模塊對外暴露一個 js 函數(shù)
函數(shù)的原型 (prototype) 上定義了一個注入 compiler 對象的 apply方法 apply 函數(shù)中需要有通過 compiler 對象掛載的 webpack 事件鉤子,鉤子的回調(diào)中能拿到當前編譯的 compilation 對象,如果是異步編譯插件的話可以拿到回調(diào) callback
完成自定義子編譯流程并處理 complition 對象的內(nèi)部數(shù)據(jù)
如果異步編譯插件的話,數(shù)據(jù)處理完成后執(zhí)行 callback 回調(diào)。
下面介紹 18 個常用的 webpack 插件
HotModuleReplacementPlugin
模塊熱更新插件。Hot-Module-Replacement 的熱更新是依賴于 webpack-dev-server,后者是在打包文件改變時更新打包文件或者 reload 刷新整個頁面,HRM 是只更新修改的部分。
HotModuleReplacementPlugin是webpack模塊自帶的,所以引入webpack后,在plugins配置項中直接使用即可。
const?webpack?=?require('webpack')plugins:?[new?webpack.HotModuleReplacementPlugin(),?//?熱更新插件 ]html-webpack-plugin
生成 html 文件。將 webpack 中entry配置的相關(guān)入口 chunk 和 extract-text-webpack-plugin抽取的 css 樣式 插入到該插件提供的template或者templateContent配置項指定的內(nèi)容基礎(chǔ)上生成一個 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,?//?壓縮內(nèi)聯(lián)css},inject:?true,}), ]inject 有四個選項值
true:默認值,script 標簽位于 html 文件的 body 底部
body:script 標簽位于 html 文件的 body 底部(同 true)
head:script 標簽位于 head 標簽內(nèi)
false:不插入生成的 js 文件,只是單純的生成一個 html 文件
多頁應(yīng)用打包
有時,我們的應(yīng)用不一定是一個單頁應(yīng)用,而是一個多頁應(yīng)用,那么如何使用 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 會發(fā)現(xiàn),都同時引入了 index.f7d21a.js 和 login.f7d21a.js,通常這不是我們想要的,我們希望 index.html 中只引入 index.f7d21a.js,login.html 只引入 login.f7d21a.js。
HtmlWebpackPlugin 提供了一個 chunks 的參數(shù),可以接受一個數(shù)組,配置此參數(shù)僅會將數(shù)組中指定的 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'],}),], }這樣執(zhí)行 npm run build,可以看到 index.html 中僅引入了 index 的 js 文件,而 login.html 中也僅引入了 login 的 js 文件。
clean-webpack-plugin
clean-webpack-plugin 用于在打包前清理上一次項目生成的 bundle 文件,它會根據(jù) output.path 自動清理文件夾;這個插件在生產(chǎn)環(huán)境用的頻率非常高,因為生產(chǎn)環(huán)境經(jīng)常會通過 hash 生成很多 bundle 文件,如果不進行清理的話每次都會生成新的,導(dǎo)致文件夾非常龐大。
const?{?CleanWebpackPlugin?}?=?require('clean-webpack-plugin')plugins:?[new?HtmlWebpackPlugin({template:?path.join(__dirname,?'/index.html'),}),new?CleanWebpackPlugin(),?//?所要清理的文件夾名稱 ]extract-text-webpack-plugin
將 css 成生文件,而非內(nèi)聯(lián) 。該插件的主要是為了抽離 css 樣式,防止將樣式打包在 js 中引起頁面樣式加載錯亂的現(xiàn)象
const?ExtractTextPlugin?=?require('extract-text-webpack-plugin')plugins:?[//?將css分離到/dist文件夾下的css文件夾中的index.cssnew?ExtractTextPlugin('css/index.css'), ]mini-css-extract-plugin
將 CSS 提取為獨立的文件的插件,對每個包含 css 的 js 文件都會創(chuàng)建一個 CSS 文件,支持按需加載 css 和 sourceMap。只能用在 webpack4 中,對比另一個插件 extract-text-webpack-plugin 有以下特點:
異步加載
不重復(fù)編譯,性能更好
更容易使用
只針對 CSS
這個插件應(yīng)該只用在生產(chǎn)環(huán)境配置,并且在 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 寫得多了或者重復(fù)了,這就造成了多余的代碼,我們希望在生產(chǎn)環(huán)境進行去除。
const?path?=?require('path') const?PurifyCssWebpack?=?require('purifycss-webpack')?//?引入PurifyCssWebpack插件 const?glob?=?require('glob')?//?引入glob模塊,用于掃描全部html文件中所引用的cssmodule.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:?[//?壓縮cssnew?OptimizeCSSAssetsPlugin({})]UglifyJsPlugin
uglifyJsPlugin 是 vue-cli 默認使用的壓縮代碼方式,用來對 js 文件進行壓縮,從而減小 js 文件的大小,加速 load 速度。它使用的是單線程壓縮代碼,打包時間較慢,所以可以在開發(fā)環(huán)境將其關(guān)閉,生產(chǎn)環(huán)境部署時再把它打開。
const?UglifyJsPlugin?=?require('uglifyjs-webpack-plugin')plugins:?[new?UglifyJsPlugin({uglifyOptions:?{compress:?{warnings:?false}},sourceMap:?true,??//是否啟用文件緩存parallel:?true???//使用多進程并行運行來提高構(gòu)建速度})ParallelUglifyPlugin
開啟多個子進程,把對多個文件壓縮的工作分別給多個子進程去完成,每個子進程其實還是通過 UglifyJS 去壓縮代碼,但是變成了并行執(zhí)行。
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,兩者的區(qū)別是后者對 ES6 的壓縮不是很好,同時我們可以開啟 parallel 參數(shù),使用多進程壓縮,加快壓縮。
const?TerserPlugin?=?require('terser-webpack-plugin')?//?壓縮js代碼optimization:?{minimizer:?[new?TerserPlugin({parallel:?4,?//?開啟幾個進程來處理壓縮,默認是?os.cpus().length?-?1cache:?true,?//?是否緩存sourceMap:?false,}),] }NoErrorsPlugin
報錯但不退出 webpack 進程。編譯出現(xiàn)錯誤時,使用 NoEmitOnErrorsPlugin 來跳過輸出階段。這樣可以確保輸出資源不會包含錯誤。
plugins:?[new?webpack.NoEmitOnErrorsPlugin()]compression-webpack-plugin
所有現(xiàn)代瀏覽器都支持 gzip 壓縮,啟用 gzip 壓縮可大幅縮減傳輸資源大小,從而縮短資源下載時間,減少首次白屏時間,提升用戶體驗。
gzip 對基于文本格式文件的壓縮效果最好(如:CSS、JavaScript 和 HTML),在壓縮較大文件時往往可實現(xiàn)高達 70-90% 的壓縮率,對已經(jīng)壓縮過的資源(如:圖片)進行 gzip 壓縮處理,效果很不好。
const?CompressionPlugin?=?require('compression-webpack-plugin')plugins:?[new?CompressionPlugin({//?gzip壓縮配置test:?/\.js$|\.html$|\.css/,?//?匹配文件名threshold:?10240,?//?對超過10kb的數(shù)據(jù)進行壓縮deleteOriginalAssets:?false,?//?是否刪除原文件}), ]當然,這個方法還需要后端配置支持。
DefinePlugin
我們可以通過 DefinePlugin 可以定義一些全局的變量,我們可以在模塊當中直接使用這些變量,無需作任何聲明,DefinePlugin 是 webpack 自帶的插件。
plugins:?[new?webpack.DefinePlugin({DESCRIPTION:?'This?Is?The?Test?Text.',}), ]//?直接引用 console.log(DESCRIPTION)ProvidePlugin
自動加載模塊。任何時候,當 identifier 被當作未賦值的變量時, module 就會自動被加載,并且 identifier 會被這個 module 輸出的內(nèi)容所賦值。這是 webpack 自帶的插件。
module.exports?=?{resolve:?{alias:?{jquery:?'./lib/jquery',},},plugins:?[//提供全局的變量,在模塊中使用無需用require引入new?webpack.ProvidePlugin({$:?'jquery',React:?'react',}),], }DLLPlugin
這是在一個額外的獨立的 webpack 設(shè)置中創(chuàng)建一個只有 dll 的 bundle(dll-only-bundle)。這個插件會生成一個名為 manifest.json 的文件,這個文件是用來讓 DLLReferencePlugin 映射到相關(guān)的依賴上去的。
「使用步驟如下」
1、在 build 下創(chuàng)建 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,},}),], }2、在 webpack.prod.conf.js 的 plugin 后面加入配置
new?webpack.DllReferencePlugin({manifest:?require('../dist/vendor-manifest.json'), })3、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"}生產(chǎn)環(huán)境打包的時候先npm run build:dll命令會在打包目錄下生成 vendor-manifest.json 文件與 vendor.dll.js 文件。然后npm run build生產(chǎn)其他文件。
4、根目錄下的入口 index.html 加入引用
<script?type="text/javascript"?src="./vendor.dll.js"></script>HappyPack
HappyPack 能讓 webpack 把任務(wù)分解給多個子進程去并發(fā)的執(zhí)行,子進程處理完后再把結(jié)果發(fā)送給主進程。要注意的是 HappyPack 對 file-loader、url-loader 支持的不友好,所以不建議對該 loader 使用。
1、HappyPack 插件安裝
npm?i?-D?happypack2、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'],},] }3、在生產(chǎn)環(huán)境 webpack.prod.conf.js 文件進行配置
const?HappyPack?=?require('happypack') //?構(gòu)造出共享進程池,在進程池中包含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 中引入了靜態(tài)資源,但是打包的時候 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 內(nèi)置插件,它的作用是:忽略第三方包指定目錄,讓這些指定目錄不要被打包進去。
比如我們要使用 moment 這個第三方依賴庫,該庫主要是對時間進行格式化,并且支持多個國家語言。雖然我設(shè)置了語言為中文,但是在打包的時候,是會將所有語言都打包進去的。這樣就導(dǎo)致包很大,打包速度又慢。對此,我們可以用 IgnorePlugin 使得指定目錄被忽略,從而使得打包變快,文件變小。
const?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)前端學習筆記????
?最近花了點時間把筆記整理到語雀上了,方便同學們閱讀:公眾號回復(fù)筆記或者簡歷
?
轉(zhuǎn)載自:https://juejin.cn/post/6844904193589772301
1. JavaScript 重溫系列(22篇全)
2. ECMAScript 重溫系列(10篇全)
3. JavaScript設(shè)計模式 重溫系列(9篇全)
4.?正則 / 框架 / 算法等 重溫系列(16篇全)
5.?Webpack4 入門(上)||?Webpack4 入門(下)
6.?MobX 入門(上)?||??MobX 入門(下)
7. 80+篇原創(chuàng)系列匯總
回復(fù)“加群”與大佬們一起交流學習~
點擊“閱讀原文”查看 100+ 篇原創(chuàng)文章
總結(jié)
以上是生活随笔為你收集整理的【面试】815- 面试官常问的 webpack 插件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: display、visibility和o
- 下一篇: Httpservletrequest获取