第262集:Vue 3 Rollup高级配置

概述

Rollup是Vite的底层构建工具,提供了强大的模块打包能力。Vue 3项目可以通过Rollup进行高级配置,实现代码分割、tree shaking、构建优化和多格式输出等功能。本集将深入探讨Vue 3 Rollup的高级配置,包括代码分割策略、tree shaking优化、构建性能优化、多格式输出配置以及与Vite的集成,帮助开发者掌握Rollup的高级用法,优化Vue 3项目的构建流程。

Rollup基础回顾

Rollup是一个JavaScript模块打包工具,它将小块代码编译成大块复杂的代码,如库或应用程序。Rollup的主要特点包括:

  • ES模块支持:原生支持ES模块
  • tree shaking:自动移除未使用的代码
  • 代码分割:支持动态导入和代码分割
  • 插件系统:丰富的插件生态
  • 多格式输出:支持多种输出格式

代码分割策略

代码分割是将代码库分割成多个较小的文件,以便按需加载,减少初始加载时间。Rollup支持多种代码分割策略:

1. 自动代码分割

Rollup会自动检测动态导入,将代码分割成多个块:

// rollup.config.js
export default {
  input: 'src/main.js',
  output: {
    dir: 'dist',
    format: 'esm',
    manualChunks: {
      // 手动配置代码分割
      vue: ['vue'],
      'vue-router': ['vue-router'],
      pinia: ['pinia']
    }
  }
}

2. 手动代码分割

使用manualChunks选项手动配置代码分割:

// rollup.config.js
export default {
  input: 'src/main.js',
  output: {
    dir: 'dist',
    format: 'esm',
    manualChunks: (id) => {
      // 根据文件路径手动分割代码
      if (id.includes('node_modules')) {
        if (id.includes('vue')) {
          return 'vue-vendor'
        } else if (id.includes('vue-router')) {
          return 'vue-router-vendor'
        } else if (id.includes('pinia')) {
          return 'pinia-vendor'
        } else {
          return 'other-vendors'
        }
      }
    }
  }
}

3. 动态导入

使用动态导入实现按需加载:

// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/',
      component: () => import('../views/Home.vue') // 动态导入
    },
    {
      path: '/about',
      component: () => import('../views/About.vue') // 动态导入
    }
  ]
})

4. 共享模块

Rollup会自动处理共享模块,避免重复打包:

// rollup.config.js
export default {
  input: 'src/main.js',
  output: {
    dir: 'dist',
    format: 'esm',
    // 配置共享模块
    manualChunks: {
      shared: ['lodash-es']
    }
  }
}

Tree Shaking优化

Tree shaking是Rollup的核心特性之一,它可以自动移除未使用的代码,减小打包体积。

1. 配置tree shaking

// rollup.config.js
export default {
  input: 'src/main.js',
  output: {
    dir: 'dist',
    format: 'esm'
  },
  // 启用tree shaking
  treeshake: {
    // 启用模块级别的tree shaking
    moduleSideEffects: false,
    // 启用函数级别的tree shaking
    propertyReadSideEffects: false
  }
}

2. 标记副作用

在package.json中使用sideEffects字段标记有副作用的文件:

// package.json
{
  "name": "my-vue-package",
  "sideEffects": [
    "*.css",
    "src/side-effectful-module.js"
  ]
}

3. 优化tree shaking

  • 使用ES模块语法
  • 避免使用require()module.exports
  • 避免使用动态导入中的变量
  • 使用/*#__PURE__*/标记纯函数调用

4. 验证tree shaking效果

使用rollup-plugin-visualizer插件查看tree shaking效果:

// rollup.config.js
import { visualizer } from 'rollup-plugin-visualizer'

export default {
  input: 'src/main.js',
  output: {
    dir: 'dist',
    format: 'esm'
  },
  plugins: [
    visualizer({
      open: true,
      gzipSize: true,
      brotliSize: true
    })
  ]
}

构建性能优化

1. 缓存机制

使用cache选项启用构建缓存:

// rollup.config.js
export default {
  input: 'src/main.js',
  output: {
    dir: 'dist',
    format: 'esm'
  },
  // 启用缓存
  cache: true
}

2. 并行构建

使用rollup-plugin-parallel插件实现并行构建:

// rollup.config.js
import parallel from 'rollup-plugin-parallel'

export default {
  input: 'src/main.js',
  output: {
    dir: 'dist',
    format: 'esm'
  },
  plugins: [
    parallel({
      // 配置并行构建选项
      watch: true
    })
  ]
}

3. 增量构建

使用rollup-plugin-incremental插件实现增量构建:

// rollup.config.js
import incremental from 'rollup-plugin-incremental'

export default {
  input: 'src/main.js',
  output: {
    dir: 'dist',
    format: 'esm'
  },
  plugins: [
    incremental()
  ]
}

4. 优化插件使用

  • 只在必要时使用插件
  • 了解插件的执行顺序
  • 避免在插件中执行耗时操作
  • 使用缓存优化插件性能

多格式输出配置

Rollup支持多种输出格式,包括ES模块、CommonJS、UMD等。

1. 基本多格式输出

// rollup.config.js
export default {
  input: 'src/main.js',
  output: [
    {
      file: 'dist/bundle.cjs.js',
      format: 'cjs'
    },
    {
      file: 'dist/bundle.esm.js',
      format: 'esm'
    },
    {
      file: 'dist/bundle.umd.js',
      format: 'umd',
      name: 'MyLibrary'
    }
  ]
}

2. 针对不同环境的输出

// rollup.config.js
export default {
  input: 'src/main.js',
  output: [
    {
      file: 'dist/bundle.development.js',
      format: 'umd',
      name: 'MyLibrary',
      sourcemap: true
    },
    {
      file: 'dist/bundle.production.js',
      format: 'umd',
      name: 'MyLibrary',
      plugins: [terser()]
    }
  ]
}

3. 多入口输出

// rollup.config.js
export default {
  input: {
    main: 'src/main.js',
    admin: 'src/admin.js'
  },
  output: {
    dir: 'dist',
    format: 'esm'
  }
}

Rollup与Vite集成

Vite基于Rollup,因此可以通过Vite配置文件配置Rollup选项。

1. 在Vite中配置Rollup

// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  build: {
    // Vite构建选项
    outDir: 'dist',
    sourcemap: true,
    // Rollup配置
    rollupOptions: {
      input: {
        main: 'index.html',
        admin: 'admin.html'
      },
      output: {
        manualChunks: {
          vue: ['vue'],
          'vue-router': ['vue-router'],
          pinia: ['pinia']
        }
      }
    }
  }
})

2. 在Vite中使用Rollup插件

// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
  plugins: [vue()],
  build: {
    rollupOptions: {
      plugins: [
        visualizer({
          open: true,
          gzipSize: true
        })
      ]
    }
  }
})

3. Vite中的Rollup钩子

在Vite插件中可以使用Rollup钩子:

// vite-plugin-custom.js
export default {
  name: 'vite-plugin-custom',
  // Rollup钩子
  transform(code, id) {
    if (id.endsWith('.vue')) {
      // 转换Vue文件
      return code
    }
    return code
  },
  // Vite特定钩子
  configureServer(server) {
    // 配置开发服务器
  }
}

Rollup高级插件

1. rollup-plugin-terser

用于压缩代码:

// rollup.config.js
import terser from '@rollup/plugin-terser'

export default {
  input: 'src/main.js',
  output: {
    file: 'dist/bundle.min.js',
    format: 'esm',
    plugins: [terser()]
  }
}

2. rollup-plugin-dynamic-import-variables

支持动态导入中的变量:

// rollup.config.js
import dynamicImportVariables from '@rollup/plugin-dynamic-import-variables'

export default {
  input: 'src/main.js',
  output: {
    dir: 'dist',
    format: 'esm'
  },
  plugins: [dynamicImportVariables()]
}

3. rollup-plugin-alias

用于路径别名配置:

// rollup.config.js
import alias from '@rollup/plugin-alias'

export default {
  input: 'src/main.js',
  output: {
    dir: 'dist',
    format: 'esm'
  },
  plugins: [
    alias({
      entries: [
        { find: '@', replacement: 'src' }
      ]
    })
  ]
}

4. rollup-plugin-replace

用于替换代码中的变量:

// rollup.config.js
import replace from '@rollup/plugin-replace'

export default {
  input: 'src/main.js',
  output: {
    dir: 'dist',
    format: 'esm'
  },
  plugins: [
    replace({
      __VERSION__: '1.0.0',
      __BUILD_TIME__: new Date().toISOString(),
      preventAssignment: true
    })
  ]
}

Rollup配置最佳实践

1. 分离开发和生产配置

// rollup.config.js
import { defineConfig } from 'rollup'
import vue from 'rollup-plugin-vue'
import terser from '@rollup/plugin-terser'

const baseConfig = {
  input: 'src/main.js',
  plugins: [vue()]
}

export default defineConfig([
  // 开发配置
  {
    ...baseConfig,
    output: {
      dir: 'dist/dev',
      format: 'esm',
      sourcemap: true
    }
  },
  // 生产配置
  {
    ...baseConfig,
    output: {
      dir: 'dist/prod',
      format: 'esm',
      plugins: [terser()]
    }
  }
])

2. 使用配置文件拆分

将配置拆分为多个文件,提高可维护性:

// rollup.config.base.js
export default {
  input: 'src/main.js',
  plugins: [vue()]
}

// rollup.config.dev.js
import baseConfig from './rollup.config.base.js'

export default {
  ...baseConfig,
  output: {
    dir: 'dist/dev',
    format: 'esm',
    sourcemap: true
  }
}

// rollup.config.prod.js
import baseConfig from './rollup.config.base.js'
import terser from '@rollup/plugin-terser'

export default {
  ...baseConfig,
  output: {
    dir: 'dist/prod',
    format: 'esm',
    plugins: [terser()]
  }
}

3. 使用环境变量

// rollup.config.js
import { defineConfig } from 'rollup'
import replace from '@rollup/plugin-replace'

const isProduction = process.env.NODE_ENV === 'production'

export default defineConfig({
  input: 'src/main.js',
  output: {
    dir: 'dist',
    format: 'esm',
    plugins: isProduction ? [terser()] : []
  },
  plugins: [
    replace({
      __ENV__: JSON.stringify(process.env.NODE_ENV),
      preventAssignment: true
    })
  ]
})

4. 配置sourcemap

// rollup.config.js
export default {
  input: 'src/main.js',
  output: {
    dir: 'dist',
    format: 'esm',
    // 配置sourcemap
    sourcemap: true,
    sourcemapExcludeSources: true,
    sourcemapPathTransform: (relativeSourcePath) => {
      // 转换sourcemap路径
      return `../src/${relativeSourcePath}`
    }
  }
}

总结

Rollup是Vue 3项目的重要构建工具,通过高级配置可以实现代码分割、tree shaking、构建优化和多格式输出等功能。本集介绍了Rollup的代码分割策略、tree shaking优化、构建性能优化、多格式输出配置以及与Vite的集成,同时还介绍了一些常用的Rollup高级插件和配置最佳实践。

通过掌握Rollup的高级配置,开发者可以更好地优化Vue 3项目的构建流程,减小打包体积,提高加载速度,同时提高开发效率。Rollup与Vite的结合使用,可以充分发挥两者的优势,为Vue 3项目提供强大的构建支持。

在下一集中,我们将探讨Vue 3自定义构建流程,包括npm脚本配置、自定义构建脚本、CI/CD集成和构建优化等内容,进一步深入了解Vue 3的构建工具链。

« 上一篇 Vue 3 Vite插件开发:扩展构建工具功能 下一篇 » Vue 3 自定义构建流程:提高构建效率与质量