Vite4+pnpm Monorepo中Sass无法正常工作问题求助
问题分析与解决方案
是不是Vite+pnpm的Bug?
不是Bug,核心原因是pnpm monorepo的依赖软链机制与Vite执行时的依赖解析时机不匹配:
- 根目录安装的
sass作为devDependencies,子项目通过pnpm的workspace软链共享,但首次pnpm i后,部分子项目的依赖软链可能未完全初始化完成,此时启动Vite会触发预处理器依赖查找失败。 - 子项目的
clean脚本删除了node_modules,这会破坏pnpm自动生成的软链依赖关系;而单独执行命令时,pnpm会自动重建软链,因此能正常运行。
快速修复方案
- 修改子项目的
clean脚本,仅删除构建产物,保留pnpm自动管理的node_modules:
"clean": "rimraf dist"
- 根目录执行
pnpm run clean后,重新执行pnpm i,再运行构建/开发命令即可避免该问题。
Vite+pnpm+Monorepo+TypeScript最佳实践示例
项目结构
├── apps/ │ ├── admin/ │ │ ├── src/ │ │ │ ├── main.ts │ │ │ └── App.vue │ │ ├── index.html │ │ ├── package.json │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ └── merchant/ │ ├── src/ │ ├── index.html │ ├── package.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── packages/ (可选,存放公共业务包) ├── pnpm-workspace.yaml ├── package.json ├── tsconfig.base.json └── .npmrc
核心配置文件
根目录 pnpm-workspace.yaml
packages: - 'apps/**' - 'packages/**' # 有公共包时保留
根目录 package.json
{ "name": "monorepo-root", "private": true, "type": "module", "scripts": { "dev": "pnpm -r --parallel --filter='./apps/*' run dev", "admin": "pnpm --filter='./apps/admin' run dev", "merchant": "pnpm --filter='./apps/merchant' run dev", "clean": "pnpm -r --filter='./apps/*' run clean && rimraf node_modules", "build": "pnpm -r --filter='./apps/*' run build" }, "devDependencies": { "sass": "^1.69.5", "typescript": "^5.2.2", "rimraf": "^5.0.5" }, "engines": { "pnpm": ">=8.0.0" } }
根目录 .npmrc
# 关闭严格peer依赖检查,适配monorepo场景 strict-peer-dependencies=false # 强制hoist预处理器与构建工具,确保子项目能正常访问 public-hoist-patterns[]=*sass* public-hoist-patterns[]=*vite*
根目录 tsconfig.base.json
{ "compilerOptions": { "target": "ES2020", "useDefineForClassFields": true, "module": "ESNext", "lib": ["ES2020", "DOM", "DOM.Iterable"], "skipLibCheck": true, "moduleResolution": "bundler", "allowImportingTsExtensions": true, "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "preserve", "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true }, "include": [], "references": [ {"path": "./apps/admin/tsconfig.json"}, {"path": "./apps/merchant/tsconfig.json"} ] }
子项目(admin/merchant)package.json
{ "name": "@monorepo/admin", "private": true, "type": "module", "scripts": { "dev": "NODE_OPTIONS=--max-old-space-size=4096 vite", "clean": "rimraf dist", "build": "NODE_OPTIONS=--max-old-space-size=8192 vite build", "preview": "vite preview" }, "dependencies": { "vue": "^3.3.8" }, "devDependencies": { "@vitejs/plugin-vue": "^4.4.0", "vite": "^5.0.0", "typescript": "^5.2.2" }, "peerDependencies": { "sass": "^1.69.5" } }
子项目 vite.config.ts
import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], resolve: { // 保留软链,避免pnpm依赖解析异常 preserveSymlinks: true } })
子项目 tsconfig.json
{ "extends": "../../tsconfig.base.json", "compilerOptions": { "composite": true, "baseUrl": ".", "paths": { "@/*": ["./src/*"] } }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }] }
子项目 tsconfig.node.json
{ "compilerOptions": { "composite": true, "skipLibCheck": true, "module": "ESNext", "moduleResolution": "bundler", "allowSyntheticDefaultImports": true }, "include": ["vite.config.ts"] }
内容的提问来源于stack exchange,提问作者markin
相关产品推荐
相关产品推荐

