如何利用 `Vite` 和 `Rollup` 的配置,实现一个高度优化的生产环境打包方案?

各位观众老爷,晚上好!我是你们的老朋友——bug制造机(不是),今天咱们来聊聊怎么用Vite和Rollup这哥俩,打造一个高效到飞起的生产环境打包方案。

别怕,我保证用最接地气的方式,把这些复杂的配置给你们掰开了揉碎了讲明白。咱们的目标是:让打包速度快如闪电,体积小到可以塞进U盘里,性能好到让用户怀疑人生(怀疑人生级的好!)。

第一章:Vite打头阵,Rollup殿后,双剑合璧,天下我有!

Vite,这小伙子,是开发阶段的香饽饽,速度快、热更新丝滑。但直接拿Vite打包生产环境?嗯…也不是不行,就是可能某些高级优化上差点意思。这时候,Rollup大哥就该登场了。

我们的策略是:Vite负责快速构建,Rollup负责深度优化。Vite负责“搭架子”,Rollup负责“精装修”。

第二章:Vite配置:快速通道,先跑起来再说!

首先,我们需要一个 vite.config.js (或者 .ts,看你心情)。

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react'; // 如果你用React
import legacy from '@vitejs/plugin-legacy'; // 兼容老浏览器

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react(),
    legacy({
      targets: ['defaults', 'not IE 11'], // 兼容目标浏览器
    }),
  ],
  build: {
    // 默认的构建目标是 'modules',支持原生 ES 模块
    // 如果需要兼容更老的浏览器,可以设置为 'esnext',然后配合 legacy 插件
    target: 'modules',
    outDir: 'dist', // 输出目录
    assetsDir: 'assets', // 静态资源目录
    sourcemap: true, // 生成 sourcemap,方便调试
    minify: 'terser', // 压缩代码,可选 'terser' | 'esbuild' | false
    rollupOptions: {
      // Rollup 配置,这里先留空,后面Rollup大哥会接管
    },
    chunkSizeWarningLimit: 500, // chunk 大小警告限制 (kb)
  },
  resolve: {
    alias: {
      '@': '/src', // 路径别名,方便导入模块
    },
  },
  server: {
    port: 3000, // 开发服务器端口
    open: true, // 自动打开浏览器
  },
});

这段配置,基本上涵盖了Vite的常用选项:

  • plugins: 用了@vitejs/plugin-react处理React代码,@vitejs/plugin-legacy 搞定老浏览器的兼容问题。
  • build: 指定了构建目标、输出目录、是否生成sourcemap、代码压缩方式等等。 rollupOptions 是重点,这里先空着,等Rollup来填。
  • resolve.alias: 设置路径别名,省得写一堆 ../../../
  • server: 配置开发服务器。

第三章:Rollup配置:精雕细琢,榨干每一滴性能!

接下来,我们需要一个 rollup.config.js (或者 .ts,你说了算)。 这个文件,将接管Vite的 rollupOptions,进行更深度的优化。

import { defineConfig } from 'rollup';
import terser from '@rollup/plugin-terser'; // 代码压缩
import commonjs from '@rollup/plugin-commonjs'; // 处理 CommonJS 模块
import resolve from '@rollup/plugin-node-resolve'; // 解析 node_modules 中的模块
import json from '@rollup/plugin-json'; // 处理 JSON 文件
import replace from '@rollup/plugin-replace'; // 替换代码中的变量
import analyze from 'rollup-plugin-analyzer'; // 打包分析

export default defineConfig({
  input: 'dist/assets/index.*.js', // Vite构建后的入口文件
  output: {
    dir: 'dist', // 输出目录,和Vite保持一致
    format: 'es', // 输出格式,ES模块
    sourcemap: true, // 生成 sourcemap
    chunkFileNames: 'assets/[name]-[hash].js', // chunk 文件名格式
    assetFileNames: 'assets/[name]-[hash][extname]', // 资源文件名格式
  },
  plugins: [
    resolve(), // 解析 node_modules
    commonjs(), // 处理 CommonJS 模块
    json(), // 处理 JSON 文件
    replace({
      'process.env.NODE_ENV': JSON.stringify('production'), // 替换环境变量
      preventAssignment: true,
    }),
    terser(), // 压缩代码
    analyze({
      summaryOnly: true, // 只显示摘要信息
    }),
  ],
  // 手动指定需要保留的模块,防止被 tree-shaking 掉
  // preserveModules: true, // 保留模块结构,一般不用
});

这段配置,才是真正的大杀器:

  • input: Vite 构建后的入口文件,需要根据Vite的输出目录和文件名规则来确定。
  • output: 输出目录、格式、sourcemap、文件名格式等等。
  • plugins: 各种Rollup插件,是优化的关键:
    • @rollup/plugin-node-resolve: 解析 node_modules 里的模块。
    • @rollup/plugin-commonjs: 把 CommonJS 模块转换成 ES 模块。
    • @rollup/plugin-json: 处理 JSON 文件。
    • @rollup/plugin-replace: 替换代码中的变量,比如把 process.env.NODE_ENV 替换成 production
    • @rollup/plugin-terser: 压缩代码,效果比Vite自带的 terser 更强大。
    • rollup-plugin-analyzer: 打包分析工具,可以帮你找到打包体积的瓶颈。
  • preserveModules: 一般不用,除非你有特殊的模块结构需求。

第四章:Vite + Rollup 联动:让它们愉快地玩耍!

现在,我们需要把 rollup.config.js 里的配置,塞到 vite.config.jsrollupOptions 里。

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import legacy from '@vitejs/plugin-legacy';
import { terser } from 'rollup-plugin-terser'; // 直接引入 Rollup 插件

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react(),
    legacy({
      targets: ['defaults', 'not IE 11'],
    }),
  ],
  build: {
    target: 'modules',
    outDir: 'dist',
    assetsDir: 'assets',
    sourcemap: true,
    minify: 'terser',
    rollupOptions: {
      input: 'dist/assets/index.*.js', // Vite构建后的入口文件
      output: {
        dir: 'dist',
        format: 'es',
        sourcemap: true,
        chunkFileNames: 'assets/[name]-[hash].js',
        assetFileNames: 'assets/[name]-[hash][extname]',
      },
      plugins: [
        {
          ...terser(),
          apply: 'build', // 只在构建时应用
        },
      ],
    },
    chunkSizeWarningLimit: 500,
  },
  resolve: {
    alias: {
      '@': '/src',
    },
  },
  server: {
    port: 3000,
    open: true,
  },
});

注意几个关键点:

  1. input: Rollup 的入口文件,必须是 Vite 构建后的文件。
  2. output: Rollup 的输出配置,要和 Vite 保持一致。
  3. plugins: Rollup 的插件,要放在 rollupOptions.plugins 里面。
  4. apply: 'build': 有些 Rollup 插件,只需要在构建时应用,比如 terser。 这样可以避免在开发环境引入额外的开销。

现在,当你运行 vite build 命令时,Vite 会先进行快速构建,然后 Rollup 会接管,进行深度优化。

第五章:高级优化技巧:让你的代码瘦成一道闪电!

光有基础配置还不够,想要打造极致的打包方案,还需要一些高级技巧:

  • 代码分割 (Code Splitting):Vite 和 Rollup 都支持代码分割,可以把你的代码分成多个 chunk,按需加载。 这可以大大减少首屏加载时间。 Vite 默认会根据ES模块的 import 语句自动进行代码分割。你也可以通过动态 import() 语句手动进行代码分割。

  • Tree Shaking: Vite 和 Rollup 都支持 Tree Shaking,可以移除未使用的代码。 确保你的代码是 ES 模块,并且没有副作用,这样 Tree Shaking 才能发挥最大的效果。

  • 图片优化: 使用 vite-plugin-imagemin 插件,可以自动压缩图片,减小图片体积。

    npm install vite-plugin-imagemin -D

    然后在 vite.config.js 中配置:

    import imagemin from 'vite-plugin-imagemin';
    
    export default defineConfig({
      plugins: [
        // ...其他插件
        imagemin({
          gifsicle: { optimizationLevel: 7, interlaced: false },
          optipng: { optimizationLevel: 7 },
          mozjpeg: { quality: 20 },
          pngquant: { quality: [0.8, 0.9], speed: 4 },
          webp: { quality: 75 },
        }),
      ],
    });
  • Gzip/Brotli 压缩: 在服务器端启用 Gzip 或 Brotli 压缩,可以进一步减小传输体积。 现在很多 CDN 都支持自动 Gzip/Brotli 压缩。

  • CDN 加速: 把静态资源放到 CDN 上,可以利用 CDN 的缓存和加速能力,提高加载速度。

  • 预加载 (Preload) 和 预取 (Prefetch):使用 <link rel="preload"><link rel="prefetch"> 标签,可以提前加载关键资源,提高页面性能。

第六章:实战案例:一个React项目的打包优化

假设我们有一个简单的React项目,目录结构如下:

my-react-app/
├── index.html
├── src/
│   ├── App.jsx
│   ├── components/
│   │   ├── Button.jsx
│   │   ├── Header.jsx
│   ├── assets/
│   │   ├── logo.png
│   ├── utils/
│   │   ├── api.js
├── vite.config.js
├── package.json

我们的目标是:

  1. 打包速度快
  2. 体积小
  3. 兼容主流浏览器

vite.config.js:

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import legacy from '@vitejs/plugin-legacy';
import { terser } from 'rollup-plugin-terser';
import imagemin from 'vite-plugin-imagemin';

export default defineConfig({
  plugins: [
    react(),
    legacy({
      targets: ['defaults', 'not IE 11'],
    }),
    imagemin({
      gifsicle: { optimizationLevel: 7, interlaced: false },
      optipng: { optimizationLevel: 7 },
      mozjpeg: { quality: 20 },
      pngquant: { quality: [0.8, 0.9], speed: 4 },
      webp: { quality: 75 },
    }),
  ],
  build: {
    target: 'modules',
    outDir: 'dist',
    assetsDir: 'assets',
    sourcemap: true,
    minify: false, // 禁用 Vite 的压缩,交给 Rollup
    rollupOptions: {
      input: 'dist/assets/index.*.js',
      output: {
        dir: 'dist',
        format: 'es',
        sourcemap: true,
        chunkFileNames: 'assets/[name]-[hash].js',
        assetFileNames: 'assets/[name]-[hash][extname]',
      },
      plugins: [
        {
          ...terser(),
          apply: 'build',
        },
      ],
    },
    chunkSizeWarningLimit: 500,
  },
  resolve: {
    alias: {
      '@': '/src',
    },
  },
  server: {
    port: 3000,
    open: true,
  },
});

这个配置,结合了 Vite 的快速构建和 Rollup 的深度优化,使用了代码分割、Tree Shaking、图片优化等技巧。 最终的打包结果,应该会非常出色。

第七章:总结:打造完美打包方案的秘诀!

想要打造一个完美的生产环境打包方案,需要考虑以下几个方面:

方面 策略
打包速度 利用 Vite 的快速构建能力,尽量减少不必要的插件和转换。
体积 使用 Rollup 进行深度优化,包括代码压缩、Tree Shaking、代码分割、图片优化等。
性能 合理使用预加载和预取,利用 CDN 加速静态资源,在服务器端启用 Gzip/Brotli 压缩。
兼容性 使用 @vitejs/plugin-legacy 插件,兼容老浏览器。
可维护性 保持配置文件的简洁和清晰,使用模块化的代码结构,方便后续维护和升级。
监控 使用 rollup-plugin-analyzer 插件,监控打包体积,及时发现和解决问题。

记住,没有一劳永逸的打包方案。 随着项目的发展和技术的进步,你需要不断地调整和优化你的打包配置。

好了,今天的讲座就到这里。 希望大家都能打造出自己的完美打包方案! 下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注