1.如何用webpack来优化前端性能

1.1 压缩JS

terser-webpack-plugin

1.2 压缩CSS

optimize-css-assets-webpack-plugin

1.3 压缩图片

image-webpack-loader

1.4 清除无用的CSS

单独取出css并清除用不到的css

  1. const path = require("path");
  2. +const MiniCssExtractPlugin = require("mini-css-extract-plugin");
  3. +const PurgecssPlugin = require("purgecss-webpack-plugin");
  4. module.exports = {
  5. module: {
  6. rules: [
  7. {
  8. test: /\.css$/,
  9. include: path.resolve(__dirname, "src"),
  10. exclude: /node_modules/,
  11. use: [
  12. {
  13. loader: MiniCssExtractPlugin.loader,
  14. },
  15. "css-loader",
  16. ],
  17. }
  18. ]
  19. },
  20. plugins: [
  21. new MiniCssExtractPlugin({
  22. filename: "[name].css",
  23. }),
  24. new PurgecssPlugin({
  25. paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }),
  26. })
  27. ]
  28. devServer: {},
  29. };

1.5 Tree Shaking

  • 一个模块可以导出多个方法,只要一个方法被用到了就会把整个文件打包到bundle中去,tree shaking就是把只用到的方法打包到bundle,不用到的在uglify的时候去掉
  • 原理是ES6模块的特点,只能作为模块顶层语句出现,import的模块名只能是字符串常量

以下摘自官网
sideEffects
如果被标记为无副作用的模块没有被直接导出使用,打包工具会跳过进行模块的副作用分析评估
[sideEffects](https://webpack.docschina.org/configuration/optimization/#optimizationsideeffects)[usedExports](https://webpack.docschina.org/configuration/optimization/#optimizationusedexports)(更多被认为是 tree shaking)是两种不同的优化方式。
**sideEffects** 更为有效 是因为它允许跳过整个模块/文件和整个文件子树。
usedExports 依赖于 terser 去检测语句中的副作用。它是一个 JavaScript 任务而且没有像 sideEffects 一样简单直接。而且它不能跳转子树/依赖由于细则中说副作用需要被评估。尽管导出函数能运作如常,但 React 框架的高阶函数(HOC)在这种情况下是会出问题的。
webpack.config.js

  1. module.exports = {
  2. //...
  3. optimization: {
  4. usedExports: false
  5. }
  6. };
  7. op

package.json

  1. {
  2. "name": "awesome npm module",
  3. "version": "1.0.0",
  4. "sideEffects": false
  5. }

1.6 scope Hoisting

  • Scope Hoisting 可以让 Webpack 打包出来的代码文件更小、运行的更快, 它又译作 “作用域提升”
  • scope hoisting的原理是将所有的模块按照引用顺序放在一个函数作用域里,然后适当地重命名一些变量以防止命名冲突
  • 这个功能在mode为production下默认开启,开发环境要用 webpack.optimize.ModuleConcatenationPlugin插件

    1.7 代码分割

  • 将所有的代码全部打包到一个文件中运行是不合理的,webpack将代码分割成许多代码块(chunks),运行时在加载他们。

    1.7.1 动态导入和懒加载

  • 给单页面做按需加载优化的时候一般采用的原则:

    • 对网站的功能划分,一个类一个chunk
    • 对于首次打开页面的功能直接加载
    • 分割出去的模块需要一个加载的时机
  • 按需加载对应chunk的名称

    • import(/* webpackChunkName: "title" */ "./components/Title")

      1.7.2 预加载(preload)

  • preload通常用于本页面要用到的关键资源,包括关键js、字体、css文件

  • preload将会把资源得下载顺序权重提高,使得关键数据提前下载好,优化页面打开速度
  • 在资源上添加预先加载的注释,你指明该模块需要立即被使用

    1. import(
    2. `./utils.js`
    3. /* webpackPreload: true */
    4. /* webpackChunkName: "utils" */
    5. )

    1.7.3 预拉起(prefetch)

  • 它的作用是告诉浏览器未来可能会使用到的某个资源,浏览器就会在闲时去加载对应的资源,若能预测到用户的行为,比如懒加载,点击到其它页面等则相当于提前预加载了需要的资源

    1. import(
    2. `./utils.js`
    3. /* webpackPrefetch: true */
    4. /* webpackChunkName: "utils" */
    5. ).then(result => {
    6. result.default.log('hello');
    7. })

    1.7.4 splitChunks

  • module js的模块化webpack支持commonJS、ES6等模块化规范,简单来说就是你通过import语句引入的代码

  • chunk 根据功能拆分的代码块,分为三种
    • 入口代码
    • import动态导入代码
    • splitChunks拆分的代码
  • bundle是打包之后的文件,一般就是和chunk是一对一的关系,bundle就是对chunk进行编译压缩打包等处理之后的产出

    1. splitChunks: {
    2. chunks: "all", //默认作用于异步chunk,值为all/initial/async
    3. minSize: 0, //默认值是30kb,代码块的最小尺寸
    4. minChunks: 1, //被多少模块共享,在分割之前模块的被引用次数
    5. maxAsyncRequests: 2, //限制异步模块内部的并行最大请求数的,说白了你可以理解为是每个import()它里面的最大并行请求数量
    6. maxInitialRequests: 4, //限制入口的拆分数量
    7. name: true, //打包后的名称,默认是chunk的名字通过分隔符(默认是~)分隔开,如vendor~
    8. automaticNameDelimiter: "~", //默认webpack将会使用入口名和代码块的名称生成命名,比如 'vendors~main.js'
    9. cacheGroups: {
    10. //设置缓存组用来抽取满足不同规则的chunk,下面以生成common为例
    11. vendors: {
    12. chunks: "all",
    13. test: /node_modules/, //条件
    14. priority: -10, ///优先级,一个chunk很可能满足多个缓存组,会被抽取到优先级高的缓存组中,为了能够让自定义缓存组有更高的优先级(默认0),默认缓存组的priority属性为负值.
    15. },
    16. commons: {
    17. chunks: "all",
    18. minSize: 0, //最小提取字节数
    19. minChunks: 2, //最少被几个chunk引用
    20. priority: -20
    21. }
    22. }
    23. }

    1.8 CDN

  • CND又叫内容分发网络,把资源分布到世界各地,从最近的地方取资源,从而加快获取速度。CDN作用加速网络传输

  • 可以在 http 响应头加上 Cache-control 或 Expires 字段来设置缓存,浏览器可以将这些资源一一缓存到本地
  • 后续访问的时候,如果需要再次请求同样的静态资源,且静态资源没有过期,那么浏览器可以直接走本地缓存而不用再通过网络请求资源
  • 缓存配置
    • HTML文件不缓存,放在自己的服务器上,关闭自己服务器的缓存,静态资源的URL变成指向CDN服务器的地址,并且文件名带上HASH值
    • 为了并行加载不阻塞,把不同的静态资源分配到不同的CDN服务器上
  • 域名限制
    • 同一时刻一个域名的资源并行请求是有限制的
    • 可以把这些静态资源分散到不同的 CDN 服务上去
    • 多个域名后会增加域名解析时间
    • 可以通过在 HTML HEAD 标签中 加入去预解析域名,以降低域名解析带来的延迟

      2.如何提高webpack的构建速度

      2.1 缩小范围

      2.1 noParse

      2.1 IgnorePlugin

      2.1 DLL

      2.1 利用缓存

      2.1 多进程处理