Rspack 性能优化实战:JS/CSS 压缩 + 代码分割,让产物体积直降 40%

在前端项目上线前,「构建优化」是绕不开的环节 ------ 既要保证代码压缩到最小体积(提升加载速度),又要通过代码分割减少重复代码(降低缓存失效成本)。

Rspack 作为下一代打包工具,内置了两套核心优化工具:SwcJsMinimizerRspackPlugin(基于 Rust 的 JS 压缩器,速度远超 Terser)和 LightningCssMinimizerRspackPlugin(高性能 CSS 压缩器),再配合 splitChunks 代码分割,能轻松实现 "快构建 + 小体积"。本文就带你逐行拆解这套优化配置,学完直接复用。

一、先理清优化核心:这 3 个配置解决什么问题?

在看具体代码前,先明确优化目标 ------ 避免 "为了优化而优化",每一项配置都要对应实际问题:

  1. JS 压缩 :用 SwcJsMinimizerRspackPlugin 替代传统 Terser,在压缩 JS 时移除无用代码、console/debugger,同时兼容 ES5(支持旧浏览器);
  2. CSS 压缩 :用 LightningCssMinimizerRspackPlugin 压缩 CSS,自动处理前缀兼容,比 cssnano 更快;
  3. 代码分割 :用 splitChunks 将第三方库(如 Vue/React)、公共代码拆分成独立 chunk,实现 "一次加载、多次复用",减少重复加载体积。

二、核心配置拆解:从 JS 压缩到代码分割

第一步:全局优化开关 optimization

整个优化逻辑都在 optimization 配置项中,先看整体结构,再逐模块拆解:

java 复制代码
// rspack.config.js
const rspack = require('@rspack/core'); // 引入 Rspack 核心

module.exports = {
  // 其他基础配置(入口、出口、loader 等)...
  optimization: {
    // 1. 全局开启压缩(生产环境必须设为 true,开发环境建议 false 提速)
    minimize: true,

    // 2. 配置具体的压缩器(JS + CSS)
    minimizer: [/* 下文详细拆解 */],

    // 3. 代码分割规则(拆分第三方库、公共代码)
    splitChunks: {/* 下文详细拆解 */},

    // 4. 提取 runtime 代码(避免缓存失效问题)
    runtimeChunk: { name: 'runtime' }
  }
};

⚠️ 注意:minimize: true 仅建议在生产环境开启!开发环境开启压缩会大幅拖慢构建速度,且不利于调试(代码被混淆)。

第二步:JS 压缩配置 SwcJsMinimizerRspackPlugin

这是 Rspack 内置的 JS 压缩插件,基于 SWC(Rust 编写),压缩速度是 Terser 的 5-10 倍,同时支持精细化配置(如保留关键变量、移除 console 等):

javascript 复制代码
// 接上面的 optimization.minimizer
minimizer: [
  // 1. JS 压缩器:SwcJsMinimizerRspackPlugin
  new rspack.SwcJsMinimizerRspackPlugin({
    // 规则:不压缩 .xlsx 相关的 JS 文件(按需配置,比如 xlsx 库压缩后可能报错)
    test: /^(?!.*xlsx).*\.js$/,

    // JS 压缩的核心配置
    minimizerOptions: {
      // jsc:控制 JS 语法处理
      jsc: {
        // 输出 ES5 兼容代码(关键!支持 IE 11 等旧浏览器,避免箭头函数、let 等语法报错)
        target: 'es5'
      },

      // compress:代码压缩优化(最核心的体积优化项)
      compress: {
        drop_console: true,    // 移除所有 console 语句(线上无需调试日志)
        drop_debugger: true,   // 移除 debugger 语句(避免线上调试入口)
        passes: 2,             // 压缩次数:2 次(比默认 1 次压缩更彻底,体积更小)
        keep_infinity: true,   // 保留 Infinity(避免压缩后变成 1/0,部分场景报错)
        comparisons: false,    // 禁用比较优化(如 a <= b 不转成 a < b || a === b,兼容旧浏览器)
        pure_funcs: [],        // 标记"无副作用"的函数(如 lodash 的 noop,可安全移除)
        
        // --- 强力推荐配置:进一步减小体积 ---
        unused: true,          // 移除未使用的变量/函数(比如定义了但没调用的函数)
        dead_code: true,       // 移除死代码(比如 if(false) 里的代码)
        evaluate: true,        // 编译时计算常量(比如 1+2 直接转成 3)
        join_vars: true,       // 合并 var 声明(比如 var a=1;var b=2 → var a=1,b=2)
        properties: true,      // 优化属性访问(比如 obj['name'] → obj.name)
        side_effects: true     // 移除无副作用的代码(比如单独的 var a=3; 且没被使用)
      },

      // mangle:变量名混淆(减小体积,但需保留关键变量避免报错)
      mangle: {
        // 保留不被混淆的变量名(比如 Vue 的 _c/_v 等渲染函数,混淆后会报错)
        reserved: ['$', 'exports', 'require', '_c', '_v', '_s', '_e'],
        keep_fnames: false     // 不保留函数名(true 则保留,体积会大一点,但便于调试)
      },

      // format:输出格式控制
      format: {
        comments: false,       // 移除所有注释(注释不影响运行,纯占体积)
        ascii_only: true       // 强制输出 ASCII 字符(避免中文等非 ASCII 字符转义后体积变大)
      }
    }
  }),

  // 2. CSS 压缩器:LightningCssMinimizerRspackPlugin(下文拆解)
  new rspack.LightningCssMinimizerRspackPlugin({/* ... */})
]

关键配置避坑(线上报错高频点):

  • test: /^(?!.*xlsx).*\.js$/

    必须排除特殊库(如 xlsx、pdfjs)!这类库的源码可能包含特殊语法,压缩后会导致功能失效(比如 xlsx 的二进制处理逻辑被破坏),需要根据项目依赖调整排除规则。

  • mangle.reserved

    一定要保留框架 / 库的关键变量!比如 Vue 的 _c(创建元素)、_v(创建文本节点),React 的 React 等,混淆后会导致渲染报错 ------ 如果用了其他框架,需追加对应变量名。

  • jsc.target: 'es5'

    若项目需要支持 IE 11,必须设为 es5;若只支持现代浏览器(Chrome 60+、Safari 14+),可设为 es2015,压缩后体积更小(无需转译箭头函数、let 等)。

第三步:CSS 压缩配置 LightningCssMinimizerRspackPlugin

这是 Rspack 推荐的 CSS 压缩器,基于 Lightning CSS(Rust 编写),比传统的 css-minimizer-webpack-plugin 快 10 倍以上,还能自动处理浏览器前缀:

php 复制代码
// 接上面的 minimizer 数组
new rspack.LightningCssMinimizerRspackPlugin({
  minimizerOptions: {
    // 兼容目标:defaults(自动读取 .browserslistrc 配置,无需重复写 targets)
    targets: 'defaults'
  }
})

配置解读:

  • targets: 'defaults'

    无需手动写浏览器兼容列表!Lightning CSS 会自动读取项目根目录的 .browserslistrc(比如之前配置的 ie >= 11> 1%),自动添加所需的 CSS 前缀(如 -ms--webkit-),避免重复配置。

  • 额外优化(可选)

    若需要更精细控制(如移除 unused CSS),可添加 drafts: { unusedSymbols: true },但需注意:移除 unused CSS 可能误删动态使用的样式(如 document.styleSheets 操作的样式),需测试后启用:

    minimizerOptions: { targets: 'defaults', drafts: { unusedSymbols: true } // 移除未使用的 CSS 选择器(谨慎启用) }

第四步:代码分割 splitChunks + runtimeChunk

代码分割是 "减少重复加载" 的核心 ------ 把第三方库、公共代码拆分成独立 chunk,用户首次加载后,后续页面可复用缓存,无需重复下载:

javascript 复制代码
// 接上面的 optimization
splitChunks: {
  chunks: 'all',               // 分割所有类型的 chunk(initial 初始 chunk、async 异步 chunk)
  maxSize: 244 * 1024,         // 单个 chunk 最大体积:244KB(超过则自动拆分,避免单个文件过大)
  minSize: 30 * 1024,          // 单个 chunk 最小体积:30KB(小于则不拆分,避免太多小文件)
  
  // 缓存组:按规则拆分不同类型的代码
  cacheGroups: {
    // 1. 第三方库缓存组(node_modules 里的代码)
    vendors: {
      test: /[\\/]node_modules[\\/]/, // 匹配 node_modules 目录下的文件
      name: 'chunk-vendors',          // 拆分后的 chunk 名:chunk-vendors.js
      priority: -10,                  // 优先级:-10(比 common 高,先匹配 vendors)
      chunks: 'all'                   // 分割所有类型的 chunks
    },

    // 2. 公共代码缓存组(项目内被多次引用的代码)
    common: {
      name: 'chunk-common',           // 拆分后的 chunk 名:chunk-common.js
      minChunks: 2,                   // 最小引用次数:2 次(被 2 个及以上文件引用才拆分)
      priority: -20,                  // 优先级:-20(低于 vendors,避免公共代码被归为 vendors)
      reuseExistingChunk: true,       // 复用已存在的 chunk(比如 A 引用 B,B 已拆分成 chunk,则 A 直接复用)
      chunks: 'all'
    }
  }
},

// 提取 runtime 代码(关键!避免缓存失效)
runtimeChunk: {
  name: 'runtime' // 把 webpack/rspack 的运行时代码(如模块映射关系)拆成独立 chunk
}

代码分割核心逻辑(为什么要这么拆):

  1. chunk-vendors

    第三方库(如 Vue、lodash、axios)更新频率低,拆成独立 chunk 后,用户首次加载后会缓存,后续项目业务代码更新时,chunk-vendors 不会重新下载,减少加载体积。

  2. chunk-common

    项目内的公共代码(如 utils 工具函数、公共组件)被多次引用,拆分成独立 chunk 后,避免在多个业务 chunk 中重复打包,减少整体体积。

  3. runtime chunk

    运行时代码包含 "模块映射关系"(比如哪个模块对应哪个文件),如果不提取,每次业务代码更新时,运行时代码也会跟着变,导致 chunk-vendors 等缓存失效 ------ 提取后,runtime 体积很小(几十 KB),且只有当模块映射关系变化时才会更新。

三、验证优化效果:3 个维度检查

配置完成后,执行生产构建命令(pnpm run build),通过以下 3 个维度验证优化是否生效:

1. 查看产物体积变化

对比优化前后的 dist 目录总大小:

  • JS 压缩:通常能减少 30%-50% 体积(比如 1MB 的 JS 压缩后变成 500KB 左右);
  • CSS 压缩:通常能减少 20%-40% 体积(比如 200KB 的 CSS 压缩后变成 120KB 左右);
  • 代码分割:拆分出 chunk-vendors.jschunk-common.jsruntime.js,且单个 chunk 体积不超过 244KB(符合 maxSize 配置)。

2. 检查 JS 压缩效果

打开 dist/js 目录下的压缩文件,确认:

  • console.logdebugger 语句(drop_console/drop_debugger 生效);
  • 变量名被混淆(如 userName 变成 a,但 $_c 等保留变量未被混淆);
  • 无注释(format.comments: false 生效)。

3. 检查 CSS 压缩效果

打开 dist/css 目录下的压缩文件,确认:

  • 空格、换行被移除(压缩生效);
  • 自动添加了浏览器前缀(如 -ms-flex-webkit-box,对应 .browserslistrc 配置);
  • 无未使用的 CSS 选择器(若启用了 unusedSymbols)。

四、进阶优化建议:根据项目调整

1. 异步 chunk 优化

如果项目用了动态导入(import('xxx')),可在 splitChunks 中添加异步 chunk 专属配置,进一步拆分:

javascript 复制代码
splitChunks: {
  // 原有配置...
  cacheGroups: {
    // 原有配置...
    // 新增:异步 chunk 缓存组(比如路由组件)
    async: {
      name: 'chunk-async',
      test: /[\\/]src[\\/]views[\\/]/, // 匹配路由视图组件
      minChunks: 1,
      priority: -15,
      chunks: 'async' // 只处理异步 chunk
    }
  }
}

2. 控制 chunk-vendors 体积

如果 chunk-vendors 体积过大(比如超过 1MB),可拆分大型第三方库(如 xlsx、echarts):

javascript 复制代码
splitChunks: {
  // 原有配置...
  cacheGroups: {
    vendors: {
      // 原有配置...
      // 拆分大型库:把 xlsx 单独拆成 chunk
      test: [/[\\/]node_modules[\\/]/, /[\\/]node_modules[\\/]xlsx[\\/]/],
      name(module) {
        // 对 xlsx 单独命名,其他第三方库归为 chunk-vendors
        const match = module.resource.match(/[\\/]node_modules[\\/](xlsx)[\\/]/);
        return match ? `chunk-${match[1]}` : 'chunk-vendors';
      }
    }
  }
}

3. 开发环境关闭优化

rspack.config.js 中根据环境动态控制 minimize,避免开发环境变慢:

arduino 复制代码
optimization: {
  // 开发环境关闭压缩,生产环境开启
  minimize: process.env.NODE_ENV === 'production',
  // 其他配置...
}

总结

Rspack 的优化配置核心是「用 Rust 工具提速 」和「精细化拆分代码」,这套配置可直接复用,关键总结为 3 点:

  1. JS 压缩:用 SwcJsMinimizerRspackPlugin,重点配置 compress 移除无用代码、mangle 保留关键变量、jsc.target 保证兼容;
  2. CSS 压缩:用 LightningCssMinimizerRspackPlugin,依赖 .browserslistrc 自动兼容,无需重复配置;
  3. 代码分割:用 splitChunks 拆分第三方库和公共代码,用 runtimeChunk 保护缓存,避免失效。

相比 Webpack 传统优化方案,这套配置的构建速度能提升 5-10 倍,产物体积能减少 30%-50%,且无需额外安装大量依赖(Rspack 内置核心插件)。

你在 Rspack 优化中还遇到过哪些问题?比如大型库拆分、异步 chunk 体积控制等,欢迎在评论区分享你的解决方案~

相关推荐
恋猫de小郭18 小时前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅1 天前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60611 天前
完成前端时间处理的另一块版图
前端·github·web components
掘了1 天前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅1 天前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅1 天前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅1 天前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment1 天前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅1 天前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊1 天前
jwt介绍
前端