|
1 | 1 | import { execSync } from 'node:child_process' |
2 | 2 | import { existsSync, readFileSync } from 'node:fs' |
| 3 | +import { createRequire } from 'node:module' |
3 | 4 | import path from 'node:path' |
4 | 5 |
|
5 | 6 | import type { UserConfig } from '@rspress/core' |
@@ -75,6 +76,15 @@ export function createRspressConfig(options: CreateRspressConfigOptions): UserCo |
75 | 76 | const isVscode = vscode === true |
76 | 77 | const headScriptBody = buildHeadScriptBody({ colorMode, themeName, vscode: isVscode }) |
77 | 78 |
|
| 79 | + // Force a single React instance across all compiled theme components. |
| 80 | + // Without this alias, Rspress's rspack may resolve react from the |
| 81 | + // @zpress/ui dist/theme directory (deep inside pnpm's .pnpm store), |
| 82 | + // producing a second copy that triggers "Invalid hook call" errors. |
| 83 | + // Resolve from this package's context (react is a peer dep of @zpress/ui). |
| 84 | + const selfRequire = createRequire(import.meta.url) |
| 85 | + const reactAlias = path.dirname(selfRequire.resolve('react/package.json')) |
| 86 | + const reactDomAlias = path.dirname(selfRequire.resolve('react-dom/package.json')) |
| 87 | + |
78 | 88 | return { |
79 | 89 | root: paths.contentDir, |
80 | 90 | outDir: paths.distDir, |
@@ -130,6 +140,10 @@ export function createRspressConfig(options: CreateRspressConfigOptions): UserCo |
130 | 140 | }, |
131 | 141 | resolve: { |
132 | 142 | alias: { |
| 143 | + // Deduplicate React — pnpm isolation can cause rspack to resolve |
| 144 | + // different physical copies from theme components vs Rspress internals. |
| 145 | + react: reactAlias, |
| 146 | + 'react-dom': reactDomAlias, |
133 | 147 | // Allow generated MDX files in .zpress/content/ to import |
134 | 148 | // zpress React components used in landing pages. |
135 | 149 | '@zpress/ui/theme': path.resolve(import.meta.dirname, 'theme', 'index.tsx'), |
|
0 commit comments