性能优化 - 构建效率优化

主要优化方向

  • 提高构建效率:指从源代码到最终产物的转换速度,包括编译、打包、优化等环节的耗时。
  • 添加构建缓存:通过缓存编译结果,避免重复编译未变更的文件,大幅提升二次构建速度。
  • 缩小文件搜索范围 :通过配置 include/exclude 限制 loader 处理的文件范围,减少不必要的文件扫描。

1. 编译速度优化

SWC(Speedy Web Compiler) :基于 Rust 编写的编译器,编译速度比 Babel 快 10-70 倍。SWC 常用于替代 Babel 以提升编译性能,在 Vite 的 React 项目中可通过 @vitejs/plugin-react-swc 启用。

  • 编译速度快:基于 Rust 编写,性能远超 JavaScript 实现的 Babel。
  • 功能完整:支持 ES6+、TypeScript、JSX 等语法转换。
  • 兼容性好:大多数语法转换场景下可以替代 Babel,如果依赖 Babel 插件生态实现复杂转换,则还是需要 Babel 支持。

在基于 Vue-Cli5 的项目测试中,使用 Babel 的构建时间约 40s,使用 SWC 的构建时间约为 22s,提升了约 45%。

另一种是采用基于 Go 编写的 ESBuild 优化编译速度

Vue-cli 配置

javascript 复制代码
// vue.config.js
// 安装:npm install @swc/core swc-loader -D
module.exports = {
  chainWebpack: (config) => {
    // 移除旧 babel-loader 编译
    config.module.rules.delete("js");

    // 用 SWC 处理 JS/JSX 文件
    config.module
      .rule("js")
      .test(/\.(js|jsx)$/) // 匹配 .js 和 .jsx 文件
      .exclude.add(/node_modules/) // 排除 node_modules
      .end()
      .use("swc-loader")
      .loader("swc-loader")
      .options({
        jsc: {
          parser: {
            syntax: "ecmascript", // 解析 ECMAScript 语法
            jsx: true, // 支持 JSX(不影响 Vue)
            dynamicImport: true, // 支持动态导入
          },
          target: "es2015", // 转译为 ES6 语法
        },
        sourceMap: process.env.NODE_ENV === "development", // 开发环境生成 SourceMap
      });

    // 如果项目使用 TypeScript,再添加 TS 处理(没有则删除这部分)
    if (config.module.rules.has("ts")) {
      config.module.rules.delete("ts");
      config.module
        .rule("ts")
        .test(/\.(ts|tsx)$/) // 匹配 .ts 和 .tsx 文件
        .exclude.add(/node_modules/)
        .end()
        .use("swc-loader")
        .loader("swc-loader")
        .options({
          jsc: {
            parser: {
              syntax: "typescript", // 解析 TypeScript 语法
              tsx: true, // 支持 TSX
            },
            target: "es2015",
          },
          sourceMap: process.env.NODE_ENV === "development",
        });
    }
  },
};

2. 构建结果缓存

通过缓存编译结果,避免重复编译未变更的文件,可以大幅提升二次构建的速度。

工作原理

  1. 首次构建时,编译所有文件,将结果缓存到磁盘。
  2. 二次构建时,检查文件是否变更,未变更的文件直接使用缓存结果。
  3. 当文件内容或配置变更时,会自动使对应缓存失效,重新构建。

Vue-cli 配置(Webpack 4) :手动使用 cache-loader 实现缓存,需要手动配置。

cache-loader 主要用于 Webpack 4,在 Webpack 5 中已不再推荐使用。

javascript 复制代码
// Webpack 4 - cache-loader 配置
// vue.config.js
// 安装:npm install cache-loader -D

module.exports = {
  chainWebpack: (config) => {
    // 为 babel-loader 添加缓存
    // 注意:cache-loader 必须放在其他 loader 之前
    config.module
      .rule("js")
      .test(/\.js$/) // 匹配 .js 文件
      .exclude.add(/node_modules/) // 排除 node_modules
      .end()
      .use("cache-loader") // 先使用 cache-loader
      .loader("cache-loader")
      .options({
        cacheDirectory: ".cache/babel-loader", // 缓存目录
      })
      .end()
      .use("babel-loader") // 再使用 babel-loader
      .loader("babel-loader");

    // 为 CSS 处理添加缓存
    config.module
      .rule("css")
      .test(/\.css$/) // 匹配 .css 文件
      .use("cache-loader")
      .loader("cache-loader")
      .options({
        cacheDirectory: ".cache/css-loader", // 缓存目录
      })
      .end()
      .use("css-loader")
      .loader("css-loader");
  },
};

Vue-cli 配置(Webpack 5):内置持久化缓存机制,默认启用,无需额外配置。

javascript 复制代码
// Webpack 5 - 内置缓存配置
// vue.config.js

const path = require("path");

module.exports = {
  configureWebpack: {
    cache: {
      type: "filesystem", // 使用文件系统缓存(默认是 memory 内存缓存,重启后失效)
      buildDependencies: {
        config: [__filename], // 当配置文件变更时,使缓存失效
      },
      cacheDirectory: path.resolve(__dirname, ".cache/webpack"), // 缓存目录
      compression: "gzip", // 压缩缓存文件,支持 gzip 和 brotli,开发环境默认关闭
      maxAge: 1000 * 60 * 60 * 24 * 7, // 缓存有效期 7 天(毫秒,默认 1 个月)
    },
  },
};

Vite :默认启用文件系统缓存,缓存位置在 node_modules/.vite 目录中。如果代码修改后发现未更新,可以删除该目录来清除缓存。

javascript 复制代码
// vite.config.js(Vite 内置缓存)
import { defineConfig } from "vite";

export default defineConfig({
  // Vite 默认启用文件系统缓存,无需额外配置
  // 缓存位置:node_modules/.vite
  // 开发环境:缓存预构建的依赖
  // 生产环境:缓存 Rollup 构建结果
  build: {
    // 生产构建缓存配置
    rollupOptions: {
      // Rollup 配置
    },
  },
});

3. 缩小文件搜索范围

通过 include/exclude 配置 loader 指向的范围空间,减少不必要的文件扫描,提升构建速度。

优化原理

  1. include:指定 loader 只处理特定目录的文件,避免扫描无关目录。
  2. exclude :排除不需要处理的目录(如 node_modules),减少文件扫描量。
  3. resolve 配置:配置模块解析路径和别名,减少路径解析时间。

Vue-cli 配置

javascript 复制代码
// vue.config.js
const path = require("path");

function resolve(dir) {
  return path.join(__dirname, dir);
}

module.exports = {
  chainWebpack: (config) => {
    // JS 文件处理
    config.module
      .rule("js")
      .test(/\.js$/)
      .include.add(resolve("src")) // 只在 src 文件夹下查找
      .end()
      .exclude.add(/node_modules/) // 排除 node_modules
      .end()
      .use("babel-loader")
      .loader("babel-loader");

    // TypeScript 文件处理
    config.module
      .rule("ts")
      .test(/\.ts$/)
      .include.add(resolve("src"))
      .end()
      .exclude.add(/node_modules/)
      .end()
      .use("ts-loader")
      .loader("ts-loader");
  },
};

Vite 配置

javascript 复制代码
// vite.config.js
import { defineConfig } from "vite";
import { resolve } from "path";

export default defineConfig({
  resolve: {
    alias: {
      "@": resolve(__dirname, "src"), // 配置别名,减少路径解析时间
    },
    // 指定文件扩展名解析顺序,按顺序尝试,找到即停止
    extensions: [".js", ".vue", ".json", ".ts"],
  },
  // Vite 会自动排除 node_modules,无需手动配置
});

4. 环境配置优化

使用 Vite 代替 Webpack

Vite:基于 ESM 的构建工具,编译功能依赖于 Rollup 和 ESBuild 完成,开发环境使用原生 ESM,生产环境使用 Rollup 打包,构建速度更快。

优势:

  • 依赖预构建:基于 ESBuild 预构建后无需重新打包,启动速度极快。
  • 动态导入机制
    • 传统打包方式是把所有文件编译后构建为 bundle,再启动 devServer 加载,这种模式导致冷启动和大项目下的构建成本较高。
    • Vite 依赖了 ES6 的 ESM 模块机制,Vite 在开发阶段基于浏览器原生 ESM 进行模块加载,按模块请求进行即时转译与返回,从而显著降低冷启动成本。
  • 缓存机制优化 :对于开发环境下的依赖模块采用 Cache-Control: max-age=31536000,immutable 进行强缓存,源码则根据 304 Not Modified 进行协商缓存。

关闭 source-map

source-map:用于开发环境调试,但会显著增加构建时间。生产环境建议关闭。

建议

  • 开发环境 :使用快速 source-map(如 eval-cheap-module-source-map)。
  • 生产环境:关闭 source-map,提升构建速度,同时避免源码结构暴露。

Vue-cli 配置

javascript 复制代码
// vue.config.js(Webpack)
module.exports = {
  productionSourceMap: false, // 关闭生产环境 source map
  configureWebpack: {
    devtool:
      process.env.NODE_ENV === "development"
        ? "eval-cheap-module-source-map"
        : false,
  },
};

Vite 配置

javascript 复制代码
// vite.config.js
import { defineConfig } from "vite";

export default defineConfig({
  build: {
    sourcemap: false, // 生产环境关闭 source map
  },
  // 开发环境默认启用 source map,无需配置
});

5. 构建结果分析

这块应该补充在构建体积优化,但感觉本质也是体积压缩也是效率优化的一类

通过 webpack-bundle-analyzer(Vue-Cli)/ rollup-plugin-visualizer(Vite、Rollup)输出生产结果统计,分析打包体积,找出优化点:

  • 被重复打包的组件和依赖/chunk 体积过大:通过异步组件/路由、splitChunk 抽离、webpackChunkName 进行优化。
  • 占用较大体积的三方插件:查看是否有 ESM 版本支持 Tree-Shaking,查找按需引入方案(搜索 babel import 或 auto import 关键词)。
  • 无需打包的模块:发现不用打包的依赖,分析其引入位置进行优化。

Vue-cli 配置

javascript 复制代码
// vue.config.js
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");

module.exports = {
  configureWebpack: {
    plugins: [
      // 配置环境变量,只在必要时开启
      process.env.ANALYZE &&
        new BundleAnalyzerPlugin({
          analyzerMode: "static", // 分析模式:server(启动分析服务,默认)、static(生成 HTML 报告)、json(生成 JSON 报告)
          openAnalyzer: false, // 不自动打开浏览器
          reportFilename: "bundle-report.html", // 报告文件名
          generateStatsFile: true, // 生成 stats.json
          statsFilename: "bundle-stats.json",
        }),
    ].filter(Boolean),
  },
};

Vite 配置:

javascript 复制代码
// vite.config.js(使用 rollup-plugin-visualizer)
import { defineConfig } from "vite";
import { visualizer } from "rollup-plugin-visualizer";

export default defineConfig({
  plugins: [
    visualizer({
      open: false, // 构建后自动打开报告
      filename: "dist/stats.html", // 报告输出路径
      gzipSize: true, // 显示 gzip 压缩后的大小
      brotliSize: true, // 显示 brotli 压缩后的大小
      template: "treemap", // 可选:sunburst、treemap、network
    }),
  ],
});

使用方式

json 复制代码
// package.json
{
  "scripts": {
    "analyze": "cross-env ANALYZE=true npm run build", // 分析打包体积
    "build": "vue-cli-service build" // 正常构建
  }
}

总结

  • 核心优化策略
    • 编译速度优化:使用 SWC 代替 Babel。
    • 构建结果缓存 :Webpack 5 内置缓存或使用 cache-loader
    • 缩小搜索范围 :通过 include/excluderesolve 配置。
    • 环境配置优化:使用 Vite 代替 Vue-Cli(Webpack)。
  • 注意事项
    • SWC 需要同时安装 @swc/coreswc-loader
    • Webpack 5 缓存默认启用,无需额外配置。
    • 生产环境务必关闭 source-map,提升构建速度和安全性。
    • 构建分析工具仅在需要时启用,避免影响正常构建速度。

参考内容

相关推荐
北岛寒沫6 小时前
北京大学国家发展研究院 经济学原理课程笔记(第十九课 长期经济增长)
经验分享·笔记·学习
OEC小胖胖6 小时前
02|从 `createRoot` 到 `scheduleUpdateOnFiber`:一次更新如何进入 React 引擎
前端·javascript·react.js·前端框架
山沐与山7 小时前
【Redis】读写锁实战详解:读多写少场景的性能优化利器
数据库·redis·性能优化
林太白7 小时前
ofd文件
前端·后端
ouliten7 小时前
vllm笔记(1):最基础的离线推理
笔记·vllm·模型推理
闲云一鹤7 小时前
Git 焚决!一个绝招助你找回丢失的代码文件!
前端·git
小宇的天下7 小时前
Calibre 3Dstack--每日一个命令day 6 [process和export layout](3-6)
java·前端·数据库
冴羽7 小时前
2025 年最火的前端项目出炉,No.1 易主!
前端·javascript·node.js
wtmReiner7 小时前
山东大学数值计算2026.1大三上期末考试回忆版
笔记·算法
wordbaby7 小时前
Flexbox 布局中的滚动失效问题:为什么需要 `min-h-0`?
前端·css