webpack4配置
1、基本配置
webpack.common.js
const path = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') const { srcPath, distPath } = require('./paths') module.exports = { entry: { index: path.join(srcPath, 'index.js'), other: path.join(srcPath, 'other.js') }, module: { rules: [ // babel-loader ] }, plugins: [ // new HtmlWebpackPlugin({ // template: path.join(srcPath, 'index.html'), // filename: 'index.html' // }) // 多入口 - 生成 index.html new HtmlWebpackPlugin({ template: path.join(srcPath, 'index.html'), filename: 'index.html', // chunks 表示该页面要引用哪些 chunk (即上面的 index 和 other),默认全部引用 chunks: ['index', 'vendor', 'common'] // 要考虑代码分割 }), // 多入口 - 生成 other.html new HtmlWebpackPlugin({ template: path.join(srcPath, 'other.html'), filename: 'other.html', chunks: ['other', 'vendor', 'common'] // 考虑代码分割 }) ] }
webpack.dev.js
const path = require('path') const webpack = require('webpack') const webpackCommonConf = require('./webpack.common.js') const { smart } = require('webpack-merge') const { srcPath, distPath } = require('./paths') const HotModuleReplacementPlugin = require('webpack/lib/HotModuleReplacementPlugin'); module.exports = smart(webpackCommonConf, { mode: 'development', entry: { // index: path.join(srcPath, 'index.js'), index: [ 'webpack-dev-server/client?http://localhost:8080/', 'webpack/hot/dev-server', path.join(srcPath, 'index.js') ], other: path.join(srcPath, 'other.js') }, module: { rules: [ { test: /\.js$/, loader: ['babel-loader?cacheDirectory'],//开启缓存 include: srcPath, // exclude: /node_modules/ }, // 直接引入图片 url { test: /\.(png|jpg|jpeg|gif)$/, use: 'file-loader' }, // { // test: /\.css$/, // // loader 的执行顺序是:从后往前 // loader: ['style-loader', 'css-loader'] // }, { test: /\.css$/, // loader 的执行顺序是:从后往前 loader: ['style-loader', 'css-loader', 'postcss-loader'] // 加了 postcss }, { test: /\.less$/, // 增加 'less-loader' ,注意顺序 loader: ['style-loader', 'css-loader', 'less-loader'] } ] }, plugins: [ new webpack.DefinePlugin({ // window.ENV = 'production' ENV: JSON.stringify('development') }), new HotModuleReplacementPlugin() ], devServer: { port: 8080, progress: true, // 显示打包的进度条 contentBase: distPath, // 根目录 open: true, // 自动打开浏览器 compress: true, // 启动 gzip 压缩 hot: true, // 设置代理 proxy: { // 将本地 /api/xxx 代理到 localhost:3000/api/xxx '/api': 'http://localhost:3000', // 将本地 /api2/xxx 代理到 localhost:3000/xxx '/api2': { target: 'http://localhost:3000', pathRewrite: { '/api2': '' } } } }, // watch: true, // 开启监听,默认为 false // watchOptions: { // ignored: /node_modules/, // 忽略哪些 // // 监听到变化发生后会等300ms再去执行动作,防止文件更新太快导致重新编译频率太高 // // 默认为 300ms // aggregateTimeout: 300, // // 判断文件是否发生变化是通过不停的去询问系统指定文件有没有变化实现的 // // 默认每隔1000毫秒询问一次 // poll: 1000 // } })
webpack.prod.js
const path = require('path') const webpack = require('webpack') const { smart } = require('webpack-merge') const { CleanWebpackPlugin } = require('clean-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') const TerserJSPlugin = require('terser-webpack-plugin') const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin') const HappyPack = require('happypack') const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin') const webpackCommonConf = require('./webpack.common.js') const { srcPath, distPath } = require('./paths') module.exports = smart(webpackCommonConf, { mode: 'production', output: { // filename: 'bundle.[contentHash:8].js', // 打包代码时,加上 hash 戳 filename: '[name].[contentHash:8].js', // name 即多入口时 entry 的 key path: distPath, // publicPath: 'http://cdn.abc.com' // 修改所有静态文件 url 的前缀(如 cdn 域名),这里暂时用不到 }, module: { rules: [ // js { test: /\.js$/, // 把对 .js 文件的处理转交给 id 为 babel 的 HappyPack 实例 use: ['happypack/loader?id=babel'], include: srcPath, // exclude: /node_modules/ }, // 图片 - 考虑 base64 编码的情况 { test: /\.(png|jpg|jpeg|gif)$/, use: { loader: 'url-loader', options: { // 小于 5kb 的图片用 base64 格式产出 // 否则,依然延用 file-loader 的形式,产出 url 格式 limit: 5 * 1024, // 打包到 img 目录下 outputPath: '/img1/', // 设置图片的 cdn 地址(也可以统一在外面的 output 中设置,那将作用于所有静态资源) // publicPath: 'http://cdn.abc.com' } } }, // 抽离 css { test: /\.css$/, loader: [ MiniCssExtractPlugin.loader, // 注意,这里不再用 style-loader 'css-loader', 'postcss-loader' ] }, // 抽离 less { test: /\.less$/, loader: [ MiniCssExtractPlugin.loader, // 注意,这里不再用 style-loader 'css-loader', 'less-loader', 'postcss-loader' ] } ] }, plugins: [ new CleanWebpackPlugin(), // 会默认清空 output.path 文件夹 new webpack.DefinePlugin({ // window.ENV = 'production' ENV: JSON.stringify('production') }), // 抽离 css 文件 new MiniCssExtractPlugin({ filename: 'css/main.[contentHash:8].css' }), // 忽略 moment 下的 /locale 目录 new webpack.IgnorePlugin(/\.\/locale/, /moment/), // happyPack 开启多进程打包 new HappyPack({ // 用唯一的标识符 id 来代表当前的 HappyPack 是用来处理一类特定的文件 id: 'babel', // 如何处理 .js 文件,用法和 Loader 配置中一样 loaders: ['babel-loader?cacheDirectory'] }), // 使用 ParallelUglifyPlugin 并行压缩输出的 JS 代码 new ParallelUglifyPlugin({ // 传递给 UglifyJS 的参数 // (还是使用 UglifyJS 压缩,只不过帮助开启了多进程) uglifyJS: { output: { beautify: false, // 最紧凑的输出 comments: false, // 删除所有的注释 }, compress: { // 删除所有的 `console` 语句,可以兼容ie浏览器 drop_console: true, // 内嵌定义了但是只用到一次的变量 collapse_vars: true, // 提取出出现多次但是没有定义成变量去引用的静态值 reduce_vars: true, } } }) ], optimization: { // 压缩 css minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})], // 分割代码块 splitChunks: { chunks: 'all', /** * initial 入口chunk,对于异步导入的文件不处理 async 异步chunk,只对异步导入的文件处理 all 全部chunk */ // 缓存分组 cacheGroups: { // 第三方模块 vendor: { name: 'vendor', // chunk 名称 priority: 1, // 权限更高,优先抽离,重要!!! test: /node_modules/, minSize: 0, // 大小限制 minChunks: 1 // 最少复用过几次 }, // 公共的模块 common: { name: 'common', // chunk 名称 priority: 0, // 优先级 minSize: 0, // 公共模块的大小限制 minChunks: 2 // 公共模块最少复用过几次 } } } } })
综合以上配置,webpack性能优化的的点有
优化构建打包速度:
优化babel-loader:开启缓存
ignorePlugin:打包忽略某个第三方模块下的某个目录
happPack多进程打包:js是单线程,开启多进程打包,提交构建速度
ParallelUglifyPlugin:多进程压缩js,更快
下面的点不可用于生产环境:
自动刷新:网页全部刷新
热更新:新代码生效,网页不刷新,配置有成本
DllPlugin==>动态链接插件,提高本地构建速度
优化产出代码:
目标:
体积更小
合理分包,不重复加载
速度更快,内存使用更小
实现: 小图片base64编码
bunddle加hash
懒加载
提取公用的代码(splitChunks)
IngonrePlugin
使用CDN加速
使用production ==》 生产环境自动开启代码压缩,根据官网的提示,使用了 import
、export
,以及将 mode
设置为 production
时,自动开启 Tree Shaking
启动tree Shaking: ES6 module才能让tree-shaking生效,commonjs就不行
ES6 module静态引入,编译时引入:只有ES module 才能静态分析
commonjs动态引入,执行时引入
scopeHosting==》 代码体积更小
创建的函数作用域更少
代码可读性更好