跳转到内容

构建打包规范

产物目录、资源命名、压缩策略


  • Standard:新项目优先使用 Vite,存量 Webpack 项目可逐步迁移。
  • Standard:构建工具版本在 package.json 中锁定,团队统一。
工具适用场景说明
Vite新项目、中小型项目构建快、配置简单、基于 Rollup
Webpack大型存量项目生态成熟、配置灵活
Rollup库/组件库打包Tree-shaking 优秀、产物干净
esbuild极致性能场景Go 编写、速度极快
Turbopack大型 monorepoWebpack 替代品(实验性)
语言构建工具
JavaMaven / Gradle
PythonPoetry / setuptools / pyinstaller
Go原生 go build
Node.jstsc / esbuild / pkg
  • Requirement:package.json 中必须定义标准化的构建脚本:
{
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "build:dev": "vite build --mode development",
    "build:staging": "vite build --mode staging",
    "build:prod": "vite build --mode production",
    "preview": "vite preview",
    "lint": "eslint . --ext .ts,.tsx",
    "type-check": "tsc --noEmit",
    "test": "vitest"
  }
}

  • Requirement:构建产物统一输出到 dist/ 目录,禁止输出到其他目录。
dist/
├── index.html # 入口 HTML
├── assets/ # 静态资源
│ ├── js/ # JavaScript 文件
│ ├── css/ # CSS 文件
│ ├── images/ # 图片
│ ├── fonts/ # 字体
│ └── icons/ # 图标
├── favicon.ico
├── robots.txt
└── manifest.json

**Java(Maven):

target/
├── user-service-1.0.0.jar # 可执行 Jar
├── user-service-1.0.0.jar.original # 原始 Jar(Spring Boot 瘦身)
├── classes/ # 编译后的 class 文件
├── lib/ # 依赖 Jar
└── maven-status/

**Go:

build/
├── user-service # 二进制文件
├── user-service-darwin-arm64
├── user-service-linux-amd64
└── user-service-windows-amd64.exe

**Python:

dist/
├── user_service-1.0.0-py3-none-any.whl # Wheel 包
└── user_service-1.0.0.tar.gz # 源码包
  • Requirement:构建前必须清理旧产物,禁止增量构建导致的残留文件。
  • Standard:dist/、target/、build/ 目录必须加入 .gitignore。
# .gitignore
dist/
target/
build/
*.log

  • Requirement:JS/CSS 文件名必须包含内容 hash,格式为 `..。
dist/assets/js/index.3a2b1c4d.js
dist/assets/css/main.9e8f7g6h.css
  • Standard:hash 长度 8 位,使用内容哈希(contenthash)。
  • Standard:图片、字体同样带 hash,确保缓存可控。
dist/assets/images/logo.1a2b3c4d.png
dist/assets/fonts/inter.5e6f7g8h.woff2
  • Standard:入口 HTML 文件名保持 index.html,不添加 hash。
// vite.config.ts
import { defineConfig } from 'vite';
import { resolve } from 'path';
 
export default defineConfig({
  build: {
    outDir: 'dist',
    assetsDir: 'assets',
    sourcemap: false, // 生产环境默认关闭,调试时按需开启
    rollupOptions: {
      output: {
      // JS 文件命名
      entryFileNames: 'assets/js/[name].[hash].js',
      chunkFileNames: 'assets/js/[name].[hash].js',
      // CSS 文件命名
      assetFileNames: (assetInfo) => {
        const name = assetInfo.name || '';
        if (name.endsWith('.css')) {
          return 'assets/css/[name].[hash][extname]';
        }
        if (/\.(png|jpe?g|svg|gif|webp)$/.test(name)) {
          return 'assets/images/[name].[hash][extname]';
        }
        if (/\.(woff2?|ttf|otf)$/.test(name)) {
          return 'assets/fonts/[name].[hash][extname]';
        }
        return 'assets/[name].[hash][extname]';
      },
    },
  },
  },
});

  • Requirement:生产构建必须开启代码压缩(minify)。
  • Standard:使用 terser(Webpack)或 esbuild(Vite)压缩。
  • Standard:压缩时移除 console.log、debugger、注释。
// vite.config.ts
export default defineConfig({
  build: {
    minify: 'esbuild', // 或 'terser'
    terserOptions: {
      compress: {
        drop_console: true,   // 移除 console
        drop_debugger: true, // 移除 debugger
      },
      format: {
        comments: false,    // 移除注释
      },
    },
  },
});
  • Requirement:生产构建必须压缩 CSS,移除空白与注释。
  • Standard:使用 cssnano 或 esbuild 内置 CSS 压缩。
  • Requirement:必须开启代码分割,将第三方依赖与业务代码分离。
  • Standard:按路由懒加载页面组件,减小首屏包体积。
  • Standard:第三方依赖单独打包,便于缓存。
// vite.config.ts
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          'react-vendor': ['react', 'react-dom', 'react-router-dom'],
          'ui-vendor': ['antd', '@ant-design/icons'],
          'utils-vendor': ['lodash-es', 'dayjs', 'axios'],
        },
      },
    },
  },
});
  • Requirement:必须开启 Tree Shaking,移除未使用的代码。
  • Standard:确保所有依赖支持 ES Module 格式,避免全量引入。
// 正确:按需引入
import { debounce } from 'lodash-es';
 
// 错误:全量引入
import _ from 'lodash';
  • Standard:生产环境默认关闭 Source Map,避免源码泄露。
  • Caution:如生产环境需要错误定位,可生成 Source Map 但上传到错误监控平台(Sentry),不随产物发布。
// vite.config.ts
export default defineConfig({
  build: {
    sourcemap: process.env.NODE_ENV !== 'production', // 生产关闭
  },
});
  • Standard:构建时生成 .gz / .br 预压缩文件,由 CDN 或 Nginx 直接返回。
  • Standard:文本类资源(JS、CSS、HTML、SVG、字体)开启压缩。
  • Caution:图片(PNG、JPG、WebP)已是压缩格式,无需再 gzip。
// vite.config.ts
import viteCompression from 'vite-plugin-compression';
 
export default defineConfig({
  plugins: [
    viteCompression({
      algorithm: 'gzip',
      threshold: 10240, // 大于 10KB 才压缩
      ext: '.gz',
    }),
    viteCompression({
      algorithm: 'brotliCompress',
      threshold: 10240,
      ext: '.br',
    }),
  ],
});
  • Standard:使用 rollup-plugin-visualizer 或 webpack-bundle-analyzer 分析包体积。
  • Standard:单 chunk 体积建议 ≤ 200KB(gzip 后),超过需拆分。
// vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer';
 
export default defineConfig({
  plugins: [visualizer({ open: true })],
});

  • Requirement:不同环境使用不同的构建配置,通过 --mode 参数区分。
  • Requirement:生产构建必须设置 NODE_ENV=production,确保依赖库进入生产模式(关闭开发警告)。
  • Standard:构建时注入环境变量,区分开发/预发布/生产。
// vite.config.ts
export default defineConfig(({ mode }) => ({
  define: {
    'process.env.NODE_ENV': JSON.stringify(mode),
    __APP_VERSION__: JSON.stringify(process.env.npm_package_version),
    __BUILD_TIME__: JSON.stringify(new Date().toISOString()),
  },
}));
# 开发环境构建
npm run build:dev
 
# 预发布环境构建
npm run build:staging
 
# 生产环境构建
npm run build:prod
  • Requirement:构建完成后必须校验产物完整性:

    1. 产物目录存在且非空。
    2. 入口 index.html 存在。
    3. 所有引用的资源文件存在。
    4. 无 console.log / debugger 残留(生产环境)。
    5. 包体积在阈值范围内。
  • Standard:CI 流水线中集成构建产物校验脚本。

#!/bin/bash
# scripts/verify-build.sh
set -e
 
DIST_DIR="dist"
 
# 检查产物目录
if [ ! -d "$DIST_DIR" ]; then
  echo "❌ Build output directory not found: $DIST_DIR"
  exit 1
fi
 
# 检查入口 HTML
if [ ! -f "$DIST_DIR/index.html" ]; then
  echo "❌ index.html not found"
  exit 1
fi
 
# 检查无 console.log 残留(生产环境)
if [ "$NODE_ENV" = "production" ]; then
  if grep -r "console.log" "$DIST_DIR/assets" --include="*.js" | head -1; then
    echo "❌ console.log found in production build"
    exit 1
  fi
fi
 
echo "✅ Build verification passed"

**Java Spring Boot 构建:

mvn clean package -DskipTests -Pprod

**Go 交叉编译:

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o build/user-service ./cmd/server

**Python 构建:

python -m build

反模式问题建议
产物不带 hash 文件名缓存无法自动失效构建时自动加 contenthash
生产环境保留 console.log信息泄露、性能损耗构建时移除
生产环境开启 Source Map源码泄露默认关闭,按需上传到监控平台
不开启代码分割首屏包体积过大按路由 + 第三方依赖拆分
全量引入依赖包体积膨胀按需引入 + Tree Shaking
构建产物未清理旧文件残留文件导致部署异常构建前清理 dist
不同环境共用同一构建产物配置错乱分环境构建
图片未压缩直接打包包体积过大构建时自动压缩
无包体积监控体积膨胀无法感知集成 bundle analyzer