webpack 是个很强大的构建工具,其丰富灵活的配置决定了使用也不简单。在面试中经常能遇到 webpack 相关的问题,如果平常只是使用脚手架如 vue-cli 而没有好好深入学习研究 webpack 的话,估计答不上什么。我相信,如果没有深入了解,部分面试官也问不出什么。可能也就变成了两个人侃侃如何配置出入口,常见的 loader,plugin 有哪些。
作为一名多年油条前端,一直没有正视 webpack 相关知识,面对 webpack 相关的面试题更是一问三不知。这次准备好好学习研究 webpack相关内容,并且将学习内容记录成 webpack 系列,希望可以让不了解 webpack 的小白能对其有所掌握。
常用的webpack插件
前面我们简单介绍了如何开发一个 webpack 插件,现在我们来看看在日常开发中有哪些常用的插件
1、HtmlWebpackPlugin
作用:根据模板文件自动生成 html 文件,并且将输出文件JS自动插入到 html 中,免去了需要手动更新版本号的烦恼。
const HtmlWebpackPlugin = require('html-webpack-plugin')
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html'
})
2、CleanWebpackPlugin
作用:用于清除打包的输出文件夹,试想如果每次打包出的文件都带有不同版本号,不及时清除文件夹,那么是不是会越来越大。本插件可以帮助我们自动清除,避免手动操作。
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
new CleanWebpackPlugin()
3、CopyWebpackPlugin
作用:将文件从某一目录复制到另一目录,可以用于 public 下的静态文件,比如和 html 同级的 JS 文件,无需参与编译但是需要输出到 dist 目录
const CopyWebpackPlugin = require('copy-webpack-plugin')
new CopyWebpackPlugin([
{ from: 'public/*.js', flatten: true },
])
4、webpack.DefinePlugin
作用:定义某些变量的值,在打包时用变量值替代变量
new webpack.DefinePlugin({
ISPRO: true
})
在JS中
if (ISPRO) {
console.log(true);
}
打包后将被替换为
if (true) {
console.log(true);
}
5、MiniCssExtractPlugin
作用:抽离 css 到独立的文件中,否则将会以内嵌的方式嵌在 html 中
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
new MiniCssExtractPlugin({
filename: '[name].css'
})
6、PurgeCSSPlugin
作用:删除没有引用到的选择器及其样式,需要配置判断引用文件,如 html,js。起到 css tree-shaking 的效果。需要注意的是,不会删除重复的选择器样式,这个属于压缩的任务。
const glob = require('glob-all');
const PurgeCSSPlugin = require('purgecss-webpack-plugin')
new PurgeCSSPlugin({
paths: glob.sync([path.resolve(__dirname, 'public/*.html'),
path.resolve(__dirname, '*.js')], { nodir: true }),
})
7、webpack.ProvidePlugin
作用:配置全局模块,避免多次引入的麻烦
new webpack.ProvidePlugin({
_: 'lodash'
})
在任意 JS 中可以使用 _ 而无需再次引入
console.log(_)
8、BundleAnalyzerPlugin
作用:文件分析插件,可以用于打包后资源的依赖及大小分析
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
new BundleAnalyzerPlugin({
generateStatsFile: true
})
9、ImageminPlugin
作用:压缩图片
const ImageminPlugin = require('imagemin-webpack-plugin').default
new ImageminPlugin({
pngquant: {
quality: '95-100'
}
})
PS: 由于该插件安装依赖其它文件的下载,可能会导致下载不了的情况,可以尝试切换为 cnpm 下载,以及尝试不同版本的下载情况。
10、CompressionPlugin
作用:启用传输压缩,比如将资源压缩为 GZIP 格式。需要服务端进行配合。
const CompressionPlugin = require("compression-webpack-plugin");
new CompressionPlugin({
// gzip压缩配置
test: /\.js$|\.html$|\.css/, // 匹配文件名
threshold: 10240, // 对超过10kb的数据进行压缩
deleteOriginalAssets: false, // 是否删除原文件
})
11、webpack.NoEmitOnErrorsPlugin
作用:遇到编译报错不输出。比如我们启用热加载开发时,改错资源引用将导致页面实时报错,配置该插件可以让遇到错误的编译不再输出资源文件,页面也不会更新报错。打包时也是如此,遇到错误将跳过输出。
new webpack.NoEmitOnErrorsPlugin()
12、OptimizeCssAssetsPlugin
作用:压缩css,会去除重复的类名样式
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g
})
13、UglifyJsPlugin
作用:压缩JS
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
new UglifyJsPlugin()
14、webpack.HotModuleReplacementPlugin
作用:热加载插件,配合热加载设置,提高开发效率
new webpack.HotModuleReplacementPlugin()
15、TerserPlugin
作用:压缩JS,和 UglifyJsPlugin 插件相比,能更好的处理 ES6 以上语法
const TerserPlugin = require('terser-webpack-plugin');
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true
}),
]
}
16、optimization.splitChunks
作用:提取多入口的公共文件,避免重复打包。或者提取某一模块文件(如node_modules),配合页面缓存来提高页面加载速度
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /node_modules/,
name: 'vendor',
minChunks: 1,
}
}
}
}
后话
其实每个插件都有其丰富的配置选项,在这里我只是简单的罗列了下其主要功能及极简配置。如果想要深入学习理解的话还是得往每个插件的 npm 主页进行查看,学习其配置文档。在配置的过程中我也遇到不同的坑,主要是版本问题,所以在这边贴出我的配置版本及代码,遇到问题的可以看看。
webpack.config.js
const path = require('path');
const glob = require('glob-all');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const PurgeCSSPlugin = require('purgecss-webpack-plugin')
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const CompressionPlugin = require("compression-webpack-plugin");
const TerserPlugin = require('terser-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const ImageminPlugin = require('imagemin-webpack-plugin').default
module.exports = {
mode: 'none',
entry: './index.js',
output: {
filename: '[name]-[chunkhash:6].js',
path: path.resolve(__dirname, 'dist'),
publicPath: './'
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader'
]
},
{
test: /\.css$/,
use: [{
loader: MiniCssExtractPlugin.loader,
options: {
esModule: false
}
}, 'css-loader']
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 1024
}
}]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html'
}),
new CleanWebpackPlugin(),
new webpack.DefinePlugin({
ISPRO: true
}),
new CopyWebpackPlugin([
{ from: 'public/*.js', flatten: true },
]),
new MiniCssExtractPlugin({
filename: '[name].css'
}),
new PurgeCSSPlugin({
paths: glob.sync([path.resolve(__dirname, 'public/*.html'),
path.resolve(__dirname, '*.js')], { nodir: true }),
}),
new webpack.ProvidePlugin({
_: 'lodash'
}),
new BundleAnalyzerPlugin({
generateStatsFile: true
}),
// cnpm i imagemin-webpack-plugin@1.5.0-beta.1 -D
new ImageminPlugin({
pngquant: {
quality: '95-100'
}
}),
new CompressionPlugin({
// gzip压缩配置
test: /\.js$|\.html$|\.css/, // 匹配文件名
threshold: 10240, // 对超过10kb的数据进行压缩
deleteOriginalAssets: false, // 是否删除原文件
}),
new webpack.NoEmitOnErrorsPlugin(),
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g
}),
// new webpack.HotModuleReplacementPlugin()
// new UglifyJsPlugin()
],
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /node_modules/,
name: 'vendor',
minChunks: 1,
}
}
},
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true
}),
]
}
}
package.json
{
"name": "webpack-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"lodash": "^4.17.20"
},
"devDependencies": {
"clean-webpack-plugin": "^3.0.0",
"compression-webpack-plugin": "^6.0.0",
"copy-webpack-plugin": "^5.1.2",
"css-loader": "^5.0.1",
"file-loader": "^6.2.0",
"glob-all": "^3.2.1",
"html-webpack-plugin": "^4.3.0",
"imagemin-webpack-plugin": "^1.5.0-beta.1",
"mini-css-extract-plugin": "^1.3.3",
"npm": "^6.14.9",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"purgecss-webpack-plugin": "^3.0.0",
"style-loader": "^2.0.0",
"terser-webpack-plugin": "^4.0.0",
"uglifyjs-webpack-plugin": "^2.2.0",
"url-loader": "^4.1.1",
"webpack": "^4.44.2",
"webpack-bundle-analyzer": "^4.2.0",
"webpack-cli": "^3.3.12"
},
"author": "",
"license": "ISC"
}
参考
欢迎到前端菜鸟群一起学习交流~516913974