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

pnpm Monorepo中Jest无法解析共享UI组件的配置问题

pnpm Monorepo中Jest无法解析跨库组件的问题

问题描述

在pnpm管理的React+TypeScript+Vite Monorepo项目中,Hello.spec.tsx测试文件无法解析位于/libs/ui库中的Test组件。使用标准导入语法import { Test } from "@libs/ui"时,Jest抛出模块无法找到的错误,但普通测试文件(如add.spec.ts)可正常运行,不确定问题源于Monorepo跨包模块解析还是Jest路径配置。

相关代码示例

pds/src/components/Hello.tsx

import { Test } from "@libs/ui"; // Test组件来自monorepo/libs/ui
export default () => (
  <>
    <p>Hello Diego was here</p>
    <Test />
  </>
);

pds/src/components/Hello.spec.tsx

/**
 * @jest-environment jsdom
 */

import { render, screen } from '@testing-library/react'
import Component from './Hello';
import '@testing-library/jest-dom'


test('renders paragraph and Test component', () => {
  render(<Component />)

  // 检查段落是否渲染
  expect(screen.getByText(/Hello Diego was here/i)).toBeInTheDocument()
})

/libs/ui/src/Test.tsx

export const Test: React.FC = () => <p>This is a Test Component</p>

可正常运行的测试文件示例

/pds/src/add.ts

export const add = (a: number, b: number) => {
  return a + b;
}

/pds/src/add.spec.ts

import { add } from "./add";

describe("add function", () => {
  it("should add two numbers together", () => {
    const result = add(10, 5);
    expect(result).toBe(15);
  });
});

问题复现步骤

  • 安装pnpm
  • 创建monorepo文件夹
  • 进入monorepo执行pnpm init
  • 创建monorepo/pnpm-workspace.yaml并填入对应内容
  • 创建apps和libs两个文件夹
  • 进入apps执行pnpm create vite@latest,选择typescript和react模板
  • 进入libs执行pnpm create vite@latest,选择typescript和react模板
  • 替换pds和ui项目的package.json、vite.config.ts、tsconfig.json内容

项目结构

/monorepo
  ├── pnpm-workspace.yaml
  ├── package.json
  ├── jest.config.ts
  ├── tsconfig.build.json
  ├── tsconfig.json
  ├── /apps
  │    └── /pds
  │        ├── package.json
  │        ├── vite.config.ts
  │        └── tsconfig.json
  └── /libs
       └── /ui
           ├── tsconfig.json
           ├── vite.config.ts
           └── package.json

配置文件详情

/monorepo/pnpm-workspace.yaml

packages:
  - 'apps/*'
  - 'libs/*'

/monorepo/package.json

{
  "name": "monorepo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "pds": "pnpm --filter @apps/pds",
    "ui": "pnpm --filter @libs/ui",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@eslint/js": "^9.19.0",
    "@testing-library/jest-dom": "^6.6.3",
    "@types/jest": "^29.5.14",
    "eslint": "^9.20.0",
    "globals": "^15.14.0",
    "jest": "^29.7.0",
    "jest-environment-jsdom": "^29.7.0",
    "ts-jest": "^29.2.5",
    "ts-node": "^10.9.2",
    "typescript": "~5.7.2",
    "typescript-eslint": "^8.22.0",
    "vite": "^6.1.0"
  }
}

/monorepo/jest.config.ts

import { Config } from 'jest';

const config: Config = {
  // verbose: true,
  preset: "ts-jest",
  testEnvironment: "jsdom",
  transform: {
    "^.+\\.(ts|tsx)$": "ts-jest",
  },
  projects: [
    {
      displayName: 'pds',
      preset: 'ts-jest',
      testEnvironment: 'jsdom',
      testMatch: ['<rootDir>/apps/pds/src/**/*.spec.tsx', '<rootDir>/apps/pds/src/**/*.spec.ts'],
      transform: {
        '^.+\\.(ts|tsx)$': 'ts-jest'
      },
    }
  ],
};

module.exports = config;

解决方案

1. 配置Jest模块映射

Jest无法自动识别pnpm workspace的别名,需手动在jest.config.ts中添加moduleNameMapper,将@libs/ui映射到实际源码路径:

import { Config } from 'jest';
import path from 'path';

const config: Config = {
  preset: "ts-jest",
  testEnvironment: "jsdom",
  transform: {
    "^.+\\.(ts|tsx)$": "ts-jest",
  },
  projects: [
    {
      displayName: 'pds',
      preset: 'ts-jest',
      testEnvironment: 'jsdom',
      testMatch: ['<rootDir>/apps/pds/src/**/*.spec.tsx', '<rootDir>/apps/pds/src/**/*.spec.ts'],
      transform: {
        '^.+\\.(ts|tsx)$': 'ts-jest'
      },
      // 添加模块映射
      moduleNameMapper: {
        '^@libs/ui$': path.resolve(__dirname, 'libs/ui/src'),
        '^@libs/ui/(.*)$': path.resolve(__dirname, 'libs/ui/src/$1'),
      },
      // 确保Jest处理tsx文件扩展名
      moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
    }
  ],
};

module.exports = config;

2. 同步TypeScript路径配置

确保根目录tsconfig.json中配置了对应路径别名,且pds的tsconfig.json继承该配置:
/monorepo/tsconfig.json

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@libs/ui": ["libs/ui/src"],
      "@libs/ui/*": ["libs/ui/src/*"]
    }
  },
  "include": ["apps/**/*", "libs/**/*"]
}

/apps/pds/tsconfig.json(需添加extends)

{
  "extends": "../../tsconfig.json",
  // 其他原有配置...
}

3. 确保包已正确链接

执行pnpm install让pnpm自动处理workspace包的依赖链接,或手动执行:

pnpm --filter @apps/pds add @libs/ui@workspace:*

4. 检查UI包的入口配置

确保/libs/ui/package.json中指定了正确的入口文件,若有统一导出的index.ts:

{
  "name": "@libs/ui",
  "main": "./src/index.ts",
  "exports": {
    ".": "./src/index.ts",
    "./src/*": "./src/*"
  }
}

(若未创建index.ts,需在其中导出Test组件:export { Test } from './Test';)

原因说明

Jest不会自动读取Vite的解析配置或pnpm workspace的别名规则,必须通过moduleNameMapper手动映射别名到实际文件路径。同时需要同步TypeScript的paths配置,保证编译和测试阶段的路径解析一致。

内容的提问来源于stack exchange,提问作者Diego Salas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 11:35:55