Webpack 再入门(2)性能优化

171 阅读3分钟

Webpack 性能优化

开发环境优化

加快构建速度 -- HMR

HMR 热更新,一个模块发生更新,只重新打包更新这一个模块

devServer: {
  hot: true
}
  • html 不需要热更新
  • 样式文件支持 HMR 功能,style-loader 支持
  • js 文件默认不能使用 HMR,需要添加如下代码,只能处理非入口的 js 文件
if(module.hot) {
  module.hot.accept('./some.js', function () {
    // do something
  })
}

方便调试代码 -- source-map

source-map,源代码与产物代码之间的映射关系

// webpack.config.js 中开启 source-map
// [inline-|hidden-|eval-][nosources-][cheap-[module-]]soure-map
devtool: 'source-map'
参数生成位置说明
source-map外部错误代码的源代码及位置
inline-内联生成到文件底部
错误代码的源代码及位置
eval-内联生成到构建的文件中每个文件的 eval 后
错误代码的源代码及位置
hidden-外部不能追踪错误,只能提示构建后代码的错误位置
nosources-外部有错误代码的源代码位置,但无源代码
cheap-外部有错误代码的源代码,只能确定到行
cheap-module-外部会包含 module 的 sourcemap

生产环境优化

加快 loader 处理 -- oneOf

// webpack.config.js

modules: {
  rules: [
     {
       test: /xx/
       ...
     }, {
       // 使用 oneOf 文件只会匹配其中一个 loader
       // 注意不能有两个配置处理同一文件
       oneOf: [
         { test: /.x1./, loader: 'xx1'} ,
         { test: /.x2./, loader: 'xx2'} ,
         { test: /.x3./, loader: 'xx3'} ,
       ]
     }
  ]
}

缓存

babel 缓存

在 babel-loader 中设置参数,cacheDirectory: ture

文件资源缓存

资源文件使用哈希值命名,如

  • [hash] webpack 每次打包的唯一 hash
  • [chunkhash] 每个 chunk 具有的 hash,如果几个文件同属一个 chunk,它们的 chunkhash 一样
  • [contenthash] 每个文件具有的唯一 hash

因此最佳选择就是 contenthash

tree-shaking

去除无用代码

前提必须使用 ES6 模块,在 production 就支持 tree-shaking 了

package.json 中的配置 sideEffects,如果为 false,则表示当前项目下文件无副作用, tree-shaking 的过程中就有可能把 import './index.css' 干掉;如果为 ["*.css", "*.less"],则表示 css/less 文件有副作用,就会保留

code split

使用多入口

在 entry 中配置多个入口

optimization

// node_modules 中的代码单独打包
// 自动分析多入口中的公共文件,并单独打包成一个 chunk
optimization: {
  splitChunks: {
    chunks: 'all'
  }
}

import()

使用 import() 动态导入,能将某个文件单独打包

使用 webpackChunkName 注释可以给打包后的文件命名,否则以一串 id 命名

import(/* webpackChunkName: "test"*/ './test.js')
  .then(testModule => {
    console.log('文件加载完成')
  }).catch(() => {
    console.log('文件加载失败')
  })

懒加载和预加载

懒加载

使用时才加载

import(/* webpackChunkName: "test"*/ './test.js')

预加载

预加载,浏览器空闲时,默默的加载,到了使用时就早已完成加载,节省了时间,又不会影响正常的加载

import(/* webpackChunkName: 'test', webpackPrefetch: true  */ './test.ts)

PWA

PWA(Progressive Web Apps,渐进式网络应用),可以实现离线可访问的应用

workbox-webpack-plugin 帮助 serviceworker 快速启动,删除旧的 servicework

new WorkboxWebpackPlugin.GenerateSW({
  clientsClaim: true,
  skipWaiting: true,
})
// 注册 serviceworker
// 处理兼容性
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serivceWork.register('/service-worker.js')
      .then(()=> console.log('sw注册成功'))
      .catch(()=> console.log('sw注册失败'))
  })
}

多进程打包

使用 thread-loader,并放在需要的 loader 后面,开启多进程打包,但由于开启多进程也会耗时,只有工作时间较长时,开启才有效果,否则会有反效果

{
  test: /\.js$/,
  use: [
    'thread-loader',
    {
      loader: 'babel-loader',
      options: {...}
    }
  ]
 
}

externals

使用外部扩展,不将代码打入包中,例如在 html 中使用 CDN 引入 jquery ,而打包时需要排除 jquery

// webpack.config.js
module.exports = {
   ...
   externals: {
     // 忽略包名:全局变量名
     jquery: jQuery
   }
   ...
}