webpack5 入门学习笔记(四)性能优化

本文详细介绍Webpack5的性能优化技巧,包括开发环境与生产环境的优化策略,如HMR、source-map、缓存机制、treeshaking、代码分割、多进程打包等,帮助开发者提升构建效率。

写在前面

webpack优化配置

开发环境性能优化

  • 优化打包构建速度
    • HMR 模块热替换
  • 优化代码调试
    • source-map

生产环境性能优化

  • 优化打包构建速度
    • oneOf
    • babel 缓存
    • 多进程打包 同一时间干多件事,提升打包速度,进程开启和交流也有开销,消耗时间比较长的任务,使用 thread-loader 对 babel-loader 进行优化
    • external 声明不用打包的库,再用 cdn 引进来
  • 优化代码运行的性能
    • 缓存(hash-chunkhash-contenthash)
    • tree shaking (es6 模块,production)(package.json 中 sideEffects:[‘xxx’])
    • code split {单页面,单入口通过 import 引入的一定会被分割成单独的打包,optimization}
    • 懒加载/预加载
      • 代码分割是异步执行,使用懒加载
      • 预加载等其他资源加载完再加载,预加载兼容性问题大用之慎重
    • pwa 离线可访问,serviceworker 和 cache,使网络离线可访问,兼容性问题严重

HMR

定义
  • hot module replacement 热模块替换 / 模块热替换
作用
  • 一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块),极大提升构建速度
使用方法
  1. devServer 中加上 hot:true
    	devServer: {
    		hot:true
    	}
    
  2. 样式文件:可以使用 HMR 功能 ,因为 style-loader 内部实现了,所以开发环境下用 style-loader ,但是生产环境下还是提取 css 为单独文件,就不能使用了
    	loader:'style-loader'
    
  3. html文件: 默认不能使用 HMR 功能,开启 HMR 同时会导致
    • 问题html 文件不能热更新了
    • 解决:修改 entry 入口,将 html 文件引入( html 文件只有一个,不用做 HMR 功能)
    	//入口文件
    	entry:['./src/js/index.js','./src/index.html'],
    
  4. js文件:默认不能使用 HMR 功能 -->需要修改 js 代码,添加支持 HMR 功能的代码
    • 注意HMR 功能对 js 的处理,只能处理非入口 js 文件的其他文件
    • index.js 文件中加入以下代码
    	if (module.hot) {
        //全局中寻找hot
        //一旦module.hot为true,说明开启了HMR功能。 -->让HMR功能代码生效
        module.hot.accept('./print.js', function () {
            //方法会监听print.js文件的变化,一旦发生变化,其他默认不会重新打包构建
            //会执行后面的回调函数
            print()
        })
    }
    
要点记录
  1. 当修改了 webpack 配置,新配置要想生效必须重启 webpack 服务
代码实现
	const { resolve } = require('path');
	
	const HtmlWebpackPlugin = require('html-webpack-plugin');
	
	module.exports = {
	  //入口文件
	  entry:['./src/js/index.js','./src/index.html'],
	  //出口
	  output: {
	    //输出的文件名
	    filename: 'js/bundle.js',
	    //输出的路径
	    path: resolve(__dirname, 'dist'),
	    clean:true //清理旧文件
	  },
	  module: {
	    rules: [
	      {
	        test: /\.css$/,
	        use: ['style-loader', 'css-loader']
	      },
	      {
	        test: /\.less$/,
	        use: ['style-loader', 'css-loader','less-loader']
	      },
	      {
	        //处理图片资源(样式中的图片资源,html中的是处理不了的)
	        test: /\.(jpg|png|gif)$/,
	        loader: 'url-loader', //通过es6module解析
	        options: {
	            limit: 8 * 1024,
	            name: '[name].[hash:10].[ext]',
	            //关闭es6模块化,开启commonjs模块化
	            esModule: false,
	            outputPath:'img'
	        }
	    },
	    {
	        //处理html中的img资源
	        test: /\.html$/,
	        loader: 'html-loader',
	        options: {
	            esModule: false
	        }
	        
	    },
	    {
	        //处理其他资源
	        exclude: /\.(html|js|css|less|jpg|png|gif)$/,
	        loader: 'file-loader',  //url-loader是基于file-loader封装的,多一些压缩功能,比如讲图片转成base64格式
	        options: {
	            name: '[name].[hash:10].[ext]',
	            outputPath:'media'
	        }
	    }
	    ]
	  },
	  plugins: [
	    new HtmlWebpackPlugin({
	      template: './src/index.html',
	      //inject: 'head',
	      scriptLoading: 'blocking',
	      title:'Hot Module Replacement'
	    }),
	  ],
	  mode: 'development',
	  target: 'web',
	  devServer: {
	    contentBase: './dist',
	    //启动gzip压缩
	    compress: true,
	    //端口号
	    port: 8888,
	    //首次运行自动打开浏览器
	    open: 'Chrome',
	    // 开启HMR功能
	    //当修改了webpack配置,新配置要想生效必须重启webpack服务
	    hot: true
	    
	  }
	};

source-map

定义
  • source-map: 一种 提供源代码到构建后代码映射 技术 (如果构建后代码出错了,通过映射关系可以追踪源代码错误)
作用
  • 一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块),极大提升构建速度
使用方法
  1. devtool:'source-map' 基本配置
    	devtool: 'source-map'  //生产环境选择
    	devtool: 'eval-source-map' //开发环境选择
    
  2. 几个可选参数:
    	[inline-|hidden|eval-][nosources-][cheap-[module-]]source-map
    
  3. 内联和外部
    • 外部生成了 map 文件
    • 内联在 bundle.js 文件中
    • 内联构建速度更快
  • source-map 外部
    • 错误代码的准确信息 和 源代码的错误位置
  • inline-source-map 内联
    • 只生成一个内联source-map
    • 错误代码的准确信息 和 源代码的错误位置
  • hidden-source-map 外部
    • 错误代码错误原因,但是没有错误位置
    • 不能追踪源代码错误,只能看到构建后代码的错误位置
  • eval-source-map 内联
    • 每个文件后面追加一个source-map 在eval函数中
    • 错误代码的准确信息 和 源代码的错误位置,多一个hash值
  • nosources-source-map 外部
    • 错误代码的准确信息,但是没有任何源代码信息
  • cheap-source-map 外部
    • 错误代码的准确信息 和 源代码的错误位置
    • 只能精确到行,不能精确到列
  • cheap-module-source-map 外部
    • 错误代码的准确信息 和 源代码的错误位置
    • module会将loader的source map加入
  • 开发环境:速度快,调试更友好
  • 速度快eval>inline>cheap>...
  • eval-cheap-source-map 第一
  • eval-source-map
  • 调试友好
  • source-map 第一
  • cheap-module-source-map
  • cheap-source-map
  • 又快又好 – > eval-source-map / eval-cheap-module-source-map

  • 生产环境:源代码要不要隐藏? 调试要不要更友好
  • 内联会让代码体积变大,所以在生产环境不用内联
  • 源代码隐藏
  • nosources-source-map 全部隐藏
  • hidden-source-map 只隐藏源代码,会提示构建后代码错误
  • – > 调试友好 source-map / 速度快 cheap-module-source-map
代码实现
	const { resolve } = require('path');

	const HtmlWebpackPlugin = require('html-webpack-plugin');
	
	module.exports = {
	  //入口文件
	  entry:['./src/js/index.js','./src/index.html'],
	  //出口
	  output: {
	    //输出的文件名
	    filename: 'js/bundle.js',
	    //输出的路径
	    path: resolve(__dirname, 'dist'),
	    clean:true //清理旧文件
	  },
	  module: {
	    rules: [
	      {
	        test: /\.css$/,
	        use: ['style-loader', 'css-loader']
	      },
	      {
	        test: /\.less$/,
	        use: ['style-loader', 'css-loader','less-loader']
	      },
	      {
	        //处理图片资源(样式中的图片资源,html中的是处理不了的)
	        test: /\.(jpg|png|gif)$/,
	        loader: 'url-loader', //通过es6module解析
	        options: {
	            limit: 8 * 1024,
	            name: '[name].[hash:10].[ext]',
	            //关闭es6模块化,开启commonjs模块化
	            esModule: false,
	            outputPath:'img'
	        }
	    },
	    {
	        //处理html中的img资源
	        test: /\.html$/,
	        loader: 'html-loader',
	        options: {
	            esModule: false
	        }
	        
	    },
	    {
	        //处理其他资源
	        exclude: /\.(html|js|css|less|jpg|png|gif)$/,
	        loader: 'file-loader',  //url-loader是基于file-loader封装的,多一些压缩功能,比如讲图片转成base64格式
	        options: {
	            name: '[name].[hash:10].[ext]',
	            outputPath:'media'
	        }
	    }
	    ]
	  },
	  plugins: [
	    new HtmlWebpackPlugin({
	      template: './src/index.html',
	      //inject: 'head',
	      scriptLoading: 'blocking'
	    }),
	  ],
	  mode: 'development',
	  target: 'web',
	  devServer: {
	    contentBase: './dist',
	    //启动gzip压缩
	    compress: true,
	    //端口号
	    port: 8888,
	    //首次运行自动打开浏览器
	    open: 'Chrome',
	    // 开启HMR功能
	    //当修改了webpack配置,新配置要想生效必须重启webpack服务
	    hot: true
	  },
	  //devtool: 'source-map'  //生产环境选择
	  devtool: 'eval-source-map' //开发环境选择
	};

oneOf

定义
  • 以下 loader 只会匹配一个
作用
  • 优化生产环境打包构建速度
使用方法
  1. 在众多 loader 外嵌套一层
    	 oneOf: [
    	 	{
                //css兼容性处理
                test: /\.css$/,
                use: [...commonCssloader],
            },
            //...
    	]
    
要点记录
  1. oneOf 里不能有两个配置处理同一种类型文件
代码实现
	/**
	 * oneOf:优化生产环境打包构建速度
	 */
	
	//绝对路径解析方法
	const { resolve } = require("path");
	
	//提取css成单独文件插件
	const MiniCssExtractPlugin = require('mini-css-extract-plugin')
	
	//最新压缩css插件
	const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
	
	//手动添加webpack内部js压缩器
	const TerserWebpackPlugin = require('terser-webpack-plugin');
	
	//对html文件处理
	const HtmlWebpackPlugin = require('html-webpack-plugin');
	
	//默认使用生产环境,定义nodejs环境变量:决定使用browserslist的哪个环境
	process.env.NODE_ENV = 'production'
	
	//复用loader
	const commonCssloader = [
	    MiniCssExtractPlugin.loader,//提取css为单独文件
	    'css-loader',
	    {//兼容性处理 还需要在package.json中定义browserslist
	        loader: 'postcss-loader',
	        options: {
	            postcssOptions: {
	                ident: 'postcss',
	                plugins: [
	                    'postcss-preset-env'
	                ]
	            }
	        }
	    }
	]
	
	module.exports = {
	    entry: './src/js/index.js',
	    output: {
	        filename: 'js/bundle.js',
	        path:resolve(__dirname,'dist'),
	        clean: true,
	        publicPath:'./'
	    },
	    //压缩css
	    optimization: {
	        minimize: true,
	        minimizer: [
	            new TerserWebpackPlugin(),
	            new CssMinimizerPlugin()
	        ]
	    },
	    module: {
	        rules: [
	            /**
	             *  正常来讲,一个文件只能被一个loader处理
	             *  当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序
	             *  在loader中设置enforce:'pre',最先执行
	             */
	            {
	                //优化生产环境打包构建速度
	                //以下loader只会匹配一个
	                //注意:这里不能有两个配置处理同一种类型文件
	                oneOf: [
	                    {
	                        //css兼容性处理
	                        test: /\.css$/,
	                        use: [...commonCssloader],
	                    },
	                    {
	                        //less兼容性处理
	                        test: /\.less$/,
	                        use: [...commonCssloader,
	                            //use中loader执行从下往上,必须把这个处理放在css-loader与less-loader之间
	                            'less-loader'//将less转成css文件
	                        ],
	                    },
	                    {
	                        //js兼容性处理
	                        test: /\.js$/,
	                        exclude: /node_modules/,
	                        loader:'babel-loader' //配置在.babelrc文件中
	                    },
	                    {
	                        //图片处理
	                        test: /\.(jpg|png|gif)$/,
	                        loader: 'url-loader',
	                        options: {
	                            limit: 8 * 1024,//对8kb以下的图片进行base64处理
	                            name: '[name].[hash:8].[ext]',//对处理后的图片重命名
	                            outputPath: 'img', //设置处理后的图片路径
	                            publicPath: './', //指定打包后的css图片的基础路径,
	                            esModule:false //关闭es6模块化
	                        }
	                    },
	                    {
	                        //处理html中的图片问题
	                        test: /\.html$/,
	                        loader: 'html-loader',
	                        options: {
	                            esModule:false
	                        }
	                    },
	                    // 打包iconfont字体图标,和打包图片类似
			            {
			                test:/\.ttf$/,
			                use: {
			                loader: 'file-loader',
			                options: {
			                    esModule: false, // 新版本中esModule默认为true,会导致文件的地址变为[object Module],因此这里设置为false
			                    name: '[name]_[hash:6].[ext]', // 输出的文件名为[原名称]_[哈希值].[原后缀]
			                    outputPath: 'fonts/',       // 文件存储路径(output.path + 值)(物理路径, 存储路径)
			                    publicPath:'../fonts' ,     // 负责输出目录, 即打包后的写在磁盘的位置
			                     // 输出解析文件的目录,url 相对于 HTML 页面(index.html所在文件夹的绝对路径 + 值)(文件引用路径就是看这个)
			                    // 如果output设置了publicPath, options也设置了publicPath,优先以options的publicPath为主
			                    // 是对页面引入资源的补充,比如img标签引入或者css引入等.
			                    // 千万不能设错,应该观察文件和HTML页面的存储地址位置,进行设置,否则引用时地址会错误,找不到文件
			                    // 一般只设置output的publicPath,方便统一管理
			                    limit: 1024        // 限制当文件小于1KB的时候,就将文件转为base64存储于js中,以减少http请求次数,当文件大于1KB,则打包文件到指定目录,避免js过大
			                }
			                }
			            },
	                    {
	                        //处理其他文件
	                        exclude: /\.(js|css|less|html|jpg|png|gif|ttf)$/,
	                        loader: 'file-loader',
	                        options: {
	                            name: '[name].[hash:8].[ext]',
	                            outputPath:'media'
	                        },
	                        // type: 'asset/resource',
	                        // generator: {
	                        //     filename: 'media/[name].[hash:6].[ext]'
	                        // }
	                    },
	                ]
	            }
	        ]
	    },
	    devtool: 'source-map',//错误追踪
	    plugins: [
	        //提取css为单独文件
	        new MiniCssExtractPlugin({
	            filename:'css/built.css'
	        }),
	        //对html文件处理
	        new HtmlWebpackPlugin({
	            template: './src/index.html',
	            scriptLoading: 'blocking',//去除script defer模式
	            //html压缩
	            mimify: {
	                //移除空格
	                collaspeWhitespace: true,
	                //移除注释
	                removeComments:true
	            }
	        })
	    ],
	    //mode为production,js就自动压缩了
	    mode:'production'
	}

缓存

作用
  • babel缓存
    • 让第二次打包构建速度更快
  • 文件缓存
    • 让代码上线运行缓存更好使用 上线代码性能优化
使用方法
  1. 开启 babel 缓存
    	 {
              //js兼容性处理
              test: /\.js$/,
              exclude: /node_modules/,
              loader: 'babel-loader', //配置在.babelrc文件中
              options: {
                  //开启babel缓存,第二次构建时会读取之前的缓存
                  //问题:当文件名没有发生变化的时候,同名文件都是走缓存。会导致修改内容与实际展示内容不一致。
                  cacheDirectory:true 
              }
          }
    
  2. 添加 contenthash
    	output: {
    	        filename: 'js/bundle.[contenthash:10].js',
    	        path:resolve(__dirname,'dist'),
    	        clean: true,
    	        publicPath:'./'
    	    },
        plugins: [
            //提取css为单独文件
            new MiniCssExtractPlugin({
                filename:'css/built.[contenthash:10].css'
            }),
        }
    
  3. 创建临时服务器 新建server.js文件 启动指令 node server.js
    	/**
    	 * 服务器代码
    	 * 启动指令 node server.js
    	 * 使用nodemon server.js 需要全局安装nodemon npm i nodemon -g
    	 */
    	const express = require('express')
    	const app = express();
    	
    	app.use(express.static('dist', { maxAge: 1000 * 3600 }));
    	
    	app.listen(3000);
    
    
  4. 打包之后,启动服务器,在浏览器中查看,network,刷新就能看到,后面是通过读取缓存内容显示的,速度也会更快
要点记录
  1. babel缓存
  • babel 处理后的资源缓存起来(哪里的 js 改变就更新哪里,其他 js 还是用之前缓存的资源),让第二次打包构建速度更快
  • 因为 js 文件最多 编译过程 类似 HMR 功能,但是生产环境不能用HMR功能
  • 所以在生产环境下 开启 babel缓存 ,第二次构建时,会读取之前的缓存
  • "cacheDirectory":true
  • 问题:当文件名没有发生变化的时候,同名文件都是走缓存。会导致修改内容与实际展示内容不一致。
  • 解决:使用 hash 命名,通过更换文件名来判断哪些文件需要更新
  1. 文件缓存
  • hash :每次 webpack 构建时会生成一个唯一的 hash
  • 问题:因为 jscss 同时使用一个 hash 值。如果重新打包,会导致所有的缓存失效。但是我可能是只改动了一个文件
  • chunkhash:根据 chunk 生成的 hash 值,如果打包来源于同一个 chunk ,那么 hash 值就一样
  • 问题:jscsshash 值还是一样的,因为 css 是在 js 中被引入的,所以同属于一个 chunk
  • contenthash:根据文件的内容生成 hash 值,不同文件的 hash 值一定不一样
代码实现
	//绝对路径解析方法
	const { resolve } = require("path");
	
	//提取css成单独文件插件
	const MiniCssExtractPlugin = require('mini-css-extract-plugin')
	
	//最新压缩css插件
	const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
	
	//手动添加webpack内部js压缩器
	const TerserWebpackPlugin = require('terser-webpack-plugin');
	
	//对html文件处理
	const HtmlWebpackPlugin = require('html-webpack-plugin');
	
	//默认使用生产环境,定义nodejs环境变量:决定使用browserslist的哪个环境
	process.env.NODE_ENV = 'production'
	
	//复用loader
	const commonCssloader = [
	    MiniCssExtractPlugin.loader,//提取css为单独文件
	    'css-loader',
	    {//兼容性处理 还需要在package.json中定义browserslist
	        loader: 'postcss-loader',
	        options: {
	            postcssOptions: {
	                ident: 'postcss',
	                plugins: [
	                    'postcss-preset-env'
	                ]
	            }
	        }
	    }
	]
	
	module.exports = {
	    entry: './src/js/index.js',
	    output: {
	        filename: 'js/bundle.[contenthash:10].js',
	        path:resolve(__dirname,'dist'),
	        clean: true,
	        publicPath:'./'
	    },
	    //压缩css
	    optimization: {
	        minimize: true,
	        minimizer: [
	            new TerserWebpackPlugin(),
	            new CssMinimizerPlugin()
	        ]
	    },
	    module: {
	        rules: [
	            /**
	             *  正常来讲,一个文件只能被一个loader处理
	             *  当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序
	             *  在loader中设置enforce:'pre',最先执行
	             */
	            {
	                //优化生产环境打包构建速度
	                //以下loader只会匹配一个
	                //注意:这里不能有两个配置处理同一种类型文件
	                oneOf: [
	                    {
	                        //css兼容性处理
	                        test: /\.css$/,
	                        use: [...commonCssloader],
	                    },
	                    {
	                        //less兼容性处理
	                        test: /\.less$/,
	                        use: [...commonCssloader,
	                            //use中loader执行从下往上,必须把这个处理放在css-loader与less-loader之间
	                            'less-loader'//将less转成css文件
	                        ],
	                    },
	                    {
	                        //js兼容性处理
	                        test: /\.js$/,
	                        exclude: /node_modules/,
	                        loader: 'babel-loader', //配置在.babelrc文件中
	                        options: {
	                            //开启babel缓存,第二次构建时会读取之前的缓存
	                            //问题:当文件名没有发生变化的时候,同名文件都是走缓存。会导致修改内容与实际展示内容不一致。
	                            cacheDirectory:true 
	                        }
	                    },
	                    {
	                        //图片处理
	                        test: /\.(jpg|png|gif)$/,
	                        loader: 'url-loader',
	                        options: {
	                            limit: 8 * 1024,//对8kb以下的图片进行base64处理
	                            name: '[name].[hash:8].[ext]',//对处理后的图片重命名
	                            outputPath: 'img', //设置处理后的图片路径
	                            publicPath: './', //指定打包后的css图片的基础路径,
	                            esModule:false //关闭es6模块化
	                        }
	                    },
	                    {
	                        //处理html中的图片问题
	                        test: /\.html$/,
	                        loader: 'html-loader',
	                        options: {
	                            esModule:false
	                        }
	                    },
	                    // 打包iconfont字体图标,和打包图片类似
	                    {
	                        test:/\.ttf$/,
	                        use: {
	                        loader: 'file-loader',
	                        options: {
	                            esModule: false, // 新版本中esModule默认为true,会导致文件的地址变为[object Module],因此这里设置为false
	                            name: '[name]_[hash:6].[ext]', // 输出的文件名为[原名称]_[哈希值].[原后缀]
	                            outputPath: 'fonts/',       // 文件存储路径(output.path + 值)(物理路径, 存储路径)
	                            publicPath:'../fonts' ,     // 负责输出目录, 即打包后的写在磁盘的位置
	                            // 输出解析文件的目录,url 相对于 HTML 页面(index.html所在文件夹的绝对路径 + 值)(文件引用路径就是看这个)
	                            // 如果output设置了publicPath, options也设置了publicPath,优先以options的publicPath为主
	                            // 是对页面引入资源的补充,比如img标签引入或者css引入等.
	                            // 千万不能设错,应该观察文件和HTML页面的存储地址位置,进行设置,否则引用时地址会错误,找不到文件
	                            // 一般只设置output的publicPath,方便统一管理
	                            limit: 1024                 // 限制当文件小于1KB的时候,就将文件转为base64存储于js中,以减少http请求次数,当文件大于1KB,则打包文件到指定目录,避免js过大
	                        }
	                        }
	                    },
	                    {
	                        //处理其他文件
	                        exclude: /\.(js|css|less|html|jpg|png|gif|ttf)$/,
	                        loader: 'file-loader',
	                        options: {
	                            name: '[name].[hash:8].[ext]',
	                            outputPath:'media'
	                        },
	                        // type: 'asset/resource',
	                        // generator: {
	                        //     filename: 'media/[name].[hash:6].[ext]'
	                        // }
	                    },
	                ]
	            }
	        ]
	    },
	    devtool: 'source-map',//错误追踪
	    plugins: [
	        //提取css为单独文件
	        new MiniCssExtractPlugin({
	            filename:'css/built.[contenthash:10].css'
	        }),
	        //对html文件处理
	        new HtmlWebpackPlugin({
	            template: './src/index.html',
	            scriptLoading: 'blocking',//去除script defer模式
	            //html压缩
	            mimify: {
	                //移除空格
	                collaspeWhitespace: true,
	                //移除注释
	                removeComments:true
	            }
	        })
	        
	    ],
	    //mode为production,js就自动压缩了
	    mode: 'production'
	}

tree shaking

定义
  • 将应用程序想象成一棵树。实际使用的源代码和库表示树的绿色活叶。死代码表示秋天被树木消耗的褐色枯叶,为了摆脱枯叶,必须摇晃树,使它们掉落
  • 官方文档
作用
  • tree shaking:去除无用代码,
使用方法
  1. 使用ES2015模块语法(即importexport
  2. 开启 production 环境 (webpack4 还必须使用 es6 模块化)
  3. package.json 中配置无副作用的文件
     {
     	"name":"your-project",
    	"sideEffects": ["*.css","*.less","./src/xxx"],          
     }
    
要点记录
  1. “副作用”:在导入时执行特殊行为的代码,而不公开一个或多个导出。
  • "sideEffects":false
    • 所有代码都没有副作用(都可以进行tree shaking)问题:可能会把css文件删掉
  • "sideEffects": true所有文件都有副作用,
    • 全都不可 tree-shaking
  • "sideEffects": ["*.css","*.less"]
    • 除了css,less文件有副作用,所有其他文件都可以 tree-shaking,但会保留这些文件
  1. "sideEffects"类似于,/*#__PURE__*/ 但在模块级别而不是语句级别。
  2. 通过使用 /*#__PURE__*/ 注释,可以告诉webpack函数调用是无副作用的(纯净的)。可以将其放在函数调用之前,以将其标记为无副作用。传递给函数的参数不会被注释标记,可能需要单独标记。当未使用变量的变量声明中的初始值被视为无副作用(纯净)时,它将被标记为无效代码,不被 minimizer 执行并丢弃, optimization.innerGraph 设置为 true 的时候启用。
     /*#__PURE__*/ double(55);
    
代码实现
	//绝对路径解析方法
	const { resolve } = require("path");
	
	//提取css成单独文件插件
	const MiniCssExtractPlugin = require('mini-css-extract-plugin')
	
	//最新压缩css插件
	const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
	
	//手动添加webpack内部js压缩器
	const TerserWebpackPlugin = require('terser-webpack-plugin');
	
	//对html文件处理
	const HtmlWebpackPlugin = require('html-webpack-plugin');
	
	//默认使用生产环境,定义nodejs环境变量:决定使用browserslist的哪个环境
	process.env.NODE_ENV = 'production'
	
	//复用loader
	const commonCssloader = [
	    MiniCssExtractPlugin.loader,//提取css为单独文件
	    'css-loader',
	    {//兼容性处理 还需要在package.json中定义browserslist
	        loader: 'postcss-loader',
	        options: {
	            postcssOptions: {
	                ident: 'postcss',
	                plugins: [
	                    'postcss-preset-env'
	                ]
	            }
	        }
	    }
	]
	
	module.exports = {
	    entry: './src/js/index.js',
	    output: {
	        filename: 'js/bundle.[contenthash:10].js',
	        path:resolve(__dirname,'dist'),
	        clean: true,
	        publicPath:'./'
	    },
	    //压缩css
	    optimization: {
	        minimize: true,
	        minimizer: [
	            new TerserWebpackPlugin(),
	            new CssMinimizerPlugin()
	        ]
	    },
	    module: {
	        rules: [
	            {
	                oneOf: [
	                    {
	                        //css兼容性处理
	                        test: /\.css$/,
	                        use: [...commonCssloader],
	                    },
	                    {
	                        //less兼容性处理
	                        test: /\.less$/,
	                        use: [...commonCssloader,
	                            //use中loader执行从下往上,必须把这个处理放在css-loader与less-loader之间
	                            'less-loader'//将less转成css文件
	                        ],
	                    },
	                    {
	                        //js兼容性处理
	                        test: /\.js$/,
	                        exclude: /node_modules/,
	                        loader: 'babel-loader', //配置在.babelrc文件中
	                        options: {
	                            //开启babel缓存,第二次构建时会读取之前的缓存
	                            //问题:当文件名没有发生变化的时候,同名文件都是走缓存。会导致修改内容与实际展示内容不一致。
	                            cacheDirectory:true 
	                        }
	                    },
	                    {
	                        //图片处理
	                        test: /\.(jpg|png|gif)$/,
	                        loader: 'url-loader',
	                        options: {
	                            limit: 8 * 1024,//对8kb以下的图片进行base64处理
	                            name: '[name].[hash:8].[ext]',//对处理后的图片重命名
	                            outputPath: 'img', //设置处理后的图片路径
	                            publicPath: './', //指定打包后的css图片的基础路径,
	                            esModule:false //关闭es6模块化
	                        }
	                    },
	                    {
	                        //处理html中的图片问题
	                        test: /\.html$/,
	                        loader: 'html-loader',
	                        options: {
	                            esModule:false
	                        }
	                    },
	                    // 打包iconfont字体图标,和打包图片类似
	                    {
	                        test:/\.ttf$/,
	                        use: {
	                        loader: 'file-loader',
	                        options: {
	                            esModule: false, // 新版本中esModule默认为true,会导致文件的地址变为[object Module],因此这里设置为false
	                            name: '[name]_[hash:6].[ext]', // 输出的文件名为[原名称]_[哈希值].[原后缀]
	                            outputPath: 'fonts/',       // 文件存储路径(output.path + 值)(物理路径, 存储路径)
	                            publicPath:'../fonts' ,     // 负责输出目录, 即打包后的写在磁盘的位置
	                            // 输出解析文件的目录,url 相对于 HTML 页面(index.html所在文件夹的绝对路径 + 值)(文件引用路径就是看这个)
	                            // 如果output设置了publicPath, options也设置了publicPath,优先以options的publicPath为主
	                            // 是对页面引入资源的补充,比如img标签引入或者css引入等.
	                            // 千万不能设错,应该观察文件和HTML页面的存储地址位置,进行设置,否则引用时地址会错误,找不到文件
	                            // 一般只设置output的publicPath,方便统一管理
	                            limit: 1024                 // 限制当文件小于1KB的时候,就将文件转为base64存储于js中,以减少http请求次数,当文件大于1KB,则打包文件到指定目录,避免js过大
	                        }
	                        }
	                    },
	                    {
	                        //处理其他文件
	                        exclude: /\.(js|css|less|html|jpg|png|gif|ttf)$/,
	                        loader: 'file-loader',
	                        options: {
	                            name: '[name].[hash:8].[ext]',
	                            outputPath:'media'
	                        },
	                        // type: 'asset/resource',
	                        // generator: {
	                        //     filename: 'media/[name].[hash:6].[ext]'
	                        // }
	                    },
	                ]
	            }
	        ]
	    },
	    devtool: 'source-map',//错误追踪
	    plugins: [
	        //提取css为单独文件
	        new MiniCssExtractPlugin({
	            filename:'css/built.[contenthash:10].css'
	        }),
	        //对html文件处理
	        new HtmlWebpackPlugin({
	            template: './src/index.html',
	            scriptLoading: 'blocking',//去除script defer模式
	            //html压缩
	            mimify: {
	                //移除空格
	                collaspeWhitespace: true,
	                //移除注释
	                removeComments:true
	            }
	        })
	        
	    ],
	    //mode为production,js就自动压缩了
	    mode: 'production'
	}

code split

  • 可以将代码分成多个 bundles ,然后可以按需或并行加载,可以用于实现更小的 bundle 和控制资源加载优先级
  • 官方文档
entry points(入口起点)
定义
使用方法
  1. 将入口设置为一个对象
  2. 更改输出文件名
    	//单入口
    	//entry: './src/js/index.js',
    	entry: {
    		index: './src/index.js',
    		another: './src/another-module.js',
    	},
    	output: {
    		//filename: 'main.js',
    		filename: '[name].bundle.js'
    	},
    
    
要点记录
  1. 多入口:一个入口 ,输出就有一个 bundle
  2. 问题:如果入口 chunk 之间包含一些重复的模块,那些重复模块都会被引入到各个 bundle 中。
  3. 这种方法不够灵活,并且不能动态地将核心应用程序逻辑中的代码拆分出来。
代码实现
	/**
	 * code split entry point
	 * 入口为一个对象
	 * entry:{}
	 */
	
	//绝对路径解析方法
	const { resolve } = require("path");
	
	//对html文件处理
	const HtmlWebpackPlugin = require('html-webpack-plugin');
	
	module.exports = {
	    //单入口
	    //entry: './src/js/index.js',
	    entry: {
	        //多入口:一个入口 --> 输出就有一个bundle
	        index: './src/js/index.js',
	        add: './src/js/add.js'
	    },
	    output: {
	        //[name]:取文件名
	        filename: 'js/[name].[contenthash:10].js',
	        path:resolve(__dirname,'dist'),
	        clean: true,
	        publicPath:'./'
	    },
	    plugins: [
	        //对html文件处理
	        new HtmlWebpackPlugin({
	            template: './src/index.html',
	            scriptLoading: 'blocking',//去除script defer模式
	        })
	    ],
	    mode: 'development',
	}
prevent duplication(防止重复)
定义
  • 使用 Entry dependencies 或者 SplitChunksPlugin 去重和分离 chunk
  • 官方文档
使用方法
Entry dependencies
  1. 配置 dependOn option 选项然后再加上optimization.runtimeChunk: 'single',否则会出问题,这样可以在多个 chunk 之间共享模块
    module.exports = {
    	mode: 'development',
    	entry: {
    		index: {
    			import: './src/index.js',
    			dependOn: 'shared',
    		},
    		another: {
    			import: './src/another-module.js',
    			dependOn: 'shared',
    		},
    		shared: 'lodash',
    	},
    	output: {
    		filename: '[name].bundle.js'
    	},
    	optimization: {
    		runtimeChunk: 'single',
    	},
    };
    
    除了生成 shared.bundle.jsindex.bundle.jsanother.bundle.js 之外,还生成了一个 runtime.bundle.js 文件
SplitChunksPlugin
  1. SplitChunksPlugin 插件可以将公共的依赖模块提取到现有的入口 chunk 中,或者提取到一个新生成的 chunk 。让我们使用这个插件,将在此之前的示例中重复的 lodash 模块移除
    	module.exports = {
    		mode: 'development',
    		entry: {
    			index: './src/index.js',
    			another: './src/another-module.js',
    		},
    		output: {
    			filename: '[name].bundle.js',
    			path: path.resolve(__dirname, 'dist'),
    		},
    		optimization: {
    			splitChunks: {
    			 	chunks: 'all',
    			},
    		},
    	};
    
    有了 optimization.splitChunks 配置选项后,我们现在应该看到从index.bundle.js 中删除了重复的依赖项 another.bundle.js。插件将lodash 分离到单独的块
要点记录
  1. 尽管可以在 webpack 中允许每个页面使用多入口,应确保避免使用多入口的入口: entry: { page: ['./analytics', './app'] } 。如此,在使用 async 脚本标签时,会有更好的优化以及一致的执行顺序
  2. index.js 文件这样引入 jquery
    	import $ from 'jquery';
    	console.log($);
    
    直接打包会将 jqueryindex.js 打包成一个文件,加上 splitChunks.chunks为all ,就能将引入的第三方库,单独打包出来,还能分析多入口 chunk 中有没有公共文件(>30kb),有就单独打包
代码实现
	/**
	 * prevent duplication(防止重复)
	 */
	
	//绝对路径解析方法
	const { resolve } = require("path");
	
	//对html文件处理
	const HtmlWebpackPlugin = require('html-webpack-plugin');
	
	module.exports = {
	    //单入口
	    entry: './src/js/index.js',
	    // entry: {
	    //     index: './src/js/index.js',
	    //     add: './src/js/add.js'
	    // },
	    output: {
	        //[name]:取文件名
	        filename: 'js/[name].[contenthash:10].js',
	        path:resolve(__dirname,'dist'),
	        clean: true,
	        publicPath:'./'
	    },
	    optimization: {
	        /**
	         * 单入口只有1,多入口1、2都有
	         * 1. 可以将node_modules中代码单独打包成一个chunk最终输出
	         * 2. 自动分析多入口chunk中有没有公共的文件(>30kb),如果有会单独打包成一个chunk
	         */
	        splitChunks: {
	            chunks:'all'
	        }
	    },
	    plugins: [
	        //对html文件处理
	        new HtmlWebpackPlugin({
	            template: './src/index.html',
	            scriptLoading: 'blocking',//去除script defer模式
	        })
	        
	    ],
	    mode: 'development',
	}
import(动态引入)
定义
  • 通过模块的内联函数调用来分离代码
  • 官方文档
    • import() function(string path):Promise 动态加载模块。详细
    • require.ensure() 特定于webpack 详细
使用方法
  1. 通过 js 代码,让某个文件被单独打包成一个 chunk
  • import 动态导入语法:能将某个文件单独打包
    	/**
    	 * 通过js代码,让某个文件被单独打包成一个chunk
    	 * import动态导入语法:能将某个文件单独打包
    	 */
    	import(/* webpackChunkName:'add' */'./add')
    	    .then(({ mul, count }) => {
    	        console.log('add文件加载成功');
    	        console.log("3+9=" + mul(3, 9));
    	        console.log("3-9="+count(3,9));
    	    })
    	    .catch(() => {
    	        console.log('文件加载失败');
    	    })
    
    
要点记录
  1. 语法
    	import(/* webpackChunkName:'test' */'./test')
    
代码实现
	/**
	 * code split
	 * 单入口,import()动态引入
	 */
	
	//绝对路径解析方法
	const { resolve } = require("path");
	
	//对html文件处理
	const HtmlWebpackPlugin = require('html-webpack-plugin');
	
	module.exports = {
	    //单入口
	    entry: './src/js/index.js',
	    output: {
	        //[name]:取文件名
	        filename: 'js/[name].[contenthash:5].js',
	        path:resolve(__dirname,'dist'),
	        clean: true,
	        publicPath:'./'
	    },
	    
	    plugins: [
	        //对html文件处理
	        new HtmlWebpackPlugin({
	            template: './src/index.html',
	            scriptLoading: 'blocking',//去除script defer模式
	        })
	        
	    ],
	    mode: 'development',
	}

lary loading

定义
  • 懒加载 前提:进行代码分割,当文件需要使用时才加载
  • 官方文档
  • 预加载 prefetch:会在使用之前,提前加载 js 文件 使用慎之又慎详细
    • 正常加载可以认为是并行加载(同一时间加载多个文件)
    • 预加载 :等其他资源加载完毕,浏览器空闲了,再偷偷加载资源
使用方法
  1. 通过 js 代码,让某个文件被单独打包成一个 chunk
    import动态导入语法:能将某个文件单独打包
    	document.getElementById('btn').onclick = function () {
        import(/* webpackChunkName:'add',webpackPrefetch:true */'./add')
        	.then(({ mul }) => {
            	console.log(mul(4, 5));
        	})
    	}
    
要点记录
  1. 增加一个交互,当用户单击按钮的时候用 console 打印一些文字,但是会等到第一次交互的时候再加载那个代码块(print.js
代码实现
	/**
	 * lary 懒加载
	 */
	//绝对路径解析方法
	const { resolve } = require("path");
	
	//对html文件处理
	const HtmlWebpackPlugin = require('html-webpack-plugin');
	
	module.exports = {
	    //单入口
	    entry: './src/js/index.js',
	    output: {
	        //[name]:取文件名
	        filename: 'js/[name].[contenthash:10].js',
	        path:resolve(__dirname,'dist'),
	        clean: true,
	        publicPath:'./'
	    },
	    optimization: {
	        splitChunks: {
	            chunks:'all'
	        }
	    },
	    plugins: [
	        //对html文件处理
	        new HtmlWebpackPlugin({
	            template: './src/index.html',
	            scriptLoading: 'blocking',//去除script defer模式
	            //html压缩
	            mimify: {
	                //移除空格
	                collaspeWhitespace: true,
	                //移除注释
	                removeComments:true
	            }
	        })
	        
	    ],
	    //mode为production,js就自动压缩了
	    mode: 'production',
	}

PWA

定义
  • 渐进式Web应用程序(或 PWA )是可提供与本机应用程序相似的体验的 Web 应用程序。有很多事情可以促成这一点。在这些功能中,最重要的是使应用程序能够在离线状态下运行的能力,这是通过使用称为 Service Workers 的网络技术来实现的
  • 官方文档
使用方法
  1. 安装插件
    	npm i workbox-webpack-plugin -D
    
  2. webpack.config.js中添加
    	new WorkboxWebpackPlugin.GenerateSW({
                /**
                 * 1. 帮助serviceworker快速启动
                 * 2. 删除旧的 serviceworker
                 * 
                 * 生成一个 serviceworker 配置文件 index.js中注册
                 */
                clientsClaim: true,
                skipWaiting:true
            })
    
  3. index.js中注册serviceWorker 处理兼容性问题
    	if ('serviceWorker' in navigator) {
    	    window.addEventListener('load', () => {
    	        navigator.serviceWorker
    	            .register('/service-worker.js')
    	            .then(() => {
    	                console.log('sw注册成功了');
    	            })
    	            .catch(() => {
    	                console.log('sw注册失败了');
    	        })
    	    })
    	}
    
  4. 安装
    	npm i serve -g
    
  5. 启动服务器,将 dist 目录下所有资源作为静态资源暴露出去 把网络设置为离线之后就可以在 application 中查看 serviceworker 中的文件了,使得网站可以离线访问
    	serve -s dist
    
要点记录
  1. serviceworker 代码必须运行在服务器上
代码实现
	/**
	 * PWA:渐进式网络开发应用程序(离线可访问)
	 * workbox --> workbox-webpack-plugin
	 */
	// workbox 下载插件
	const WorkboxWebpackPlugin =require('workbox-webpack-plugin')
	
	//绝对路径解析方法
	const { resolve } = require("path");
	
	//提取css成单独文件插件
	const MiniCssExtractPlugin = require('mini-css-extract-plugin')
	
	//最新压缩css插件
	const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
	
	//手动添加webpack内部js压缩器
	const TerserWebpackPlugin = require('terser-webpack-plugin');
	
	//对html文件处理
	const HtmlWebpackPlugin = require('html-webpack-plugin');
	
	//默认使用生产环境,定义nodejs环境变量:决定使用browserslist的哪个环境
	process.env.NODE_ENV = 'production'
	
	//复用loader
	const commonCssloader = [
	    MiniCssExtractPlugin.loader,//提取css为单独文件
	    'css-loader',
	    {//兼容性处理 还需要在package.json中定义browserslist
	        loader: 'postcss-loader',
	        options: {
	            postcssOptions: {
	                ident: 'postcss',
	                plugins: [
	                    'postcss-preset-env'
	                ]
	            }
	        }
	    }
	]
	
	module.exports = {
	    entry: './src/js/index.js',
	    output: {
	        filename: 'js/bundle.[contenthash:10].js',
	        path:resolve(__dirname,'dist'),
	        clean: true,
	        publicPath:'./'
	    },
	    //压缩css
	    optimization: {
	        minimize: true,
	        minimizer: [
	            new TerserWebpackPlugin(),
	            new CssMinimizerPlugin()
	        ]
	    },
	    module: {
	        rules: [
	            /**
	             *  正常来讲,一个文件只能被一个loader处理
	             *  当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序
	             *  在loader中设置enforce:'pre',最先执行
	             */
	            {
	                //优化生产环境打包构建速度
	                //以下loader只会匹配一个
	                //注意:这里不能有两个配置处理同一种类型文件
	                oneOf: [
	                    {
	                        //css兼容性处理
	                        test: /\.css$/,
	                        use: [...commonCssloader],
	                    },
	                    {
	                        //less兼容性处理
	                        test: /\.less$/,
	                        use: [...commonCssloader,
	                            //use中loader执行从下往上,必须把这个处理放在css-loader与less-loader之间
	                            'less-loader'//将less转成css文件
	                        ],
	                    },
	                    {
	                        //js兼容性处理
	                        test: /\.js$/,
	                        exclude: /node_modules/,
	                        loader: 'babel-loader', //配置在.babelrc文件中
	                        options: {
	                            //开启babel缓存,第二次构建时会读取之前的缓存
	                            //问题:当文件名没有发生变化的时候,同名文件都是走缓存。会导致修改内容与实际展示内容不一致。
	                            cacheDirectory:true 
	                        }
	                    },
	                    {
	                        //图片处理
	                        test: /\.(jpg|png|gif)$/,
	                        loader: 'url-loader',
	                        options: {
	                            limit: 8 * 1024,//对8kb以下的图片进行base64处理
	                            name: '[name].[hash:8].[ext]',//对处理后的图片重命名
	                            outputPath: 'img/', //设置处理后的图片路径
	                            publicPath: './img', //指定打包后的css图片的基础路径,
	                            esModule:false //关闭es6模块化
	                        }
	                    },
	                    {
	                        //处理html中的图片问题
	                        test: /\.html$/,
	                        loader: 'html-loader',
	                        options: {
	                            esModule: false
	                        }
	                    },
	                    // 打包iconfont字体图标,和打包图片类似
	                    {
	                        test:/\.ttf$/,
	                        loader: 'file-loader',
	                        options: {
	                            esModule: false, // 新版本中esModule默认为true,会导致文件的地址变为[object Module],因此这里设置为false
	                            name: '[name]_[hash:6].[ext]', // 输出的文件名为[原名称]_[哈希值].[原后缀]
	                            outputPath: 'fonts/',       // 文件存储路径(output.path + 值)(物理路径, 存储路径)
	                            publicPath:'../fonts' ,     // 负责输出目录, 即打包后的写在磁盘的位置
	                            // 输出解析文件的目录,url 相对于 HTML 页面(index.html所在文件夹的绝对路径 + 值)(文件引用路径就是看这个)
	                            // 如果output设置了publicPath, options也设置了publicPath,优先以options的publicPath为主
	                            // 是对页面引入资源的补充,比如img标签引入或者css引入等.
	                            // 千万不能设错,应该观察文件和HTML页面的存储地址位置,进行设置,否则引用时地址会错误,找不到文件
	                            // 一般只设置output的publicPath,方便统一管理
	                            limit: 1024                 // 限制当文件小于1KB的时候,就将文件转为base64存储于js中,以减少http请求次数,当文件大于1KB,则打包文件到指定目录,避免js过大
	                        }
	                    },
	                    {
	                        //处理其他文件
	                        exclude: /\.(js|css|less|html|jpg|png|gif)$/,
	                        loader: 'file-loader',
	                        options: {
	                            // esModule: false,
	                            name: '[name].[hash:8].[ext]',
	                            outputPath: 'media/',
	                            publicPath:'../media'
	                        },
	                        // type: 'asset/resource',
	                        // generator: {
	                        //     filename: 'media/[name].[hash:6].[ext]'
	                        // }
	                    },
	                ]
	            }
	        ]
	    },
	    plugins: [
	        //提取css为单独文件
	        new MiniCssExtractPlugin({
	            filename:'css/built.[contenthash:10].css'
	        }),
	        //对html文件处理
	        new HtmlWebpackPlugin({
	            template: './src/index.html',
	            scriptLoading: 'blocking',//去除script defer模式
	            //html压缩
	            mimify: {
	                //移除空格
	                collaspeWhitespace: true,
	                //移除注释
	                removeComments:true
	            }
	        }),
	        new WorkboxWebpackPlugin.GenerateSW({
	            /**
	             * 1. 帮助serviceworker快速启动
	             * 2. 删除旧的 serviceworker
	             * 
	             * 生成一个 serviceworker 配置文件 index.js中注册
	             */
	            clientsClaim: true,
	            skipWaiting:true
	        })
	        
	    ],
	    //mode为production,js就自动压缩了
	    mode: 'production',
	    devtool:'source-map'
	}

多进程打包

定义
  • 在大项目中使用 thread-loader ,提升构建速度
  • 官方文档
使用方法
  1. 安装插件
    	npm i thread-loader -D
    
  2. 开启多进程打包,在 babel-loader 前面添加,可以在 options 中进行配置
    	{
    		 loader: 'thread-loader',
    		 // options: {
             //     workers:2 // 产生的工作线程的数量,默认为(cpu数量- 1)或当require('os').cpus()未定义时,返回1
             // }
    	},
    
要点记录
  1. js 一般比较多,一般给 babel-loader 用,工作时间最长的 loader,所以用 thread-loader 优化
  2. 使用了这个 loader之后:
    • loaders 不能发出文件
    • loaders 不能使用自定义loader API(即通过插件)
    • loaders 无法访问 webpack options
    • 项目较大,打包较慢,开启多进程能提高速度
    • 项目较少,打包很快,开启多进程会降低速度,进程启动大概为600ms,进程通信也有开销
代码实现
	/**
	 * 多进程打包
	 */
	// workbox 下载插件
	const WorkboxWebpackPlugin =require('workbox-webpack-plugin')
	
	//绝对路径解析方法
	const { resolve } = require('path');
	
	//提取css成单独文件插件
	const MiniCssExtractPlugin = require('mini-css-extract-plugin')
	
	//最新压缩css插件
	const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
	
	//手动添加webpack内部js压缩器
	const TerserWebpackPlugin = require('terser-webpack-plugin');
	
	//对html文件处理
	const HtmlWebpackPlugin = require('html-webpack-plugin');
	
	//默认使用生产环境,定义nodejs环境变量:决定使用browserslist的哪个环境
	process.env.NODE_ENV = 'production'
	
	//复用loader
	const commonCssloader = [
	    MiniCssExtractPlugin.loader,//提取css为单独文件
	    'css-loader',
	    {//兼容性处理 还需要在package.json中定义browserslist
	        loader: 'postcss-loader',
	        options: {
	            postcssOptions: {
	                ident: 'postcss',
	                plugins: [
	                    'postcss-preset-env'
	                ]
	            }
	        }
	    }
	]
	
	module.exports = {
	    entry: './src/js/index.js',
	    output: {
	        filename: 'js/bundle.[contenthash:10].js',
	        path:resolve(__dirname,'dist'),
	        clean: true,
	        publicPath:'./'
	    },
	    //压缩css
	    optimization: {
	        minimize: true,
	        minimizer: [
	            new TerserWebpackPlugin(),
	            new CssMinimizerPlugin()
	        ]
	    },
	    module: {
	        rules: [
	            /**
	             *  正常来讲,一个文件只能被一个loader处理
	             *  当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序
	             *  在loader中设置enforce:'pre',最先执行
	             */
	            {
	                //优化生产环境打包构建速度
	                //以下loader只会匹配一个
	                //注意:这里不能有两个配置处理同一种类型文件
	                oneOf: [
	                    {
	                        //css兼容性处理
	                        test: /\.css$/,
	                        use: [...commonCssloader],
	                    },
	                    {
	                        //less兼容性处理
	                        test: /\.less$/,
	                        use: [...commonCssloader,
	                            //use中loader执行从下往上,必须把这个处理放在css-loader与less-loader之间
	                            'less-loader'//将less转成css文件
	                        ],
	                    },
	                    {
	                        //js兼容性处理
	                        test: /\.js$/,
	                        exclude: /node_modules/,
	                        use: [
	                            /**
	                             * 开启多进程打包
	                             * 进程启动大概为600ms,进程通信也有开销
	                             * 只有工作消耗时间比较长,才需要多进程打包
	                             * js一般比较多,工作时间最长的loader,所以用thread-loader优化
	                             */
	                            {
	                                loader: 'thread-loader',
	                                options: {
	                                    workers:2 //进程2个 ,产生的工作线程的数量,默认为(cpu数量- 1)CPU核数减一
	                                }
	                            },
	                            {
	                                loader: 'babel-loader', //配置在.babelrc文件中
	                                options: {
	                                    //开启babel缓存
	                                    cacheDirectory:true 
	                                }
	                            }
	                        ]
	                    },
	                    {
	                        //图片处理
	                        test: /\.(jpg|png|gif)$/,
	                        loader: 'url-loader',
	                        options: {
	                            limit: 8 * 1024,//对8kb以下的图片进行base64处理
	                            name: '[name].[hash:8].[ext]',//对处理后的图片重命名
	                            outputPath: 'img/', //设置处理后的图片路径
	                            publicPath: './img', //指定打包后的css图片的基础路径,
	                            esModule:false //关闭es6模块化
	                        }
	                    },
	                    {
	                        //处理html中的图片问题
	                        test: /\.html$/,
	                        loader: 'html-loader',
	                        options: {
	                            esModule:false
	                        }
	                    },
	                    {
	                        //处理其他文件
	                        exclude: /\.(js|css|less|html|jpg|png|gif)$/,
	                        loader: 'file-loader',
	                        options: {
	                            name: '[name].[hash:8].[ext]',
	                            outputPath: 'media/',
	                            publicPath:'../media'
	                        },
	                        // type: 'asset/resource',
	                        // generator: {
	                        //     filename: 'media/[name].[hash:6].[ext]'
	                        // }
	                    },
	                ]
	            }
	        ]
	    },
	    plugins: [
	        //提取css为单独文件
	        new MiniCssExtractPlugin({
	            filename:'css/built.[contenthash:10].css'
	        }),
	        //对html文件处理
	        new HtmlWebpackPlugin({
	            template: './src/index.html',
	            scriptLoading: 'blocking',//去除script defer模式
	            //html压缩
	            mimify: {
	                //移除空格
	                collaspeWhitespace: true,
	                //移除注释
	                removeComments:true
	            }
	        }),
	        new WorkboxWebpackPlugin.GenerateSW({
	            /**
	             * 1. 帮助serviceworker快速启动
	             * 2. 删除旧的 serviceworker
	             * 
	             * 生成一个 serviceworker 配置文件 index.js中注册
	             */
	            clientsClaim: true,
	            skipWaiting:true
	        })
	        
	    ],
	    //mode为production,js就自动压缩了
	    mode: 'production',
	    devtool:'source-map'
	}

external

定义
  • Externals 配置项用来告诉 Webpack 要构建的代码中使用了哪些不用被打包的模块,也就是说这些模版是外部环境提供的,Webpack 在打包时可以忽略它们
  • 官方文档
使用方法
  1. 在module.exports中添加,要排除的包名
    	externals: {
        //拒绝jQuery被打包进来 在html界面通过script标签引入cdn链接
        jquery:'jQuery'
      }
    
  2. 在html界面通过script标签引入cdn链接
    	<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    
要点记录
  1. cdn boostrapcdn开源网站,优化 webpack 打包
  2. external 可以防止框架的二次引用
代码实现
	const { resolve } = require('path');
	const HtmlWebpackPlugin = require('html-webpack-plugin');
	
	module.exports = {
	  entry: './src/js/index.js',
	  output: {
	    filename: 'js/bundle.js',
	    path: resolve(__dirname, 'dist')
	  },
	  plugins: [
	    new HtmlWebpackPlugin({
	      template: './src/index.html'
	    })
	  ],
	  mode: 'production',
	  externals: {
	    //拒绝jQuery被打包进来 在html界面通过script标签引入cdn链接
	    jquery:'jQuery'
	  }
	};

写在后面

优化配置,这里终于告一段落,学习的过程中有很多都已经变化了,所以附了很多官方文档的链接,还是要结合最新的文档配合学习。
未选择的路,心里永远会有一个设想,如果当初选择了另一条路会怎样,其实无论是什么样子,总不会是自己在这种情境下期待的样子,当你身处局中时,你的选择改变不了未来的,我们只能走一条路,在踏上的那一刻,就是一条全新的路了,未来因此刻的选择而变化,过去的结点没有办法回转。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值