构建优化

构建优化是Vue.js应用性能优化的重要环节。通过优化构建配置,可以显著减少应用的最终体积,提高加载速度。本章将介绍Vite构建优化的多种策略和最佳实践。

13.35.1 Vite构建配置优化

基础配置优化

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

export default defineConfig({
  plugins: [vue()],
  // 优化构建配置
  build: {
    // 产物目录
    outDir: 'dist',
    // 静态资源目录
    assetsDir: 'assets',
    // 产物文件名哈希
    assetsDir: 'assets/[ext]',
    // 入口文件名
    rollupOptions: {
      input: {
        main: resolve(__dirname, 'index.html')
      }
    },
    // 最小化混淆
    minify: 'terser',
    // 生成sourcemap
    sourcemap: process.env.NODE_ENV === 'development',
    // 拆分CSS
    cssCodeSplit: true,
    // 预加载策略
    preload: {
      include: {
        type: 'script'
      }
    },
    // 模块预加载
    modulePreload: {
      include: {
        type: 'script'
      }
    }
  },
  // 服务器配置
  server: {
    port: 3000,
    open: true
  },
  // 解析配置
  resolve: {
    // 别名配置
    alias: {
      '@': resolve(__dirname, 'src')
    },
    // 扩展配置
    extensions: ['.vue', '.js', '.ts', '.jsx', '.tsx']
  }
})

高级构建配置

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

export default defineConfig({
  plugins: [
    vue(),
    // 构建分析插件
    visualizer({
      open: true,
      gzipSize: true,
      brotliSize: true
    })
  ],
  build: {
    // 产物文件名格式
    rollupOptions: {
      output: {
        // 静态资源文件名格式
        assetFileNames: 'assets/[name]-[hash][extname]',
        // 入口文件名格式
        entryFileNames: 'assets/[name]-[hash].js',
        // 代码拆分
        manualChunks: {
          // 将vue相关依赖打包成一个chunk
          vue: ['vue', 'vue-router', 'pinia'],
          // 将UI组件库打包成一个chunk
          ui: ['element-plus'],
          // 将工具库打包成一个chunk
          utils: ['axios', '@vueuse/core']
        }
      }
    },
    // 产物压缩配置
    terserOptions: {
      compress: {
        // 移除console
        drop_console: true,
        // 移除debugger
        drop_debugger: true,
        // 移除无用代码
        dead_code: true
      },
      // 混淆配置
      mangle: {
        // 保留类名
        keep_classnames: true,
        // 保留函数名
        keep_fnames: false
      }
    }
  }
})

13.35.2 依赖优化与分析

依赖分析工具

rollup-plugin-visualizer

npm install rollup-plugin-visualizer --save-dev
// vite.config.js
import { visualizer } from 'rollup-plugin-visualizer'

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

vite-bundle-analyzer

npm install vite-bundle-analyzer --save-dev
// vite.config.js
import { defineConfig } from 'vite'
import { createHtmlPlugin } from 'vite-plugin-html'

export default defineConfig({
  plugins: [
    createHtmlPlugin({
      minify: true
    })
  ]
})

依赖优化策略

  1. 移除无用依赖

    # 检查未使用的依赖
    npm install -g depcheck
    depcheck
  2. 使用更小的替代库

    • lodash → lodash-es 或 lodash/core
    • moment → dayjs 或 date-fns
    • axios → ky 或 fetch API
  3. 按需导入

    // 完整导入
    import _ from 'lodash'
    
    // 按需导入
    import { debounce } from 'lodash-es'
  4. 依赖预构建
    Vite会自动预构建依赖,将CommonJS模块转换为ESM模块,提高加载速度。

构建报告生成

# 生成构建报告
npm run build -- --report
// package.json
{
  "scripts": {
    "build": "vite build",
    "build:report": "vite build --report"
  }
}

13.35.3 压缩与CDN配置

资源压缩

Gzip压缩

// vite.config.js
import { defineConfig } from 'vite'
import viteCompression from 'vite-plugin-compression'

export default defineConfig({
  plugins: [
    viteCompression({
      // 压缩算法
      algorithm: 'gzip',
      // 压缩阈值
      threshold: 10240,
      // 压缩后的文件扩展名
      ext: '.gz',
      // 是否删除原文件
      deleteOriginFile: false
    })
  ]
})

Brotli压缩

// vite.config.js
import { defineConfig } from 'vite'
import viteCompression from 'vite-plugin-compression'

export default defineConfig({
  plugins: [
    viteCompression({
      algorithm: 'brotliCompress',
      threshold: 10240,
      ext: '.br',
      deleteOriginFile: false
    })
  ]
})

CDN配置

使用外部CDN

// vite.config.js
import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    rollupOptions: {
      external: ['vue', 'vue-router', 'pinia'],
      output: {
        globals: {
          vue: 'Vue',
          'vue-router': 'VueRouter',
          pinia: 'Pinia'
        }
      }
    }
  }
})
<!-- index.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vue.js应用</title>
  <!-- 引入CDN资源 -->
  <script src="https://unpkg.com/vue@3.3.4/dist/vue.global.js"></script>
  <script src="https://unpkg.com/vue-router@4.2.4/dist/vue-router.global.js"></script>
  <script src="https://unpkg.com/pinia@2.1.6/dist/pinia.global.js"></script>
</head>
<body>
  <div id="app"></div>
  <script type="module" src="/src/main.js"></script>
</body>
</html>

使用 vite-plugin-cdn-import

npm install vite-plugin-cdn-import --save-dev
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import cdn from 'vite-plugin-cdn-import'

export default defineConfig({
  plugins: [
    vue(),
    cdn({
      modules: [
        {
          name: 'vue',
          var: 'Vue',
          path: 'https://unpkg.com/vue@3.3.4/dist/vue.global.js'
        },
        {
          name: 'vue-router',
          var: 'VueRouter',
          path: 'https://unpkg.com/vue-router@4.2.4/dist/vue-router.global.js'
        },
        {
          name: 'pinia',
          var: 'Pinia',
          path: 'https://unpkg.com/pinia@2.1.6/dist/pinia.global.js'
        },
        {
          name: 'element-plus',
          var: 'ElementPlus',
          path: 'https://unpkg.com/element-plus@2.3.12/dist/index.full.js',
          css: 'https://unpkg.com/element-plus@2.3.12/dist/index.css'
        }
      ]
    })
  ]
})

13.35.4 PWA与离线能力

PWA配置

npm install vite-plugin-pwa --save-dev
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { VitePWA } from 'vite-plugin-pwa'

export default defineConfig({
  plugins: [
    vue(),
    VitePWA({
      // PWA配置
      registerType: 'autoUpdate',
      includeAssets: ['favicon.ico', 'apple-touch-icon.png', 'masked-icon.svg'],
      manifest: {
        name: 'Vue.js应用',
        short_name: 'Vue应用',
description: '一个基于Vue.js的PWA应用',
        theme_color: '#ffffff',
        icons: [
          {
            src: 'pwa-192x192.png',
            sizes: '192x192',
            type: 'image/png'
          },
          {
            src: 'pwa-512x512.png',
            sizes: '512x512',
            type: 'image/png'
          },
          {
            src: 'pwa-512x512.png',
            sizes: '512x512',
            type: 'image/png',
            purpose: 'any maskable'
          }
        ]
      },
      // Service Worker配置
      workbox: {
        // 缓存策略
        runtimeCaching: [
          {
            urlPattern: /^https:\/\/api\.example\.com\//,
            handler: 'NetworkFirst',
            options: {
              cacheName: 'api-cache',
              expiration: {
                maxEntries: 100,
                maxAgeSeconds: 60 * 60 * 24 // 1天
              }
            }
          },
          {
            urlPattern: /^https:\/\/assets\.example\.com\//,
            handler: 'CacheFirst',
            options: {
              cacheName: 'assets-cache',
              expiration: {
                maxEntries: 1000,
                maxAgeSeconds: 60 * 60 * 24 * 30 // 30天
              }
            }
          }
        ]
      }
    })
  ]
})

注册Service Worker

// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import { registerSW } from 'virtual:pwa-register'

// 注册Service Worker
const updateSW = registerSW({
  onNeedRefresh() {
    // 提示用户刷新
    if (confirm('应用有新版本,是否刷新?')) {
      updateSW()
    }
  },
  onOfflineReady() {
    // 提示用户应用已可离线使用
    console.log('应用已可离线使用')
  }
})

const app = createApp(App)
app.mount('#app')

PWA最佳实践

  1. 图标设计

    • 提供多种尺寸的图标
    • 使用SVG格式的maskable图标
    • 确保图标清晰可见
  2. 缓存策略

    • 静态资源使用CacheFirst策略
    • API请求使用NetworkFirst或StaleWhileRevalidate策略
    • 设置合理的缓存过期时间
  3. 更新策略

    • 使用autoUpdate自动更新
    • 提供手动更新选项
    • 提示用户有新版本可用
  4. 离线体验

    • 提供离线页面
    • 处理网络请求失败的情况
    • 显示离线状态

构建优化总结

  1. Vite配置优化

    • 合理配置构建选项
    • 使用别名简化导入
    • 配置代码拆分
  2. 依赖优化

    • 移除无用依赖
    • 使用更小的替代库
    • 按需导入
    • 生成构建报告
  3. 压缩与CDN

    • 使用Gzip和Brotli压缩
    • 配置CDN加速
    • 使用外部CDN资源
  4. PWA与离线能力

    • 配置PWA支持
    • 注册Service Worker
    • 优化离线体验

通过以上优化策略,可以显著提高Vue.js应用的构建效率和最终性能。在实际开发中,应该根据应用的具体情况选择合适的优化方案,并使用构建分析工具进行验证。

« 上一篇 33-application-performance-optimization 下一篇 » 35-ecommerce-admin