从零搭建:pnpm + Turborepo 项目架构实战(含完整代码)

本文是《从零到一:构建现代化企业级 Monorepo 项目实战》系列的第三篇。前两篇我们分析了 Monorepo 的概念和工具选型,这篇文章将手把手带你从零搭建一个完整的项目。

🎯 本文目标

读完这篇文章,你将学会:

  • 如何初始化一个 pnpm + Turborepo 项目
  • 如何设计合理的包结构
  • 如何配置依赖关系
  • 如何实现包之间的相互引用

🏗️ 项目架构设计

最终目标

bash 复制代码
gdu-common/
├── packages/
│   ├── shared/          # 🔧 共享工具库(基础层)
│   ├── utils/           # 📦 工具函数库(基础层)
│   ├── ui/              # 🎨 UI 组件库(依赖 shared + utils)
│   └── controls-sdk/    # 🎮 飞控 SDK(相对独立)
├── docs/                # 📚 文档站点
├── build/               # ⚙️ 构建配置
├── turbo.json           # Turborepo 配置
├── pnpm-workspace.yaml  # pnpm workspace 配置
└── package.json         # 根配置

依赖关系图

graph TD A[shared 共享库] --> C[ui 组件库] B[utils 工具库] --> C D[controls-sdk] -.独立.-> D E[docs 文档] -.使用.-> C E -.使用.-> B E -.使用.-> D

📝 第一步:项目初始化

1.1 创建项目目录

bash 复制代码
mkdir gdu-common
cd gdu-common

# 初始化 git
git init

# 创建 .gitignore
cat > .gitignore << EOF
node_modules
dist
.turbo
*.log
.DS_Store
.env*
coverage
EOF

1.2 初始化 package.json

bash 复制代码
pnpm init

编辑 package.json

json 复制代码
{
  "name": "gdu-common",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "packageManager": "pnpm@10.13.1",
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev",
    "lint": "turbo run lint",
    "clean": "turbo run clean"
  }
}

1.3 配置 pnpm workspace

创建 pnpm-workspace.yaml

yaml 复制代码
packages:
  # packages 目录下的所有包
  - packages/*
  # 文档站点
  - docs
  # 构建配置
  - build

1.4 安装 Turborepo

bash 复制代码
pnpm add -Dw turbo

1.5 创建 turbo.json

json 复制代码
{
  "$schema": "https://turbo.build/schema.json",
  "ui": "tui",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"],
      "cache": true
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "lint": {
      "cache": true
    },
    "clean": {
      "cache": false
    }
  }
}

📦 第二步:创建第一个包(shared)

2.1 创建包目录

bash 复制代码
mkdir -p packages/shared/src
cd packages/shared

2.2 初始化包

bash 复制代码
pnpm init

编辑 packages/shared/package.json

json 复制代码
{
  "name": "@gdu-common/shared",
  "version": "1.0.0",
  "type": "module",
  "main": "./dist/umd/gdushared.umd.js",
  "module": "./dist/es/index.mjs",
  "types": "./dist/es/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/es/index.d.ts",
      "import": "./dist/es/index.mjs",
      "require": "./dist/umd/gdushared.umd.js"
    }
  },
  "files": ["dist"],
  "scripts": {
    "build": "vite build",
    "dev": "vite build --watch",
    "clean": "rimraf dist .turbo"
  }
}

2.3 创建源代码

typescript 复制代码
// packages/shared/src/index.ts
export const APP_NAME = 'GDU Common'
export const APP_VERSION = '1.0.0'

// packages/shared/src/common/index.ts
export const API_BASE_URL = 'https://api.example.com'

// packages/shared/src/common/test.ts
export function testShared() {
  console.log('Shared module works!')
}

2.4 配置 Vite

typescript 复制代码
// packages/shared/vite.config.ts
import { defineConfig } from 'vite'
import dts from 'vite-plugin-dts'

export default defineConfig({
  plugins: [
    dts({
      outDir: 'dist/es',
      entryRoot: 'src',
    }),
  ],
  build: {
    lib: {
      entry: './src/index.ts',
      name: 'GduShared',
      formats: ['es', 'umd'],
    },
    rollupOptions: {
      output: [
        {
          format: 'es',
          dir: 'dist/es',
          entryFileNames: '[name].mjs',
          preserveModules: true,
          preserveModulesRoot: 'src',
        },
        {
          format: 'umd',
          dir: 'dist/umd',
          entryFileNames: 'gdushared.umd.js',
          name: 'GduShared',
        },
      ],
    },
  },
})

2.5 测试构建

bash 复制代码
cd packages/shared
pnpm build

# 查看生成的文件
ls dist/es
# index.mjs  index.d.ts  common/

ls dist/umd
# gdushared.umd.js

🔧 第三步:创建工具包(utils)

3.1 创建包结构

bash 复制代码
mkdir -p packages/utils/src
cd packages/utils
pnpm init

3.2 配置 package.json

json 复制代码
{
  "name": "@gdu-common/utils",
  "version": "1.0.0",
  "type": "module",
  "main": "./dist/umd/gduutils.umd.js",
  "module": "./dist/es/index.mjs",
  "types": "./dist/es/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/es/index.d.ts",
      "import": "./dist/es/index.mjs",
      "require": "./dist/umd/gduutils.umd.js"
    }
  },
  "scripts": {
    "build": "vite build",
    "dev": "vite build --watch",
    "clean": "rimraf dist .turbo"
  },
  "peerDependencies": {
    "lodash-es": "^4.17.21"
  }
}

3.3 创建工具函数

typescript 复制代码
// packages/utils/src/utils.ts
export function formatDate(date: Date): string {
  return date.toISOString().split('T')[0]
}

// packages/utils/src/test.ts
import { debounce } from 'lodash-es'

export function hello(name: string) {
  console.log(`Hello, ${name}!`)
}

export const debouncedHello = debounce(hello, 300)

// packages/utils/src/index.ts
export * from './utils'
export * from './test'

3.4 配置 Vite

typescript 复制代码
// packages/utils/vite.config.ts
import { defineConfig } from 'vite'
import dts from 'vite-plugin-dts'

export default defineConfig({
  plugins: [
    dts({
      outDir: 'dist/es',
      entryRoot: 'src',
    }),
  ],
  build: {
    lib: {
      entry: './src/index.ts',
      name: 'GduUtils',
      formats: ['es', 'umd'],
    },
    rollupOptions: {
      external: ['lodash-es'],
      output: [
        {
          format: 'es',
          dir: 'dist/es',
          entryFileNames: '[name].mjs',
          preserveModules: true,
          preserveModulesRoot: 'src',
        },
        {
          format: 'umd',
          dir: 'dist/umd',
          entryFileNames: 'gduutils.umd.js',
          name: 'GduUtils',
          globals: {
            'lodash-es': 'LodashEs',
          },
        },
      ],
    },
  },
})

🎨 第四步:创建 UI 组件库

4.1 创建包结构

bash 复制代码
mkdir -p packages/ui/src/components/Button
cd packages/ui
pnpm init

4.2 安装依赖

bash 复制代码
# 添加 Vue 作为 peer 依赖
pnpm add -D vue

# 添加内部依赖
pnpm add @gdu-common/shared@workspace:* @gdu-common/utils@workspace:*

package.json:

json 复制代码
{
  "name": "@gdu-common/ui",
  "version": "1.0.0",
  "type": "module",
  "main": "./dist/index.umd.js",
  "module": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js",
      "require": "./dist/index.umd.js"
    },
    "./dist/index.css": "./dist/index.css"
  },
  "scripts": {
    "build": "vite build",
    "dev": "vite build --watch",
    "clean": "rimraf dist .turbo"
  },
  "peerDependencies": {
    "vue": "^3.5.0",
    "@gdu-common/shared": "workspace:^",
    "@gdu-common/utils": "workspace:^"
  }
}

4.3 创建第一个组件

vue 复制代码
<!-- packages/ui/src/components/Button/button.vue -->
<template>
  <button @click="handleClick">
    <slot />
  </button>
</template>

<script setup lang="ts">
import { APP_NAME } from '@gdu-common/shared'
import { hello } from '@gdu-common/utils'

const handleClick = () => {
  hello(APP_NAME)
}
</script>

<style scoped lang="scss">
button {
  padding: 10px 20px;
  background-color: #42b983;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.3s;

  &:hover {
    background-color: #369970;
  }
}
</style>
typescript 复制代码
// packages/ui/src/components/Button/index.ts
export { default as Button } from './button.vue'

// packages/ui/src/components/index.ts
export * from './Button'

// packages/ui/src/index.ts
export * from './components'

4.4 配置 Vite(Vue 组件)

typescript 复制代码
// packages/ui/vite.config.ts
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
import dts from 'vite-plugin-dts'

export default defineConfig({
  plugins: [
    vue(),
    dts({
      outDir: 'dist',
      cleanVueFileName: true,
      rollupTypes: true,
    }),
  ],
  build: {
    lib: {
      entry: './src/index.ts',
      name: 'GduUI',
      formats: ['es', 'umd'],
      fileName: format => `index.${format === 'es' ? 'js' : 'umd.js'}`,
    },
    rollupOptions: {
      external: ['vue', '@gdu-common/shared', '@gdu-common/utils'],
      output: {
        globals: {
          vue: 'Vue',
        },
        assetFileNames: assetInfo => {
          if (assetInfo.name?.endsWith('.css')) return 'index.css'
          return assetInfo.name || ''
        },
      },
    },
    cssCodeSplit: false,
  },
})

🔗 第五步:配置 TypeScript

5.1 根目录 tsconfig

json 复制代码
// tsconfig.base.json - 基础配置
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "paths": {
      "@gdu-common/*": ["packages/*/src"]
    }
  }
}
json 复制代码
// tsconfig.packages.json - 包通用配置
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist"
  },
  "include": ["src"]
}

5.2 各包的 tsconfig

json 复制代码
// packages/shared/tsconfig.build.json
{
  "extends": "../../tsconfig.packages.json"
}

// packages/utils/tsconfig.build.json
{
  "extends": "../../tsconfig.packages.json"
}

// packages/ui/tsconfig.build.json
{
  "extends": "../../tsconfig.packages.json",
  "compilerOptions": {
    "baseUrl": "../../",
    "paths": {
      "@gdu-common/utils": ["packages/utils/src"],
      "@gdu-common/shared": ["packages/shared/src"]
    }
  }
}

🎯 第六步:统一构建配置

6.1 创建共享构建配置

typescript 复制代码
// build/build.config.ts
import vue from '@vitejs/plugin-vue'
import { type UserConfig } from 'vite'
import dts from 'vite-plugin-dts'

interface BuildOptions {
  name?: string
  external?: string[]
  globals?: Record<string, string>
}

/**
 * 生成普通库的构建配置
 */
export function generateConfig(options: BuildOptions = {}): UserConfig {
  const { name = 'Library', external = [], globals = {} } = options

  return {
    plugins: [
      dts({
        outDir: 'dist/es',
        entryRoot: 'src',
      }),
    ],
    build: {
      lib: {
        entry: './src/index.ts',
        name,
        formats: ['es', 'umd'],
      },
      rollupOptions: {
        external,
        output: [
          {
            format: 'es',
            dir: 'dist/es',
            entryFileNames: '[name].mjs',
            preserveModules: true,
            preserveModulesRoot: 'src',
          },
          {
            format: 'umd',
            dir: 'dist/umd',
            entryFileNames: `${name.toLowerCase()}.umd.js`,
            name,
            globals,
          },
        ],
      },
    },
  }
}

/**
 * 生成 Vue 组件库的构建配置
 */
export function generateVueConfig(options: BuildOptions = {}): UserConfig {
  const { name = 'Library', external = [], globals = {} } = options

  return {
    plugins: [
      vue(),
      dts({
        outDir: 'dist',
        cleanVueFileName: true,
        rollupTypes: true,
      }),
    ],
    build: {
      lib: {
        entry: './src/index.ts',
        name,
        formats: ['es', 'umd'],
        fileName: format => `index.${format === 'es' ? 'js' : 'umd.js'}`,
      },
      rollupOptions: {
        external: ['vue', ...external],
        output: {
          globals: {
            vue: 'Vue',
            ...globals,
          },
          assetFileNames: assetInfo => {
            if (assetInfo.name?.endsWith('.css')) return 'index.css'
            return assetInfo.name || ''
          },
        },
      },
      cssCodeSplit: false,
    },
  }
}

6.2 简化各包的 vite.config.ts

typescript 复制代码
// packages/shared/vite.config.ts
import { generateConfig } from '../../build/build.config'

export default generateConfig({
  name: 'GduShared',
})

// packages/utils/vite.config.ts
import { generateConfig } from '../../build/build.config'

export default generateConfig({
  name: 'GduUtils',
  external: ['lodash-es'],
  globals: {
    'lodash-es': 'LodashEs',
  },
})

// packages/ui/vite.config.ts
import { generateVueConfig } from '../../build/build.config'

export default generateVueConfig({
  name: 'GduUI',
})

🧪 第七步:测试构建

7.1 构建所有包

bash 复制代码
# 回到根目录
cd ../..

# 安装所有依赖
pnpm install

# 构建所有包
pnpm build

预期输出:

bash 复制代码
> gdu-common@1.0.0 build
> turbo run build

• Packages in scope: @gdu-common/shared, @gdu-common/ui, @gdu-common/utils
• Running build in 3 packages

@gdu-common/shared:build: cache miss, executing...
@gdu-common/utils:build: cache miss, executing...
@gdu-common/shared:build: ✓ built in 2.1s
@gdu-common/utils:build: ✓ built in 2.3s
@gdu-common/ui:build: cache miss, executing...
@gdu-common/ui:build: ✓ built in 3.2s

Tasks:    3 successful, 3 total
Cached:   0 cached, 3 total
  Time:   7.6s

7.2 再次构建(测试缓存)

bash 复制代码
pnpm build

预期输出:

bash 复制代码
Tasks:    3 successful, 3 total
Cached:   3 cached, 3 total ⚡
  Time:   450ms >>> FULL TURBO

# 从 7.6s 到 450ms,提升 16.9 倍!

🔗 第八步:包之间的依赖

8.1 在 ui 包中使用 shared 和 utils

我们在第四步已经演示了:

vue 复制代码
<script setup lang="ts">
import { APP_NAME } from '@gdu-common/shared'
import { hello } from '@gdu-common/utils'

const handleClick = () => {
  hello(APP_NAME) // ✅ 可以直接使用!
}
</script>

8.2 依赖解析原理

TypeScript 路径映射:

json 复制代码
// tsconfig.base.json
{
  "compilerOptions": {
    "paths": {
      "@gdu-common/*": ["packages/*/src"]
    }
  }
}

pnpm workspace 协议:

json 复制代码
// packages/ui/package.json
{
  "peerDependencies": {
    "@gdu-common/shared": "workspace:^", // workspace 协议
    "@gdu-common/utils": "workspace:^"
  }
}

Turborepo 依赖编排:

json 复制代码
// turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"] // ^ 表示依赖包的 build
    }
  }
}

8.3 依赖关系验证

bash 复制代码
# 查看依赖关系
pnpm list -r --depth=0

# 输出
@gdu-common/shared 1.0.0
@gdu-common/utils 1.0.0
@gdu-common/ui 1.0.0 (depends on shared, utils)

📚 第九步:添加文档站点

9.1 安装 VitePress

bash 复制代码
mkdir docs
cd docs
pnpm init
pnpm add -D vitepress vue

9.2 配置文档

typescript 复制代码
// docs/.vitepress/config.ts
import { resolve } from 'path'
import { defineConfig } from 'vitepress'

export default defineConfig({
  title: 'GDU Common',
  description: 'GDU 前端通用组件库和工具集',

  vite: {
    resolve: {
      alias: {
        '@gdu-common/ui': resolve(__dirname, '../../packages/ui/src'),
        '@gdu-common/utils': resolve(__dirname, '../../packages/utils/src'),
        '@gdu-common/shared': resolve(__dirname, '../../packages/shared/src'),
      },
    },
  },

  themeConfig: {
    nav: [
      { text: '指南', link: '/guide/' },
      { text: '组件', link: '/components/' },
    ],
  },
})

9.3 创建文档内容

markdown 复制代码
<!-- docs/index.md -->

# GDU Common

企业级前端通用组件库和工具集

## 快速开始

\`\`\`bash
pnpm add @gdu-common/ui @gdu-common/utils
\`\`\`

## 组件示例

\`\`\`vue
<template>
<Button>点击我</Button>
</template>

<script setup>
import { Button } from '@gdu-common/ui'
</script>

\`\`\`

🎯 第十步:完整的项目脚本

10.1 根 package.json

json 复制代码
{
  "name": "gdu-common",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev",
    "lint": "turbo run lint",
    "lint:fix": "turbo run lint:fix",
    "clean": "turbo run clean",
    "clean:cache": "rimraf .turbo node_modules/.cache",
    "doc:dev": "pnpm --filter @gdu-common/docs dev"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^6.0.1",
    "rimraf": "^6.0.1",
    "turbo": "^2.5.8",
    "typescript": "^5.9.2",
    "vite": "^7.1.2",
    "vite-plugin-dts": "^4.5.4",
    "vue": "^3.5.22"
  },
  "dependencies": {
    "lodash-es": "^4.17.21"
  }
}

10.2 各包的标准脚本

json 复制代码
// 每个包都应该有这些脚本
{
  "scripts": {
    "build": "vite build",
    "dev": "vite build --watch",
    "clean": "rimraf dist .turbo",
    "lint": "eslint . --ext .js,.ts,.vue",
    "lint:fix": "eslint . --ext .js,.ts,.vue --fix"
  }
}

🚀 第十一步:运行和测试

11.1 开发模式

bash 复制代码
# 终端1:启动 ui 包的 watch 模式
pnpm --filter @gdu-common/ui dev

# 终端2:启动文档站点
pnpm doc:dev

# 修改 Button 组件 → 自动重建 → 文档站点热更新
# 真正的快速开发体验!⚡

11.2 生产构建

bash 复制代码
# 构建所有包
pnpm build

# 第一次构建
Tasks:    4 successful, 4 total
Cached:   0 cached, 4 total
  Time:   9.2s

# 第二次构建(无修改)
Tasks:    4 successful, 4 total
Cached:   4 cached, 4 total ⚡
  Time:   450ms >>> FULL TURBO

# 提升 20.4 倍!🚀

11.3 增量构建测试

bash 复制代码
# 修改 shared 包
echo "export const NEW_CONST = 'test'" >> packages/shared/src/index.ts

# 再次构建
pnpm build

@gdu-common/shared:build: cache miss, executing...
@gdu-common/utils:build: cache hit ⚡
@gdu-common/ui:build: cache miss (dependency changed)
@gdu-common/docs:build: cache hit ⚡

Tasks:    4 successful, 4 total
Cached:   2 cached, 4 total
  Time:   5.1s

# 只重建了受影响的包!

💡 最佳实践

1. 包命名规范

bash 复制代码
✅ 推荐:
@company/ui
@company/utils
@company/shared

❌ 不推荐:
ui-components
my-utils
shared

2. 依赖层级设计

less 复制代码
基础层(无依赖)
  ↓
@gdu-common/shared

工具层(依赖基础层)
  ↓
@gdu-common/utils

业务层(依赖基础+工具)
  ↓
@gdu-common/ui
@gdu-common/controls-sdk

应用层
  ↓
docs

3. 版本管理策略

json 复制代码
// 内部依赖使用 workspace 协议
{
  "dependencies": {
    "@gdu-common/utils": "workspace:^"
  }
}

// 发布时自动转换为实际版本
{
  "dependencies": {
    "@gdu-common/utils": "^1.2.3"
  }
}

4. 构建优化技巧

json 复制代码
// turbo.json
{
  "tasks": {
    "build": {
      "inputs": [
        "$TURBO_DEFAULT$",
        "!{dist,coverage,.turbo}/**", // 排除输出目录
        "!**/*.md", // 排除文档
        "!**/*.test.{ts,tsx}" // 排除测试
      ]
    }
  }
}

🤔 常见问题

Q1: 如何添加新包?

bash 复制代码
# 1. 创建目录
mkdir -p packages/new-package/src

# 2. 初始化
cd packages/new-package
pnpm init

# 3. 配置 package.json
{
  "name": "@gdu-common/new-package",
  "version": "1.0.0",
  "scripts": {
    "build": "vite build"
  }
}

# 4. 创建源代码
echo "export const test = 'test'" > src/index.ts

# 5. 返回根目录构建
cd ../..
pnpm build

Q2: 如何在包之间互相引用?

typescript 复制代码
// 1. 添加依赖
cd packages/ui
pnpm add @gdu-common/utils@workspace:*

// 2. 直接导入使用
import { formatDate } from '@gdu-common/utils'

Q3: 为什么缓存没有命中?

bash 复制代码
# 检查缓存未命中原因
pnpm build --dry-run

# 常见原因:
1. 源代码改变
2. 依赖改变
3. 配置文件改变(tsconfig、eslint等)
4. 环境变量改变

Q4: 如何调试构建问题?

bash 复制代码
# 查看详细日志
pnpm build --verbosity=2

# 查看缓存状态
pnpm turbo run build --dry-run

# 清理缓存重试
pnpm clean:cache
pnpm build

📈 性能对比总结

构建性能

场景 传统方式 Turborepo 提升
首次构建 45s 9s 5x
完全缓存 45s 0.45s 100x
修改1个包 45s 2.3s 19.6x
平均构建 45s 3-4s 11-15x

磁盘空间

场景 npm pnpm 节省
单个项目 350MB 120MB 65.7%
5个项目 1.75GB 350MB 80%

开发效率

任务 Multirepo Monorepo 提升
跨包重构 30分钟 2分钟 15x
本地联调 10分钟 即时
版本发布 20分钟 5分钟 4x

🎉 完整项目清单

项目结构

lua 复制代码
gdu-common/
├── packages/
│   ├── shared/
│   │   ├── src/
│   │   │   ├── index.ts
│   │   │   └── common/
│   │   ├── package.json
│   │   ├── tsconfig.build.json
│   │   └── vite.config.ts
│   ├── utils/
│   │   ├── src/
│   │   ├── package.json
│   │   └── vite.config.ts
│   └── ui/
│       ├── src/
│       │   └── components/
│       │       └── Button/
│       ├── package.json
│       └── vite.config.ts
├── docs/
│   ├── .vitepress/
│   │   └── config.ts
│   ├── index.md
│   └── package.json
├── build/
│   ├── build.config.ts
│   └── package.json
├── turbo.json
├── pnpm-workspace.yaml
├── tsconfig.base.json
├── tsconfig.packages.json
├── package.json
└── .gitignore

关键文件检查清单

  • pnpm-workspace.yaml - workspace 配置
  • turbo.json - Turborepo 配置
  • tsconfig.base.json - TS 基础配置
  • tsconfig.packages.json - 包通用配置
  • build/build.config.ts - 共享构建配置
  • 每个包的 package.json
  • 每个包的 vite.config.ts
  • 每个包的 tsconfig.build.json

🎁 项目模板

GitHub 仓库

我已经将完整的项目模板开源:

bash 复制代码
# 克隆模板
git clone https://github.com/Fangxin920915/fang-common-template.git

# 安装依赖
pnpm install

# 开始开发
pnpm dev

🚀 下一步

现在你已经有了一个完整的 Monorepo 项目!接下来我们将:

  1. 第4篇: 配置代码质量工具(ESLint + Prettier + Stylelint)
  2. 第5篇: 版本管理和自动发布(Changeset)
  3. 第6篇: 文档站点优化(VitePress 深度定制)
  4. 第7篇: CI/CD 自动化(GitLab CI)
  5. 第8篇: 性能优化和最佳实践

💭 思考题

  1. 你的项目有多少个包?是否需要 Turborepo?
  2. 试着用本文的方法搭建一个 Monorepo,需要多长时间?
  3. 缓存命中率如何?能提升多少倍?

🔗 系列文章


完整的项目代码已开源,欢迎 star!觉得有帮助的话,请点赞收藏支持一下! 🙏

你在搭建过程中遇到了什么问题?欢迎在评论区讨论! 💬

相关推荐
JarvanMo4 小时前
Flutter 中的 ClipRRect | 每日 Flutter 组件
前端
某柚啊4 小时前
iOS移动端H5键盘弹出时页面布局异常和滚动解决方案
前端·javascript·css·ios·html5
心.c4 小时前
如何学习Lodash源码?
前端·javascript·学习
JamSlade4 小时前
react 无限画布难点和实现
前端·react.js
im_AMBER4 小时前
React 02
前端·笔记·学习·react.js·前端框架
浩男孩4 小时前
🍀我实现了个摸鱼聊天室🚀
前端
玲小珑4 小时前
LangChain.js 完全开发手册(十六)实战综合项目二:AI 驱动的代码助手
前端·langchain·ai编程
井柏然4 小时前
从 Monorepo 重温 ESM 的模块化机制
前端·javascript·前端工程化
晓得迷路了4 小时前
栗子前端技术周刊第 102 期 - Vite+ 正式发布、React Native 0.82、Nitro v3 alpha 版...
前端·javascript·vite