开发环境
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: // }, 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