一文彻底读懂 webpack 常用配置
- 2022-11-02 浙江
本文字数:6347 字
阅读完需:约 21 分钟
开发环境
const webpack = require("webpack");const path = require('path')module.exports = { // entry: { // a: './src/0706/a.js', // c: './src/0706/c.js', // }, entry: "./src/0707/reactDemo.js", output: { filename: '[name]_dist.js', path: path.resolve(__dirname, 'dist3'), }, mode: 'development', devtool: 'source-map', module: { rules: [ { test:/.js$/, use: 'babel-loader', }, { test: /.css$/, use: [ 'style-loader', 'css-loader' ] }, { test:/.less$/, use: [ 'style-loader', 'css-loader', 'less-loader' ] }, { test: /.(png|jpg|gif|jpeg)$/, use: 'file-loader' }, { test: /.(png|jpg|jpeg|gif)$/, use: { loader: 'url-loader', options: { limit: 10240 * 10 } } }, { test: /.(woff|woff2|eot|ttf|otf)$/, use: 'file-loader' } ], }, // plugins: [ // new webpack.HotModuleReplacementPlugin() // ], // 在使用devServer的时候,如果hot为true的话,会自动帮我们添加HotModuleReplacementPlugin // 如果使用自己实现的服务器,就需要自己添加 devServer: { contentBase: './dist3', hot: true }}
生产环境
const webpack = require("webpack");const MiniCssExtractPlugin = require('mini-css-extract-plugin');// minicssextractplugin 推荐使用cssminimizerwebpackplugin来压缩cssconst CssMinimizerPlugin = require('css-minimizer-webpack-plugin');// 根据模板生产html,并插入相应的chunk,同时也可以压缩htmlconst HtmlWebpackPlugin = require('html-webpack-plugin');// 清除构建产物的插件,注意这里的引入方式const { CleanWebpackPlugin } = require('clean-webpack-plugin');const path = require('path');module.exports = { // entry: { // a: './src/0706/a.js', // c: './src/0706/c.js', // }, entry: "./src/0707/reactDemo.js", output: { // 文件指纹 chunkhash chunk改变就会重新生成 // hash 整个项目有文件改变就会重新生成 // contenthash 文件内容改变才会重新生成 filename: '[name]_[chunkhash:8].js', path: path.resolve(__dirname, 'dist3'), }, mode: 'production', optimization: { minimizer: [ // 压缩CSS new CssMinimizerPlugin(), // webpack5内置了terser-plugin,但是上面的插件会覆盖掉默认的terser-plugin,所以通过下面的一行来将默认的插件加回去 '...' ] }, module: { rules: [ { test:/.js$/, use: 'babel-loader', }, { test: /.css$/, use: [ MiniCssExtractPlugin.loader, 'css-loader' ] }, { test:/.less$/, use: [ // 使用miniCssExtractPlugin提取css后,这里需要替换成它的loader MiniCssExtractPlugin.loader, 'css-loader', 'less-loader' ] }, { test: /.(png|jpg|gif|jpeg)$/, use: { loader: 'file-loader', options: { name: '[name]_[hash:8].[ext]' } } }, { test: /.(png|jpg|jpeg|gif)$/, use: { loader: 'url-loader', options: { limit: 10240 * 10 } } }, { test: /.(woff|woff2|eot|ttf|otf)$/, use: 'file-loader' } ], }, plugins: [ new MiniCssExtractPlugin({ // 使用contenthash 这样如果只改变了js的话css也无需重新生成 filename: '[name]_[contenthash:8].css' }), new HtmlWebpackPlugin({ // 模板所在路径 template: path.resolve(__dirname, 'src/index.html'), // 生成的html的名字 filename: 'index2.html', // 用到了哪个chunk // chunks: ['a'] // 压缩选项 minify: { html5: true, collapseWhitespace: true, preserveLineBreaks: false, minifyCSS: true, minifyJS: true, removeComments: true } }) ]}
自动添加 CSS 前缀
使用 postcss-loader + autoprefixer
添加 postcss.config.js 新版本直接在 webpack 配置文件里添加会报错,所以需要写到一个独立的配置文件里
module.exports = { plugins: [ require('autoprefixer')({ overrideBrowserslist: ['last 2 version', '>1%', 'ios 7'] }) ]}
添加 loader
{ test: /.css$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader' // 这里为新加的loader ]},
移动端适配 css px 自动转 rem
使用手淘 lib-flexible 动态计算 font-size
参考 webpack 视频讲解:进入学习
// 将lib-flexible静态内联到html上,因为要最先执行计算// 在头部加入如下代码// 使用了raw-loader,相当于在对应的位置是插入字符串// 需注意raw-loader新老版本引入的差异<script type="text/javascript"<%=require('raw-loader!babel-loader!./node_modules/lib-flexible/flexible.js')%></script>
使用 px2rem-loader 将 px 转成 rem
{ test: /.less$/ use: [ 'style-loader', 'css-loader', 'less-loader', { loader: 'px2rem-loader', options: { // 以设计稿宽度750px为例,1rem = 75px remUnit: 75, // 转换后的小数点后保留位数 remPrecision: 8, } } ]}
代码里面直接按设计稿一样写 px
// 下面的px最后会被转成em,如果有些特殊的地方不想转,可写成大写PX.box { width: 100px; height: 100px; // 写成大写则不会被转换 border: 1PX;}
代码分割
利用 splitChunks plugin 将公共代码抽离
optimization: { splitChunks: { cacheGroups: { vendors: { chunks: 'all', name: 'vendors', // 将react和react-dom提取出一个包 test: /(react|react-dom)/ }, common: { name: 'common', chunks: 'all', minSize: 0, // 被引用两次以上的提取出一个包 minChunks: 2 } } }}
动态 import 懒加载
通过 ES6 的动态 import + babel 插件 @babel/plugin-syntax-dynamic-import
//babel配置里增加plugins: [ '@babel/plugin-syntax-dynamic-import']// 代码里按需引入import('xxx').then(res => res.default);
webpack 结合 eslint
以 react 为例,用到几个插件 eslint eslint-plugin-import eslint-plugin-react eslint-plugin-jsx-a11y
安装解析器 babel-eslint
用 airbnb 的规则,需安装 eslint-config-airbnb
安装 eslint-loader
增加 eslint 配置 eslintrc.js
module.exports = { // 使用babel-eslint作为解析器 "parser": "babel-eslint", // 继承airbnb的规则 "extends": ["airbnb"], // 指定环境,这样使用全局变量的时候不会报错 "env": { "browser": true, "node": true }, // 自定义规则覆盖默认规则 "rules": { // 使用4个空格缩进,否则error "indent": ["error", 4] }}
webpack 打包库
代码写好后,webpack 配置如下
const path = require('path');module.exports = { // 同时提供未压缩和压缩的版本 entry: { 'mylibrary': './src/entry.js', 'mylibrary.min': './src/entry.js' }, output: { path: path.resolve(__dirname, 'lib'), // mylibrary.js mylibrary.min.js filename: '[name].js', // 对外暴露的库的名称 library: 'mylibrary', // 支持cjs, ejs, script脚本等引入方式 libraryTarget: 'umd', // 不加这个的话,使用的时候可能需要mylibrary.default libraryExport: 'default' }}
添加 terser-webpack-plugin 进行压缩
const TerserPlugin = require('terser-webpack-plugin');
optimization: { minimize: true, minimizer: [ new TerserPlugin({ // 只对min版本压缩 test: /.min.js/ }) ]}
package.json 指定入口文件
"main": "index.js"
index.js 里面做环境判断
if(process.env.NODE_EVN === 'production') { module.exports = require('./lib/mylibrary.min.js');} else { module.exports = require('./lib/mulibrary.js');}
主动捕获异常
通过插件主动捕获异常
plugins: [ function() { this.hooks.done.tap('done', (stats) => { if(stats.compilation && stats.compilation.errors.length > 1) { console.log('error') } }) }]
构建优化
速度优化:
speed-measure-webpack-plugin 分析构建速度
const SpeedMeasureWebpackPlugin = require('speed-measure-webpack-plugin');const spm = new SpeedMeasureWebpackPlugin();module.exports = spm.wrap({...});
thread-loader 开启多进程,放在需要的 loader 上面
module: { rules: [ { test: /.js$/ use: [ { loader: 'thread-loader', options: { workers: 3 } } ] } ]}
include exclude 缩小构建目标
resolve 减少文件搜索范围
modules.exports = { ... resolve: { // 指定node_modules的路径,减少模块搜索层级 modules: [path.resolve(__dirname, 'node_modules')], // import react的时候直接从指定的路径去找 alias: { react: path.resolve(__dirname, './node_modules/react/dist/react.min.js') }, // import xx from 'a'的时候,只找.js后缀的 // 高频文件后缀名放前面 extensions: ['.js'], // 指定入口,避免不必要的分析 mainFields: ['main'] }}
开启 babel-loader 缓存
// 仅需加个url参数module: { rules: [ { test: /.js$/, use: ['babel-loader?cacheDirectory=true' } ]}
terser-webpack-plugin 开启缓存
// webpack5之后不再用这种方式new TerserWebpackPlugin({ cache: true})
cache-loader 缓存
hard-source-webpack-plugin 缓存,减少二次构建时间
plugins: [new HardSourceWebpackPlugin()]
terser-webpack-plugin 默认开启了 JS 多进程压缩
optimization: { minimizer: [ new TerserWebpackPlugin({ // 指定进程数量 parallel: 4 }) ]}
使用 DLLPlugin 进行分包
先构建出单独的包
// 单独的配置文件用于生成包module.exports = { entry: { // 将react react-dom抽离出单独的包 library: ['react', 'react-dom'] }, output: { filename: '[name].dll.js', path: path.resolve(__dirname, 'dist3/lib') library: '[name]' }, plugins: [ // 使用DLLPlugin抽离,生成manifest new webpack.DllPlugin({ name: '[name]_2', path: path.resolve(__dirname, 'dist3/lib/[name].json'), }), // new CleanWebpackPlugin(), ]}
再通过 manifest 关联抽离的包
// webpack.prod.config.jsnew webpack.DllReferencePlugin({ manifest: require('./dist3/lib/library.json')})
最后将抽离的包插入 html 模板中
noParse 对完全不需要解析的库进行忽略 (不去解析但仍会打包到 bundle 中,注意被忽略掉的文件里不应该包含 import、require、define 等模块化语句)
体积优化
webpack-bundle-analyzer 分析体积
plugins: [ new WebpackBundleAnalyzer()]
图片压缩
使用 image-webpack-loader
rules: [{ test: /\.(gif|png|jpe?g|svg)$/i, use: [ 'file-loader', { loader: 'image-webpack-loader', options: { mozjpeg: { progressive: true, }, // optipng.enabled: false will disable optipng optipng: { enabled: false, }, pngquant: { quality: [0.65, 0.90], speed: 4 }, gifsicle: { interlaced: false, }, // the webp option will enable WEBP webp: { quality: 75 } } }, ],}]
对 CSS 进行 tree shaking
使用 purgecss-webpack-plugin,要配合 mini-css-extract-plugin 一起使用
const purgecssPath = path.join(__dirname, 'src');const glob = require('glob');new PurgecssPlugin({ paths: glob.sync(`${purgecssPath}/**/*`, { nodir: true }),}),
动态 polyfill
根据浏览器的 user agent 动态下发 polyfill
<script src="https://polyfill.io/v3/polyfill.min.js"></script>
或者可以自建 CDN
Geek_02d948
还未添加个人签名 2022-09-08 加入
还未添加个人简介









评论