第263集:Vue 3自定义构建流程

概述

在Vue 3项目开发中,构建流程是非常重要的一环。默认的构建配置可能无法满足所有项目的需求,因此需要进行自定义构建流程配置。本集将深入探讨Vue 3自定义构建流程,包括npm脚本配置、自定义构建脚本、CI/CD集成和构建优化等内容,帮助开发者掌握Vue 3项目的自定义构建流程,提高构建效率和项目质量。

npm脚本配置

npm脚本是自定义构建流程的基础,通过配置package.json中的scripts字段,可以定义各种构建命令。

1. 基本npm脚本配置

// package.json
{
  "name": "my-vue-project",
  "version": "1.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx --fix",
    "test": "vitest",
    "test:coverage": "vitest run --coverage"
  }
}

2. 自定义构建脚本

可以创建自定义的构建脚本文件,然后通过npm脚本调用:

// package.json
{
  "scripts": {
    "build:custom": "node scripts/build.js"
  }
}
// scripts/build.js
const { execSync } = require('child_process')
const fs = require('fs')
const path = require('path')

console.log('开始自定义构建流程...')

// 步骤1:清理旧的构建目录
console.log('清理旧的构建目录...')
const distPath = path.join(__dirname, '../dist')
if (fs.existsSync(distPath)) {
  fs.rmSync(distPath, { recursive: true, force: true })
}

// 步骤2:运行ESLint检查
console.log('运行ESLint检查...')
execSync('npm run lint', { stdio: 'inherit' })

// 步骤3:运行测试
console.log('运行测试...')
execSync('npm run test:coverage', { stdio: 'inherit' })

// 步骤4:构建项目
console.log('构建项目...')
execSync('vite build', { stdio: 'inherit' })

// 步骤5:生成构建报告
console.log('生成构建报告...')
// 可以在这里添加生成构建报告的逻辑

console.log('自定义构建流程完成!')

3. 环境特定的构建脚本

可以为不同环境配置不同的构建脚本:

// package.json
{
  "scripts": {
    "build:dev": "vite build --mode development",
    "build:test": "vite build --mode test",
    "build:prod": "vite build --mode production"
  }
}

4. 复合脚本

使用&&&组合多个命令:

// package.json
{
  "scripts": {
    "build:all": "npm run lint && npm run test && npm run build",
    "dev:with-mock": "concurrently \"vite\" \"npm run mock-server\""
  }
}

自定义构建脚本

除了使用npm脚本外,还可以创建更复杂的自定义构建脚本,使用Node.js和各种构建工具库。

1. 使用shelljs简化脚本编写

// scripts/build.js
const shell = require('shelljs')
const fs = require('fs')
const path = require('path')

// 设置shelljs为严格模式
shell.set('-e')

console.log('开始自定义构建流程...')

// 清理旧的构建目录
console.log('清理旧的构建目录...')
shell.rm('-rf', 'dist')

// 运行ESLint检查
console.log('运行ESLint检查...')
shell.exec('npm run lint')

// 运行测试
console.log('运行测试...')
shell.exec('npm run test:coverage')

// 构建项目
console.log('构建项目...')
shell.exec('vite build')

console.log('自定义构建流程完成!')

2. 使用gulp进行构建

// gulpfile.js
const gulp = require('gulp')
const eslint = require('gulp-eslint')
const { exec } = require('child_process')

// ESLint任务
gulp.task('lint', () => {
  return gulp.src(['**/*.{vue,js,ts,jsx,tsx}', '!node_modules/**'])
    .pipe(eslint())
    .pipe(eslint.format())
    .pipe(eslint.failAfterError())
})

// 测试任务
gulp.task('test', (done) => {
  exec('npm run test:coverage', (err, stdout, stderr) => {
    console.log(stdout)
    console.error(stderr)
    done(err)
  })
})

// 构建任务
gulp.task('build', (done) => {
  exec('vite build', (err, stdout, stderr) => {
    console.log(stdout)
    console.error(stderr)
    done(err)
  })
})

// 清理任务
gulp.task('clean', (done) => {
  exec('rm -rf dist', (err, stdout, stderr) => {
    console.log(stdout)
    console.error(stderr)
    done(err)
  })
})

// 主构建任务
gulp.task('build:all', gulp.series('clean', 'lint', 'test', 'build'))

3. 使用webpack进行构建

虽然Vue 3默认使用Vite,但也可以配置使用webpack进行构建:

// webpack.config.js
const { VueLoaderPlugin } = require('vue-loader')
const path = require('path')

module.exports = {
  entry: './src/main.ts',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        test: /\.ts$/,
        loader: 'ts-loader',
        options: {
          appendTsSuffixTo: [/\.vue$/]
        }
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }
    ]
  },
  plugins: [
    new VueLoaderPlugin()
  ],
  resolve: {
    extensions: ['.ts', '.js', '.vue', '.json']
  }
}
// package.json
{
  "scripts": {
    "build:webpack": "webpack --mode production"
  }
}

CI/CD集成

1. GitHub Actions配置

# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [ main, master ]
  pull_request:
    branches: [ main, master ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - name: 使用Node.js 18
      uses: actions/setup-node@v3
      with:
        node-version: 18
        cache: 'npm'

    - name: 安装依赖
      run: npm ci

    - name: 运行ESLint检查
      run: npm run lint

    - name: 运行测试
      run: npm run test:coverage

    - name: 构建项目
      run: npm run build

    - name: 上传构建产物
      uses: actions/upload-artifact@v3
      with:
        name: dist
        path: dist

2. GitLab CI配置

# .gitlab-ci.yml
image: node:18

stages:
  - install
  - lint
  - test
  - build
  - deploy

install:
  stage: install
  script:
    - npm ci
  artifacts:
    paths:
      - node_modules
    cache:
      key: $CI_COMMIT_REF_SLUG
      paths:
        - node_modules

lint:
  stage: lint
  script:
    - npm run lint
  dependencies:
    - install

test:
  stage: test
  script:
    - npm run test:coverage
  dependencies:
    - install
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml

build:
  stage: build
  script:
    - npm run build
  dependencies:
    - install
  artifacts:
    paths:
      - dist

# 部署阶段可以根据实际情况配置
deploy:
  stage: deploy
  script:
    - echo "部署到生产环境"
  dependencies:
    - build
  only:
    - main
    - master

3. Jenkins配置

// Jenkinsfile
pipeline {
    agent any

    stages {
        stage('安装依赖') {
            steps {
                sh 'npm ci'
            }
        }

        stage('ESLint检查') {
            steps {
                sh 'npm run lint'
            }
        }

        stage('运行测试') {
            steps {
                sh 'npm run test:coverage'
            }
            post {
                always {
                    publishHTML(target: [
                        allowMissing: false,
                        alwaysLinkToLastBuild: true,
                        keepAll: true,
                        reportDir: 'coverage',
                        reportFiles: 'index.html',
                        reportName: '代码覆盖率报告'
                    ])
                }
            }
        }

        stage('构建项目') {
            steps {
                sh 'npm run build'
            }
            post {
                success {
                    archiveArtifacts artifacts: 'dist/**/*', fingerprint: true
                }
            }
        }

        stage('部署') {
            steps {
                sh 'echo "部署到生产环境"'
            }
            when {
                branch 'main'
            }
        }
    }
}

构建优化

1. 缓存策略

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

export default defineConfig({
  plugins: [vue()],
  build: {
    // 启用构建缓存
    cacheDir: '.vite/cache',
    // 启用rollup缓存
    rollupOptions: {
      cache: true
    }
  }
})

2. 并行构建

使用npm-run-allconcurrently实现并行构建:

// package.json
{
  "scripts": {
    "build:parallel": "npm-run-all --parallel lint test build"
  }
}

3. 增量构建

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

export default defineConfig({
  plugins: [vue()],
  build: {
    // 启用增量构建
    incremental: true
  }
})

4. 构建分析

使用rollup-plugin-visualizer分析构建产物:

// 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,
          brotliSize: true,
          filename: 'stats.html'
        })
      ]
    }
  }
})

构建流程最佳实践

1. 分离构建环境

将构建环境与开发环境分离,使用不同的配置文件:

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

export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': '/src'
    }
  }
})

// vite.config.dev.js - 开发配置
import baseConfig from './vite.config.js'

export default {
  ...baseConfig,
  server: {
    port: 3000,
    open: true
  }
}

// vite.config.prod.js - 生产配置
import baseConfig from './vite.config.js'

export default {
  ...baseConfig,
  build: {
    outDir: 'dist',
    sourcemap: false,
    rollupOptions: {
      output: {
        manualChunks: {
          vue: ['vue'],
          'vue-router': ['vue-router'],
          pinia: ['pinia']
        }
      }
    }
  }
}

2. 使用构建变量

在构建过程中使用环境变量:

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

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd())
  
  return {
    plugins: [vue()],
    define: {
      'process.env.NODE_ENV': JSON.stringify(mode),
      'process.env.API_URL': JSON.stringify(env.VITE_API_URL)
    }
  }
})

3. 构建前检查

在构建前进行各种检查,确保构建质量:

// scripts/pre-build.js
const shell = require('shelljs')
const fs = require('fs')
const path = require('path')

console.log('开始构建前检查...')

// 检查Node.js版本
const nodeVersion = process.version
console.log(`Node.js版本: ${nodeVersion}`)
const requiredVersion = 'v16.0.0'
if (nodeVersion < requiredVersion) {
  console.error(`错误: 需要Node.js版本 ${requiredVersion} 或更高版本`)
  process.exit(1)
}

// 检查npm版本
const npmVersion = shell.exec('npm --version', { silent: true }).stdout.trim()
console.log(`npm版本: ${npmVersion}`)

// 检查依赖是否已安装
if (!fs.existsSync(path.join(__dirname, '../node_modules'))) {
  console.error('错误: 依赖未安装,请先运行 npm install')
  process.exit(1)
}

console.log('构建前检查通过!')

4. 构建后处理

在构建完成后进行一些处理,如生成构建报告、部署等:

// scripts/post-build.js
const shell = require('shelljs')
const fs = require('fs')
const path = require('path')

console.log('开始构建后处理...')

// 生成构建信息
const buildInfo = {
  timestamp: new Date().toISOString(),
  version: require('../package.json').version,
  commit: shell.exec('git rev-parse HEAD', { silent: true }).stdout.trim(),
  branch: shell.exec('git rev-parse --abbrev-ref HEAD', { silent: true }).stdout.trim()
}

fs.writeFileSync(
  path.join(__dirname, '../dist/build-info.json'),
  JSON.stringify(buildInfo, null, 2)
)

console.log('构建信息已生成!')

// 复制静态资源
console.log('复制静态资源...')
shell.cp('-r', 'public/*', 'dist/')

console.log('构建后处理完成!')

总结

自定义构建流程是Vue 3项目开发中的重要环节,通过合理配置npm脚本、自定义构建脚本、CI/CD集成和构建优化,可以提高构建效率和项目质量。本集介绍了npm脚本配置、自定义构建脚本、CI/CD集成和构建优化等内容,同时还介绍了一些构建流程的最佳实践。

通过掌握Vue 3自定义构建流程,开发者可以根据项目需求定制构建过程,提高构建效率,减少构建错误,同时保证构建产物的质量。合理的构建流程配置对于大型Vue 3项目尤为重要,可以显著提高开发效率和项目可维护性。

在下一集中,我们将探讨Vue 3多页面应用构建,包括多页面应用的配置、路由设计、状态管理和部署策略等内容,进一步深入了解Vue 3的构建工具链。

« 上一篇 Vue 3 Rollup高级配置:优化构建流程 下一篇 » Vue 3 多页面应用配置与实践:选择合适的架构模式