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 体积控制等,欢迎在评论区分享你的解决方案~

相关推荐
晚星star2 小时前
在 Web 前端实现流式 TTS 播放
前端·vue.js
huabuyu2 小时前
基于 Taro 的 Markdown AST 渲染器实现
前端
本末倒置1832 小时前
前端面试高频题:18个经典技术难点深度解析与解决方案
前端·vue.js·面试
狗头大军之江苏分军2 小时前
Meta万人裁员亲历者自述:小扎尝到了降本的甜头
前端·后端·github
秃顶老男孩.3 小时前
web中的循环遍历
开发语言·前端·javascript
快起来搬砖了3 小时前
实现一个优雅的城市选择器组件 - Uniapp实战
开发语言·javascript·uni-app
龙在天3 小时前
vue 请求接口快慢 覆盖 解决方案
前端
可子是我的小猫3 小时前
【JS】模块(一)
javascript
跟橙姐学代码3 小时前
Python 类的正确打开方式:从新手到进阶的第一步
前端·python·ipython