南昌市网站建设_网站建设公司_ASP.NET_seo优化
2026/1/21 21:34:49 网站建设 项目流程

开发一个 TypeScript + Monorepo 的前端工具函数类库,需要兼顾模块化、可维护性、类型安全、构建效率和开发者体验。以下是一个推荐的技术选型与目录结构设计方案:


一、技术选型

1. Monorepo 管理工具

  • 推荐: pnpm + workspace
    • 轻量、高效、支持软链接(hardlink + symlink),节省磁盘空间。
    • 内置 workspace 支持,无需额外工具(如 Lerna)即可管理包依赖和脚本。
    • 若需要更复杂的发布/版本管理,可搭配 changesets。

替代方案:Turborepo(适合大型项目,有缓存加速)、Lerna(较重,已逐渐被 Turborepo/pnpm 取代)。


2. 语言 & 类型

  • TypeScript(核心)
    • 启用严格模式(strict: true
    • 输出 .d.ts 声明文件
    • 使用 tsuprollup 构建

3. 构建工具

  • 推荐: tsup
    • 零配置、基于 esbuild,极快
    • 自动生成 ESM/CJS/UMD 和类型声明
    • 支持多入口(multi-entry)

替代方案:

  • Rollup + @rollup/plugin-typescript(更灵活但配置复杂)
  • Vite Library Mode(适合简单场景)

4. 测试框架

  • Vitest(推荐)
    • 极快、原生支持 TS、与 Vite 生态兼容
    • 支持覆盖率、Mock、Snapshot 等
  • 配合: @vitest/coverage-v8(代码覆盖率)

5. 代码质量

  • ESLint + @typescript-eslint
  • Prettier(格式化)
  • Husky + lint-staged(提交前检查)
  • Commitlint(规范 commit message)

6. 文档

  • VitePress(轻量、快速、支持 TS 示例)
    • 可直接在 docs 中写交互式示例
  • 或使用 Storybook(如果包含 UI 组件,但纯工具函数建议 VitePress)

7. 发布管理

  • Changesets(推荐)
    • 自动生成 changelog、版本号、发布流程
    • 与 pnpm workspace 完美集成

二、目录结构设计

my-utils-monorepo/
├── packages/
│   ├── core/                 # 核心工具函数(无依赖或仅 devDependencies)
│   ├── dom/                  # DOM 操作相关工具
│   ├── react/                # React 专用 hooks/utils
│   ├── vue/                  # Vue 专用 composables/utils(可选)
│   └── shared/               # 多包共享的内部工具(private 包)
│
├── docs/                     # 文档站点(VitePress)
│   ├── index.md
│   └── api/
│
├── scripts/                  # 自定义脚本(如生成索引、批量构建等)
│
├── .changeset/               # Changesets 自动生成的版本变更记录
│
├── package.json              # root package.json(定义 workspace 和 scripts)
├── pnpm-workspace.yaml       # pnpm workspace 配置
├── tsconfig.json             # 全局 TS 配置(被各子包继承)
├── tsconfig.build.json       # 构建专用配置(可选)
├── vitest.config.ts          # 测试配置
├── eslint.config.js          # ESLint 配置(Flat config)
├── prettier.config.js
├── .gitignore
└── README.md

三、子包(package)结构示例(以 packages/core 为例)

packages/core/
├── src/
│   ├── index.ts              # 主入口
│   ├── array/
│   │   ├── chunk.ts
│   │   └── shuffle.ts
│   ├── object/
│   │   └── deepMerge.ts
│   └── utils/
│       └── debounce.ts
├── test/
│   ├── array.test.ts
│   └── object.test.ts
├── package.json              # 注意:private: false(若要发布)
├── tsconfig.json             # extends root,设置 "composite": true
└── CHANGELOG.md              # 由 changesets 自动生成

关键点:

  • 每个子包都有自己的 package.json,可独立发布
  • 使用 exports 字段(ESM 优先):
    {"name": "@my-utils/core","type": "module","exports": {".": {"import": "./dist/index.js","require": "./dist/index.cjs","types": "./dist/index.d.ts"}}
    }
    

四、根目录 package.json 关键字段示例

{"name": "my-utils-monorepo","private": true,"scripts": {"build": "pnpm -r build","test": "vitest run","lint": "eslint .","format": "prettier --write .","changeset": "changeset","release": "pnpm build && changeset publish"},"devDependencies": {"typescript": "^5.x","tsup": "^8.x","vitest": "^2.x","@changesets/cli": "^2.x","eslint": "^9.x","prettier": "^3.x","husky": "^9.x","lint-staged": "^15.x"}
}

五、工作流建议

  1. 开发时:

    • 使用 pnpm -r watch(如果 tsup 支持)或 pnpm --filter <pkg> dev
    • 利用 pnpm 的软链接实现跨包实时引用
  2. 提交前:

    • Husky 触发 lint + format + test
  3. 发布:

    • 运行 pnpm changeset → 提交 → CI 自动 pnpm release

六、可选增强

  • Playground:在 docs 或单独 playground/ 目录中提供在线试用(用 Vite + TS)
  • Benchmarks:使用 tinybench 对比性能
  • Tree-shaking 友好:确保每个函数可独立导入(如 import { debounce } from '@my-utils/core/debounce'

我需要区分支持浏览器的工具函数和支持Node的,以及二者都支持的

区分 浏览器(Browser)、Node.js 和 通用(Universal / Isomorphic) 工具函数是构建高质量工具库的关键设计。以下是在原有 Monorepo 架构基础上,针对这一需求的细化技术方案与目录结构建议。

✅ 核心原则
类型 特点 命名建议 构建目标
Universal 无平台依赖(纯 JS/TS 逻辑) @my-utils/core 或 common ESM + CJS + types

Browser-only 使用 DOM/BOM/Web API(如 localStorage, fetch, window) @my-utils/browser ESM(可选 IIFE)

Node-only 使用 Node 内置模块(如 fs, path, process) @my-utils/node CJS + ESM(Node 兼容)

⚠️ 禁止跨环境调用:例如 node 包不能被浏览器项目引入,反之亦然。可通过文档 + 构建时警告 + package.json 条件导出规避。

🗂 推荐目录结构调整

my-utils-monorepo/
├── packages/
│ ├── common/ # ✅ 通用工具(无平台依赖)
│ │ └── src/
│ │ ├── array/
│ │ ├── object/
│ │ └── index.ts
│ │
│ ├── browser/ # 🌐 浏览器专用(依赖 DOM/BOM)
│ │ └── src/
│ │ ├── storage/
│ │ ├── dom/
│ │ └── index.ts
│ │
│ ├── node/ # 🖥️ Node.js 专用(依赖 fs/path 等)
│ │ └── src/
│ │ ├── fs/
│ │ ├── env/
│ │ └── index.ts
│ │
│ └── shared/ # 🔒 内部共享(private,不发布)

├── docs/
│ ├── guide/
│ │ ├── universal.md
│ │ ├── browser.md
│ │ └── node.md
│ └── api/

├── pnpm-workspace.yaml
└── ...

📦 各包 package.json 关键配置示例

  1. packages/common/package.json
    {
    "name": "@my-utils/common",
    "type": "module",
    "exports": {
    ".": {
    "import": "./dist/index.js",
    "require": "./dist/index.cjs",
    "types": "./dist/index.d.ts"
    }
    },
    "types": "./dist/index.d.ts",
    "files": ["dist"]
    }

  2. packages/browser/package.json
    {
    "name": "@my-utils/browser",
    "type": "module",
    "exports": {
    ".": {
    "import": "./dist/index.js",
    "types": "./dist/index.d.ts"
    }
    },
    "browser": "./dist/index.js", // 明确标识为浏览器包
    "sideEffects": false,
    "files": ["dist"]
    }

  3. packages/node/package.json
    {
    "name": "@my-utils/node",
    "type": "module",
    "exports": {
    ".": {
    "import": "./dist/index.js",
    "require": "./dist/index.cjs",
    "types": "./dist/index.d.ts"
    }
    },
    "engines": {
    "node": ">=16"
    },
    "files": ["dist"]
    }

💡 关键字段说明:

  • "browser" 字段:帮助打包工具(如 Webpack、Vite)识别这是浏览器专用包。
  • "engines":明确 Node 版本要求。
  • 不要将 node 包发布到 CDN(如 unpkg),避免前端误用。

🛠 构建配置(tsup)

每个子包使用独立的 tsup.config.ts 或统一脚本控制:

// scripts/build.ts (或每个包下单独配置)
import { defineConfig } from 'tsup'

export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'], // browser 可只用 esm;node 建议保留 cjs 兼容
dts: true,
clean: true,
sourcemap: true,
// browser 包可加 minify: true
})

✅ 建议:

  • common → 输出 esm + cjs
  • browser → 仅 esm(现代前端生态已全面支持)
  • node → esm + cjs(兼顾旧版 Node)

🔍 如何防止误用?(开发体验保障)

  1. TypeScript 路径映射(可选)
    在根 tsconfig.json 中设置路径别名,便于开发时引用:
    {
    "compilerOptions": {
    "paths": {
    "@my-utils/common": ["packages/common/src"],
    "@my-utils/browser": ["packages/browser/src"],
    "@my-utils/node": ["packages/node/src"]
    }
    }
    }

  2. ESLint 规则(进阶)
    可自定义 ESLint rule,禁止在 browser 包中 import node 模块(如 fs),反之亦然。

  3. 文档明确标注
    在 VitePress 文档中为每个函数打标签:

debounce

  • ✅ Universal
  • 📦 import { debounce } from '@my-utils/common'

readJsonFile

  • 🖥️ Node.js only
  • 📦 import { readJsonFile } from '@my-utils/node'

🧪 测试策略

  • common:在 Node 环境测试(Vitest 默认)

  • browser:使用 happy-dom 或 jsdom 模拟浏览器环境
    // vitest.config.ts
    export default defineConfig({
    test: {
    environment: 'happy-dom', // 或 'jsdom'
    include: ['packages/browser/test/**/*.{test,spec}.{js,ts}']
    }
    })

  • node:直接在 Node 环境测试(注意 mock fs 等)

📦 发布与消费者使用示例

用户按需安装:

只需要通用工具
npm install @my-utils/common

需要浏览器工具
npm install @my-utils/browser

Node 项目
npm install @my-utils/node

使用:

// 通用
import { deepMerge } from '@my-utils/common'

// 浏览器
import { getLocalStorage } from '@my-utils/browser'

// Node
import { readJson } from '@my-utils/node'

✅ 总结:你的三层架构
层级 包名 内容 安全性
通用层 @my-utils/common 纯逻辑、无环境依赖 ✅ 最安全,任意环境可用

浏览器层 @my-utils/browser DOM/BOM/Web APIs 🌐 仅限浏览器

Node 层 @my-utils/node Node 内置模块 🖥️ 仅限 Node

这种设计清晰、可维护、防误用,且符合现代前端工程化最佳实践。

VitePress 自动 API 文档生成方案

当然可以!为你的 TypeScript Monorepo 工具库(含 common / browser / node 包)配置 VitePress 自动 API 文档生成方案,目标是:

  • ✅ 从源码 .ts 文件自动提取函数签名、注释、类型
  • ✅ 按包分类展示(如 /api/common//api/browser/
  • ✅ 支持 JSDoc 注释渲染(参数、返回值、示例等)
  • ✅ 开发时热更新文档

🧩 推荐方案:使用 vitepress-plugin-typedoc

TypeDoc 是 TypeScript 官方推荐的文档生成器,能将 TS 代码转为结构化 JSON 或 HTML。
vitepress-plugin-typedoc 可将其无缝集成进 VitePress。


🔧 一、安装依赖

在项目根目录运行:

pnpm add -D typedoc vitepress-plugin-typedoc

确保你已安装 vitepress(若未安装):

pnpm add -D vitepress

📁 二、目录结构(延续之前的)

my-utils-monorepo/
├── docs/
│   ├── api/
│   │   └── .vitepress/typedoc/   ← 自动生成的 markdown 会放这里(可选)
│   ├── .vitepress/
│   │   ├── config.ts
│   │   └── theme/
│   └── index.md
├── packages/
│   ├── common/
│   ├── browser/
│   └── node/
└── ...

⚙️ 三、配置 VitePress + TypeDoc 插件

1. 创建 docs/.vitepress/config.ts

import { defineConfig } from 'vitepress'
import { typeDocSidebar } from './typedoc-sidebar'export default defineConfig({title: 'My Utils',description: 'A modern utility library for web and Node.js',srcDir: '.',outDir: '../dist-docs',// 启用插件vue: {template: {compilerOptions: {isCustomElement: (tag) => tag.includes('api-')}}},// 侧边栏:动态生成sidebar: [{ text: 'Guide', link: '/' },{ text: 'API Reference', items: typeDocSidebar }]
})

2. 创建 docs/.vitepress/typedoc-config.ts(TypeDoc 配置)

// docs/.vitepress/typedoc-config.ts
import { TypeDocOptions } from 'typedoc'export const getTypedocConfig = (entryPoints: string[], out: string): TypeDocOptions => ({entryPoints,tsconfig: '../../tsconfig.json',skipErrorChecking: true,cleanOutputDir: false,hideGenerator: true,githubPages: false,readme: 'none',disableSources: true,excludeExternals: true,excludePrivate: true,excludeProtected: true,plugin: ['vitepress-plugin-typedoc'],vitepressOut: out, // 输出到 docs/api/xxx/
})

3. 创建 docs/.vitepress/typedoc-sidebar.ts(自动生成侧边栏)

// docs/.vitepress/typedoc-sidebar.ts
import { writeFileSync, existsSync, mkdirSync } from 'fs'
import { resolve } from 'path'
import { Application } from 'typedoc'
import { getTypedocConfig } from './typedoc-config'const packages = ['common', 'browser', 'node']// 为每个包生成文档
for (const pkg of packages) {const srcPath = resolve(__dirname, `../../../packages/${pkg}/src/index.ts`)if (!existsSync(srcPath)) continueconst outDir = resolve(__dirname, `../api/${pkg}`)if (!existsSync(outDir)) mkdirSync(outDir, { recursive: true })const app = new Application()app.options.addReader(new app.options.getReader('tsconfig'))app.bootstrap(getTypedocConfig([srcPath], outDir))const project = app.convert()if (project) {app.generateDocs(project, outDir)}
}// 构建侧边栏结构
export const typeDocSidebar = packages.map(pkg => ({text: `${pkg.charAt(0).toUpperCase() + pkg.slice(1)} API`,link: `/api/${pkg}/`,
}))

💡 这个脚本会在 每次启动 VitePress 时自动运行(见下一步)。


▶️ 四、修改 docs/package.json 脚本(或根目录)

根目录 package.json 中添加:

{"scripts": {"docs:dev": "tsx docs/.vitepress/typedoc-sidebar.ts && vitepress dev docs","docs:build": "tsx docs/.vitepress/typedoc-sidebar.ts && vitepress build docs","docs:preview": "vitepress preview docs"}
}

使用 tsx(需安装)来运行 TS 脚本:

pnpm add -D tsx

✍️ 五、编写带 JSDoc 的源码(关键!)

TypeDoc 依赖 JSDoc 注释生成高质量文档。

// packages/common/src/array/chunk.ts
/*** 将数组分割成指定大小的块** @param array - 要分割的数组* @param size - 每块的大小(默认 1)* @returns 二维数组** @example* ```ts* chunk([1, 2, 3, 4], 2)* // => [[1, 2], [3, 4]]* ```*/
export function chunk<T>(array: T[], size = 1): T[][] {// ...
}

✅ 支持 @param@returns@example@since 等标准标签。


🌐 六、最终效果

访问:

  • http://localhost:5173/api/common/ → 展示 @my-utils/common 所有函数
  • 自动解析类型、参数、示例代码
  • 侧边栏按包分类,清晰隔离 browser/node/common

🛠 可选增强

1. 自定义主题样式

docs/.vitepress/theme/index.ts 中扩展 VitePress 主题,美化 API 页面。

2. 跳过无导出的内部函数

确保只导出需要文档化的函数(TypeDoc 默认只处理 export 的内容)。

3. 多入口支持

如果一个包有多个子模块(如 dom/, storage/),可配置多个 entryPoints

entryPoints: ['packages/browser/src/dom/index.ts','packages/browser/src/storage/index.ts'
]

4. CI 自动部署文档

配合 GitHub Pages / Vercel,每次 push 自动构建并部署文档站点。


✅ 总结

步骤 工具 作用
1 TypeDoc 从 TS 源码提取结构化 API 数据
2 vitepress-plugin-typedoc 将 TypeDoc 输出转为 VitePress Markdown
3 自定义脚本 按包批量生成 + 构建侧边栏
4 JSDoc 提供高质量注释内容

这套方案完全自动化,只需写好代码和注释,文档即同步生成,且与 Monorepo 结构天然契合。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询