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

Nx Monorepo中Vite Dev Server多版本依赖解析异常问题

解决Nx + Vite Monorepo中Dev Server依赖版本不符的问题

项目结构

/apps/myApp
  /package.json
  /vite.config.ts(继承根级vite.config.ts)
/libs
  /myLib1
    /package.json
  /myLib2
    /package.json
package.json
package-lock.json
vite.config.ts

问题重现

  • 根package.json依赖somePackage@1.2.3,myLib2单独依赖somePackage@1.1.1
  • npm install后,根node_modules安装1.2.3版本,myLib2的node_modules安装1.1.1版本,符合预期
  • 仅在Vite Dev Server环境下,myLib2的代码会加载根node_modules中的1.2.3版本;Nx build打包时则能正确使用1.1.1版本
  • 通过Chrome DevTools确认,myLib2的组件实际解析的是根目录下的依赖而非自身本地依赖

问题根因

Vite的optimizeDeps预构建机制会从应用入口出发,优先抓取根node_modules中的依赖做预构建缓存。即便子库有自己的本地node_modules版本,Dev Server运行时也会复用预构建后的根依赖,导致子库的特定版本被覆盖。

临时低效方案

将冲突包逐个加入optimizeDeps.exclude数组,跳过预构建:

optimizeDeps: {
  exclude: ['somePackage'],
  // ...其他原有配置
}

高效解决方案

方案1:配置resolve规则,强制子库优先使用本地依赖

修改根级vite.config.ts,添加自定义解析逻辑,让子库的代码优先加载自身node_modules中的依赖:

// 需额外引入fs模块
import fs from 'fs';

export default defineConfig(({ mode }) => {
  // ...原有代码
  return {
    // ...原有配置
    resolve: {
      alias: fs.readdirSync(path.resolve(__dirname, 'libs')).map(lib => {
        const libDir = path.resolve(__dirname, 'libs', lib);
        const pkgPath = path.join(libDir, 'package.json');
        if (!fs.existsSync(pkgPath)) return null;
        
        const pkg = require(pkgPath);
        const deps = Object.keys(pkg.dependencies || {});
        
        return deps.map(dep => ({
          find: dep,
          customResolver: (source, importer) => {
            // 当导入方是当前子库时,返回子库本地的依赖路径
            if (importer?.includes(libDir)) {
              return path.resolve(libDir, 'node_modules', dep);
            }
            // 其他场景使用根目录依赖
            return source;
          }
        }));
      }).flat().filter(Boolean),
    },
    // ...原有配置
  };
});

方案2:自动排除所有子库本地依赖的预构建

通过脚本自动扫描所有子库的依赖,批量加入optimizeDeps.exclude,无需手动逐个添加:

// 需额外引入fs模块
import fs from 'fs';

export default defineConfig(({ mode }) => {
  // ...原有代码
  // 扫描所有子库的依赖列表
  const libDeps = fs.readdirSync(path.resolve(__dirname, 'libs')).flatMap(lib => {
    const pkgPath = path.resolve(__dirname, 'libs', lib, 'package.json');
    if (fs.existsSync(pkgPath)) {
      const pkg = require(pkgPath);
      return Object.keys(pkg.dependencies || {});
    }
    return [];
  });
  
  return {
    // ...原有配置
    optimizeDeps: {
      esbuildOptions: {
        target: 'esnext',
        loader: {
          '.js': 'jsx',
          '.ts': 'tsx',
        },
      },
      // 排除所有子库本地安装的依赖,避免预构建覆盖版本
      exclude: [...new Set(libDeps)],
    },
    // ...原有配置
  };
});

环境信息

  • vite: 4.3.4
  • nx: 16.2.2

根级vite.config.ts原始配置

/// <reference types="vitest" />
import { defineConfig, loadEnv } from 'vite';
import react from '@vitejs/plugin-react';
import commonjs from 'vite-plugin-commonjs';
import viteTsConfigPaths from 'vite-tsconfig-paths';
import path from 'path';
import { nodePolyfills } from 'vite-plugin-node-polyfills';

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, `${process.cwd()}/apps/myApp/env`, '');

  return {
    // vite config
    cacheDir: '../../node_modules/.vite/myApp',

    build: {
      commonjsOptions: {
        include: [/myApp/, /node_modules/],
      },
    },

    envDir: `${process.cwd()}/apps/myApp/env`,

    esbuild: {
      loader: 'tsx',
      include: [
        'apps/**/*.(ts|tsx|js|jsx)',
        'libs/**/*.(ts|tsx|js|jsx)',
      ],
      exclude: [],
    },

    optimizeDeps: {
      esbuildOptions: {
        target: 'esnext',
        loader: {
          '.js': 'jsx',
          '.ts': 'tsx',
        },
      },
    },

    server: {
      port: 8080,
      host: 'localhost',
      fs: {
        // Allow serving files from two levels up to the project root
        allow: ['../..'],
      },
    },
    preview: {
      port: 8080,
    },

    plugins: [
      react(),
      commonjs({
      }),
      viteTsConfigPaths({
        root: '../../',
      }),
      nodePolyfills({
        include: ['util'],
        globals: {
          Buffer: true,
        },
      }),
    ],
  };
});

内容的提问来源于stack exchange,提问作者Mark McKim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 10:20:08