Webpack5热替换,压缩JS、CSS、图片,基础优化新方法

6,722 阅读4分钟

Webpack5热替换,压缩JS、CSS、图片,基础优化新方法文章首图
本文基于最新Webpack5配置HMR热替换JSCSS图片压缩基础优化并生成Source Map

热替换 · HMR · Hot Module Replace

JS 和 CSS 热替换

只需将hot设为true,不需要引入热替换插件,在入口.js,添加module.hot.accept()即可

// 配置:webpack.config.js
devServer: {
  hot: true
}
// 入口:index.js
if (module.hot) {
    module.hot.accept(); // bundle.js 支持HMR
}
import './style.css'; // CSS作为模块引入 支持HMR

注意:如果css模块命名包含[contenthash][chunkhash],HMR会失效
建议只在生产环境配置hash,开发环境HMR本身已经解决缓存问题

new MiniCssExtractPlugin({
  filename: 'style.[contenthash].css' // 开发环境:style.css即可
}),

HTML 热更新

开启热替换后,.html默认不再自动刷新,您可以:

  1. hot下新增参数watchContentBase,设为true
    • contentBase(默认当前工作目录)下文件变更都会触发刷新,JSCSS的热替换失效
  2. 通过raw-loader.html作为资源引入入口.js
    • .html成为模块可以热更新,JSCSS热替换有效,可能需要在html手动引用它们
  3. HtmlWebpackPlugin多用来将html作为模版,自动引用打包好的JSCSS 不用插件,用nodejschokidar配合before参数,.html内容变化时通知server更新即可
npm i chokidar -D
devServer: {
  hot: true,
  before(_, server) {
      const chokidar = require('chokidar');
      const files = [
          resolve('src-es6/index-tpl.html') // 与 HtmlWebpackPlugin 的 template 对应
      ];
      chokidar.watch(files).on('all', () => {
          server.sockWrite(server.sockets, 'content-changed');
      })
  }
}

综上,我们实现了JSCSS热替换(不刷新更新),HTML热更新(自动刷新页面)

JavaScript压缩

TerserPlugin

Webpack5自带,不用安装。暂时忘记UglifyjsPlugin ParallelUglifyPlugin环境变量

optimization: {
  minimize: true, // 可省略,默认最优配置:生产环境,压缩 true。开发环境,不压缩 false
  minimizer: [
      new TerserPlugin({
          parallel: true, // 可省略,默认开启并行
          terserOptions: {
              toplevel: true, // 最高级别,删除无用代码
              ie8: true,
              safari10: true,
          }
      })
}

cache不再单独配置。遵循webpackcache设置(与optimization同级)

cache: true // 可省略,默认最优配置:生产环境,不缓存 false。开发环境,缓存到内存,memory

sourceMap不再单独配置。遵循webpackdevtool配置(与cache同级)

devtool: env.NODE_ENV === 'production' ? 'source-map' : 'inline-source-map' // 官方推荐生产环境和开发环境的配置

Babel

开启缓存babel-loader?cacheDirectory仍是提高Babel性能有效方式
cache-loader类似,thread-loader代替HappyPack,为其后loader开启单独worker pool
两者只用npm i cache-loader -D npm i thread-loader -D放到需要作用的loader前面即可

module: {
  rules: [{
      test: /\.js$/, 
      include: resolve('src-es6/js'), // test、include、exclude 缩小查找范围
      use: [
          'cache-loader', // 缓存其后loader结果
          'thread-loader', // 其后loader开启独立worker池
          {
              loader: 'babel-loader?cacheDirectory', // 开启babel-loader缓存
              options: {
                  presets: '@babel/preset-env',
                  plugins: [
                      ['@babel/plugin-transform-runtime',
                       { 'corejs': 3 }]
                  ]
              }
          }
      ]
   }]
}

preset-env-2015等以年代latest结尾的预设已成为过去。只是为了es5+es5,可直接

npm i @babel/preset-env -D

默认除语法外,Babel对ES6的新增接口如includes不会转成老接口
为了兼容,需要在老浏览器上引入polyfill,即纯JS实现新增接口
@babel/polyfill7.4.0起废弃,不用配置useBuiltIns,用@babel/plugin-transform-runtim

npm i @babel/plugin-transform-runtime -D

指定corejs版本

  • 2 仅支持全局变量,如Promise
  • 3 还支持实例属性,包括includes等 安装即可
npm i @babel/runtime-corejs3 -D

作用域提升 · Scope Hoisting

多ES6模块放闭包,减冗余并加速。ModuleConcatenationPlugin曾是首选,Webpack4+默认支持

optimization: {
  concatenateModules: true // 可省略,默认最优配置,生产环境作用域提升开启 true,开发环境禁用 false
}

其它

HardSourceWebpackPlugin DllPluginDLLReferencePlugin,随着Webpack4+自身编译加快
曾经收益可观的优化方式,在一些项目中已经不那么必要,但他们的贡献有目共睹,至今仍被使用

CSS压缩

MiniCssExtractPlugin

Webpack4+以后,抽离CSS到独立文件,通过MiniCssExtractPlugin实现

npm i mini-css-extract-plugin -D
// 入口:index.js
import './style.css';
// 配置:webpack.config.js
module: {
    rules: [
        {
            test: /\.css$/,
            include: resolve('src-es6/css'), // test、include、exclude 缩小查找范围
            use: [
                MiniCssExtractPlugin.loader, // 放在css-loader前
                { loader: 'css-loader',
                  options: { sourceMap: true } } // 影响所有依赖css-loader的插件生成sourceMap
            ]
        }
    ]
},
plugins: [
  new MiniCssExtractPlugin({
      filename: 'style.css', // 指定文件名 生产环境可写成 style.[contenthash].css 避免缓存问题
  }),
]

CssMinimizerPlugin

MiniCssExtractPlugin推荐CssMinimizerPlugin压缩CSS,自带cssnano。暂时忘记PurgeCSS

npm i css-minimizer-webpack-plugin -D
配置:webpack.config.js
optimization: {
    minimizer: [
     new CssMinimizerPlugin({
            parallel: true, // 可省略,默认开启并行
            sourceMap: true, // 可省略,默认遵循webpack的devtool配置
            minimizerOptions: {
                preset: 'advanced', // 需额外安装
            },
        })
    ]
}

sourceMap可单独配置。不配置时遵循webpackdevtool配置(与optimization同级)
插件自带的preset默认是defaultcssnano共支持3种预设优化方案 cssnano共支持3种预设配置

移除未使用CSSdiscardUnused在优化方案advance中,安装cssnano-preset-advanced即可

npm i cssnano-preset-advanced -D

图片压缩

CSS内联图片

url-loader小于指定尺寸图片转base64

module: {
    rules: [{
      test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
      loader: 'url-loader',
      options: {
        limit: 10, // 小于10KB图片,转base64编码
      }
}]}

图片模块

import/require.js.htmlrequire(图片路径)的图

  • file-loader + image-webpack-loader
rules: [{
  test: /\.png$/i, // 以png为例
  use: [
    'file-loader',
    {
      loader: 'image-webpack-loader',
      options: {
        pngquant: {
          quality: [0.65, 0.90] // 设置png的品质区间
        },
      }
    },
  ],
}]

图片目录

如果图片是直接引入到.html,或者通过.js加载,上面方法无效,实际项目中

  • 图片多在同一目录
  • CopyPlugin在编译时,从源目录src复制到发布目录dist
npm i imagemin-webpack-plugin -D

注意 插件默认安装gifsicle,如果你的网络环境一直失败,请用cnpm安装
使用cnpm后,删node_modules目录,再cnpm i将之前用npm装的重装一遍,避免其它问题

plugins: [
    new CopyPlugin({
      patterns: [{
          from: resolve('src-es6/images'),
          to: resolve('dist/images'),
      }]
    }),
    new ImageminPlugin({ // 在CopyPlugin之后。如果是merge多配置文件,CopyPlugin放common被合并的配置里
        test: /\.(png|jpe?g)$/i,
        pngquant: {
            quality: '70-75' // 设置png的品质区间
        },
        plugins: [ // 可以引入其它图片压缩插件
            ImageminMozjpeg({
                quality: 70, // 设置jpeg/jpg的品质
                progressive: true // 渐进式:true:由模糊到清晰加载 false:从上到下加载
            })
        ]
    }),
]

自带jpegtran不能调品质,在《ImageminPlugin支持图片压缩插件列表》选插件
安装ImageminMozjpeg即可

npm i imagemin-mozjpeg -D

这是小宇在掘金上的首篇文章,感谢您的阅读,祝您生活愉快!