js-webpack优化

436 阅读5分钟

这个问题就像能不能说一说「从URL输入到页面显示发生了什么」一样)\

  • 使用高版本的 Webpack 和 Node.js\

  • 多进程/多实例构建:HappyPack(不维护了)、thread-loader\

  • 压缩代码

    • 多进程并行压缩
    • webpack-paralle-uglify-pluginuglifyjs-webpack-plugin 开启 parallel 参数 (不支持ES6)terser-webpack-plugin 开启 parallel 参数\
    • 通过 mini-css-extract-plugin 提取 Chunk 中的 CSS 代码到单独文件,通过 css-loader 的 minimize 选项开启 cssnano 压缩 CSS。\
  • 图片压缩

    • 使用基于 Node 库的 imagemin (很多定制选项、可以处理多种图片格式)配置 image-webpack-loader\
    • 缩小打包作用域:
      • exclude/include (确定 loader 规则范围)resolve.modules 指明第三方模块的绝对路径 (减少不必要的查找)resolve.mainFields 只采用 main 字段作为入口文件描述字段 (减少搜索步骤,需要考虑到所有运行时依赖的第三方模块的入口文件描述字段)resolve.extensions 尽可能减少后缀尝试的可能性noParse 对完全不需要解析的库进行忽略 (不去解析但仍会打包到 bundle 中,注意被忽略掉的文件里不应该包含 import、require、define 等模块化语句)IgnorePlugin (完全排除模块)合理使用alias\
  • 提取页面公共资源:

    • 基础包分离:

      • 使用 html-webpack-externals-plugin,将基础包通过 CDN 引入,不打入 bundle 中使用 SplitChunksPlugin 进行(公共脚本、基础包、页面公共文件)分离(Webpack4内置) ,替代了 CommonsChunkPlugin 插件
    • DLL:

      • 使用 DllPlugin 进行分包,使用 DllReferencePlugin(索引链接) 对 manifest.json 引用,让一些基本不会改动的代码先打包成静态资源,避免反复编译浪费时间。HashedModuleIdsPlugin 可以解决模块数字id问题\充分利用缓存提升二次构建速度:
  • babel-loader 开启缓存terser-webpack-plugin 开启缓存使用 cache-loader 或者 hard-source-webpack-plugin\

  • Tree shaking

    • 打包过程中检测工程中没有引用过的模块并进行标记,在资源压缩时将它们从最终的bundle中去掉(只能对ES6 Modlue生效) 开发中尽可能使用ES6 Module的模块,提高tree shaking效率禁用 babel-loader 的模块依赖解析,否则 Webpack 接收到的就都是转换过的 CommonJS 形式的模块,无法进行 tree-shaking使用 PurifyCSS(不在维护) 或者 uncss 去除无用 CSS 代码purgecss-webpack-plugin 和 mini-css-extract-plugin配合使用(建议)
  • Scope hoisting

    • 构建后的代码会存在大量闭包,造成体积增大,运行代码时创建的函数作用域变多,内存开销变大。Scope hoisting 将所有模块的代码按照引用顺序放在一个函数作用域里,然后适当的重命名一些变量以防止变量名冲突必须是ES6的语法,因为有很多第三方库仍采用 CommonJS 语法,为了充分发挥 Scope hoisting 的作用,需要配置 mainFields 对第三方模块优先采用 jsnext:main 中指向的ES6模块化语法\
  • 动态Polyfill

    • 建议采用 polyfill-service 只给用户返回需要的polyfill,社区维护。 (部分国内奇葩浏览器UA可能无法识别,但可以降级返回所需全部polyfill)

  • 1、通过webpack配置优化实现页面性能提升

    • ⽤webpack优化前端性能是指优化webpack的输出结果,让打包的最终结果在浏览器运⾏快速⾼效。
    • 1、压缩代码:删除多余的代码、注释、简化代码的写法等等⽅式。可以利⽤webpack的 UglifyJsPlugin 和 ParallelUglifyPlugin 来压缩JS⽂件, 利⽤ cssnano (css-loader?minimize)来压缩css\
    • 2、利⽤CDN加速: 在构建过程中,将引⽤的静态资源路径修改为CDN上对应的路径。可以利⽤webpack对于 output 参数和各loader的 publicPath 参数来修改资源路径\
    • 3、Tree Shaking: 将代码中永远不会⾛到的⽚段删除掉。可以通过在启动webpack时追加参数 --optimize-minimize 来实现\
    • 4、Code Splitting: 将代码按路由维度或者组件分块(chunk),这样做到按需加载,同时可以充分利⽤浏览器缓存\
    • 5、提取公共第三⽅库: SplitChunksPlugin插件来进⾏公共模块抽取,利⽤浏览器缓存可以⻓期缓存这些⽆需频繁变动的公共代码

  • 2、如何优化webpack构建速度

    • 配置优化

      • 1、优化 Loader 配置
        • 巧用 include 和 exclude 让尽量少的文件被 loader 处理
      • 2、优化 resolve.modules配置
        • resolve.modules 用于配置 webpack 去哪些模块下寻找第三方模块,默认是 node_modules,但是,它会先去当前目录的 ./node_modules 查找,没有的话再去 ../node_modules, 最后到根目录;\
        • 所以当安装的第三方模块都放在项目根目录时,就没有必要按默认的一层一层的查找,直接指明存放的绝对位置
      • 3、优化resolve.extensions配置
        • 频率出现高的文件后缀优先放在前面;
        • 列表尽可能的小;
        • 书写导入语句时,尽量写上后缀名
    • 使用DllPlugin优化

      • 将依赖的第三方模块抽离,打包到一个个单独的动态链接库中
      • 当需要导入的模块存在动态链接库中时,让其直接从链接库中获取
      • 项目依赖的所有动态链接库都需要被加载
    • HappyPack并行构建优化

      • 将webpack中最耗时的loader文件转换操作任务,分解到多个进程中并行处理,从而减少构建时间。

  • 3、是否可以利用swc或者esbuild提升webpack构建速度
    • 可以
    • swc是一个用 Rust 写的高性能 TypeScript / JavaScript 转译器,类似于 babel。对比 babel,swc 有至少 10 倍以上的性能优势。\我们可以使用swc-loader来代替babel-loader来加快webpack的构建速度。
    • esbuild 是用go语言编写的新一代的 JavaScript 打包工具。以速度快而著称,耗时只有 webpack 的 2% ~3%,vite就内置了esbuild。那么想用esbuild来加快webpack构建速度的话,可以用esbuild-loader来替换babel-loader。