# monorepo工程化模板 **Repository Path**: vmto/monorepo-template ## Basic Information - **Project Name**: monorepo工程化模板 - **Description**: 父项目包含三个独立的 npm 项目,两个 Vue 项目、一个 React 项目;另外还有公共组件库和工具库,组件库支持按需导入和全局注册。 - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-03-27 - **Last Updated**: 2025-05-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 前端工程化,是我最近两年主要的研究方向,手动打包已成过去,CI/CD自动打包部署已成主流。 `Monorepo` 工程化是 `npm `项目管理方案,单个仓库管理多个项目,在版本控制、代码共享、构建部署等方面效率大增,减少项目复杂性。 > 本篇,重在梳理流程,概念介绍和组件/插件一笔带过 ! ## 创建父项目 ````bash # 开发环境 版本说明 node v22.10.0 npm v10.9.0 vite v6.2.3 pnpm v8.14.1 # 创建父项目 pnpm create vite project use Vue use typescript ```` > 删除无关目录和文件:`public`、`src`、 `index.html` ## 工作目录和配置 ````bash # 工作目录 mkdir packages # 配置文件及内容 # pnpm-workspace.yaml packages: - components/** - packages/** - utils/** ```` ## 创建子项目 > 三个独立的 `npm` 项目 两个 `Vue` 项目、一个 `React` 项目 ````bash # 进入工作目录 cd packages # 北京项目 Vue $ pnpm create vite beijing | o Select a framework: | Vue | o Select a variant: | TypeScript # 南京项目 Vue $ pnpm create vite nanjing | o Select a framework: | Vue | o Select a variant: | TypeScript # 杭州项目 React $ pnpm create vite hangzhou | o Select a framework: | React | o Select a variant: | TypeScript # 指定版本 pnpm add react@~18.3.1 react-dom@~18.3.1 pnpm add @types/react@~18.3.12 @types/react-dom@~18.3.1 # 如果在根目录操作,命令参数这样: pnpm add react@~18.3.1 react-dom@~18.3.1 -F hangzhou pnpm add @types/react@~18.3.12 @types/react-dom@~18.3.1 -F hangzhou ```` ## 名称统一 @主包名/子包名 > 避免项目命名冲突,子项目前加上父项目名称,并以 `@` 开头 ````bash # 父项目 package.json { "name": "project", "scripts": { ... }, "dependencies": { "vue": "^3.5.13" }, "devDependencies": { ... } } # 北京项目 package.json { "name": "@project/beijing", "scripts": { ... }, "dependencies": { ... }, "devDependencies": { ... } } # 其余子项目省略... ```` ## 继承父项目配置 > 删除 `Vue` 子项目中这俩文件:`tsconfig.app.json` `tsconfig.node.json` 保留这个 `tsconfig.json` ,用于继承父项目配置 ````bash # beijing/tsconfig.json # nanjing/tsconfig.json { "extends": "../../tsconfig.json", "compilerOptions": { "jsx": "preserve", "jsxImportSource": "vue" }, "include": [ "src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", ] } ```` ## 准备启动 ````bash # 父项目 package.json { "scripts": { "dev:beijing": "pnpm run -C packages/beijing dev", "dev:nanjing": "pnpm run -C packages/nanjing dev", "dev:hangzhou": "pnpm run -C packages/hangzhou dev", "build:beijing": "pnpm run -C packages/beijing build", "build:nanjing": "pnpm run -C packages/nanjing build", "build:hangzhou": "pnpm run -C packages/hangzhou build" } } # 安装 全局依赖(子项目依赖也会安装) pnpm install # 启动 北京项目 pnpm run dev:beijing > project\packages\beijing > vite Port 5173 is in use, trying another one... VITE v6.2.3 ready in 514 ms ➜ Local: http://localhost:5174/ ➜ Network: use --host to expose ➜ press h + enter to show help ```` > 三个子项目必须启动成功,否则不要往下看,先折腾以上流程! > 三个子项目必须启动成功,否则不要往下看,先折腾以上流程! > 三个子项目必须启动成功,否则不要往下看,先折腾以上流程! ## 目录结构 > 目录仅供参考,以防目录创建错误 ````bash │ package.json │ pnpm-workspace.yaml │ README.md │ tsconfig.app.json │ tsconfig.json │ tsconfig.node.json │ vite.config.ts │ ├─components │ │ components.ts │ │ index.ts │ │ package.json │ │ tsconfig.json │ │ │ └─src │ ├─btn │ │ Btn.vue │ │ index.ts │ │ │ └─list │ index.ts │ List.vue │ ├─packages │ ├─beijing │ │ │ index.html │ │ │ package.json │ │ │ tsconfig.json │ │ │ vite.config.ts │ │ │ │ │ ├─public │ │ └─src │ │ │ ├─hangzhou │ │ │ index.html │ │ │ package.json │ │ │ tsconfig.json │ │ │ vite.config.ts │ │ │ │ │ ├─public │ │ └─src │ │ │ └─nanjing │ │ index.html │ │ package.json │ │ tsconfig.json │ │ vite.config.ts │ │ │ ├─public │ └─src │ └─utils create-class.ts index.ts package.json tsconfig.json ```` ## 安装依赖 > 安装 `@types/node` ,否则新特性爆红:比如 `Object.entries` ````bash # 父项目 > pnpm add @types/node -D # 报错信息  ERR_PNPM_ADDING_TO_ROOT  Running this command will add the dependency to the workspace root, which might not be what you want - if you reall y meant it, make it explicit by running this command again with the -w flag (or --workspace-root). If you don't want to see this warning anym ore, you may set the ignore-workspace-root-check setting to true. # 增加参数 -w > pnpm add @types/node -D -w devDependencies: + @types/node 22.13.13 ```` > `pnpm` 常用命令 ````bash # 安装到父项目 生产依赖(dependencies) pnpm add --workspace-root pnpm add -w # 安装到父项目 开发依赖(devDependencies) pnpm add -D -w pnpm add -Dw # 安装到子项目 pnpm add --filter pnpm add -F ```` ## 安装组件和插件 > 北京项目、南京项目测试 `Vue` 组件和插件 > 杭州项目是 `React` ,只测试插件 ````bash # 根目录 输入以下命令 # 安装组件 pnpm add @project/components -F beijing pnpm add @project/components -F nanjing # 安装插件 pnpm add @project/utils -F beijing pnpm add @project/utils -F nanjing pnpm add @project/utils -F hangzhou pnpm add @project/utils -F hangzhou ```` > 使用组件和插件 北京项目 -- 按需导入 ````bash # beijing/src/App.vue ```` 南京项目 -- 全局导入 ````bash # nanjing/src/main.ts import { createApp } from 'vue' import components from '@project/components' import App from './App.vue' const app = createApp(App); // 全局注册 app.use(components); app.mount('#app'); # nanjing/src/App.vue ```` 杭州项目 ````bash # hangzhou/src/App.tsx import {useClassName} from '@project/utils' import './app.css' const {cls} = useClassName('h1'); const {cls: btnCls} = useClassName('button'); function App() { return ( <>

杭州项目

) } export default App ```` 资源路径设为相对: `base: './'` 方便预览打包文件 ````bash # 子项目 配置 vite.config.ts import { defineConfig } from 'vite' export default defineConfig({ base: './', // 新增 }) ```` 北京项目 打包结果: ````bash project> pnpm run build:beijing > pnpm run -C packages/beijing build > vue-tsc -b && vite build vite v6.2.3 building for production... ✓ 24 modules transformed. dist/index.html 0.46 kB │ gzip: 0.31 kB dist/assets/index-D3Hsad5Y.css 0.30 kB │ gzip: 0.20 kB dist/assets/index-DBqhfqk1.js 60.86 kB │ gzip: 24.49 kB ✓ built in 651ms ```` 南京项目 打包结果: ````bash project> pnpm run build:nanjing > pnpm run -C packages/nanjing build > vue-tsc -b && vite build vite v6.2.3 building for production... ✓ 24 modules transformed. dist/index.html 0.46 kB │ gzip: 0.31 kB dist/assets/index-D3Hsad5Y.css 0.30 kB │ gzip: 0.20 kB dist/assets/index-BBGDBeaA.js 61.56 kB │ gzip: 24.77 kB ✓ built in 654ms ```` 杭州项目 打包结果: ````bash project> pnpm run build:hangzhou > pnpm run -C packages/hangzhou build > tsc -b && vite build vite v6.2.3 building for production... ✓ 29 modules transformed. dist/index.html 0.46 kB │ gzip: 0.31 kB dist/assets/index-DSCNS8nl.css 0.11 kB │ gzip: 0.09 kB dist/assets/index-BJtZOIcg.js 144.20 kB │ gzip: 46.38 kB ✓ built in 658ms ```` ## 问题合集 > 下载父项目公共组件或插件,总是提示404,父项目增加文件 `.npmrc` ````bash # 内容如下 link-workspace-packages=true ```` 注意通配符:两个 `*` ````bash # pnpm-workspace.yaml packages: - components/** - packages/** - utils/** ```` > 引入父项目公共组件或插件爆红,修改父项目文件 `tsconfig.json` ````bash # tsconfig.json { "paths": { "@project/components": [ "components/src" ], "@project/utils": [ "utils" ] }, } ```` > 如果还不行,关掉编辑器,重新打开! 如果还不行,父项目配置用我这个: ````bash # tsconfig.json { "extends": "@vue/tsconfig/tsconfig.dom.json", "compilerOptions": { "target": "ES2020", "jsx": "preserve", "lib": [ "ES2020", "DOM", "DOM.Iterable" ], "useDefineForClassFields": true, "baseUrl": ".", "module": "ESNext", "moduleResolution": "Bundler", "paths": { "@project/components": [ "components/src" ], "@project/utils": [ "utils" ] }, "resolveJsonModule": true, "allowImportingTsExtensions": true, /* Linting */ "strict": true, "noFallthroughCasesInSwitch": true, "noUnusedLocals": true, "noUnusedParameters": true, "noUncheckedSideEffectImports": true, "noEmit": true, "isolatedModules": true, "skipLibCheck": true }, "references": [ { "path": "./tsconfig.node.json" }, ], "include": [ "./global.d.ts" ] } ```` ````bash # global.d.ts declare module '*.css' { const classes: { readonly [key: string]: string } export default classes } // declare module '*.less'; declare module '*.less' { const classes: { readonly [key: string]: string } export default content } ````