You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vite4+pnpm Monorepo中Sass无法正常工作问题求助

问题分析与解决方案

是不是Vite+pnpm的Bug?

不是Bug,核心原因是pnpm monorepo的依赖软链机制与Vite执行时的依赖解析时机不匹配:

  • 根目录安装的sass作为devDependencies,子项目通过pnpm的workspace软链共享,但首次pnpm i后,部分子项目的依赖软链可能未完全初始化完成,此时启动Vite会触发预处理器依赖查找失败。
  • 子项目的clean脚本删除了node_modules,这会破坏pnpm自动生成的软链依赖关系;而单独执行命令时,pnpm会自动重建软链,因此能正常运行。

快速修复方案

  1. 修改子项目的clean脚本,仅删除构建产物,保留pnpm自动管理的node_modules:
"clean": "rimraf dist"
  1. 根目录执行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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 16:33:11