|
1 | 1 | /** |
2 | | - * DO NOT EDIT THIS FILE UNLESS YOU DEFINITELY KNWO WHAT YOU ARE DOING. |
| 2 | + * DO NOT EDIT THIS FILE UNLESS YOU DEFINITELY KNOW WHAT YOU ARE DOING. |
3 | 3 | * THIS ENSURES THAT INTEGRATION TESTS ARE LOADING THE CORRECT DEPENDENCIES. |
4 | 4 | */ |
5 | 5 | const { getDefaultConfig } = require('expo/metro-config'); |
@@ -30,25 +30,93 @@ const clerkExpoPath = getClerkExpoPath(); |
30 | 30 | const clerkMonorepoPath = clerkExpoPath?.replace(/\/packages\/expo$/, ''); |
31 | 31 |
|
32 | 32 | /** @type {import('expo/metro-config').MetroConfig} */ |
33 | | -const config = { |
34 | | - ...getDefaultConfig(__dirname), |
35 | | - watchFolders: [clerkMonorepoPath], |
36 | | - resolver: { |
37 | | - sourceExts: ['js', 'json', 'ts', 'tsx', 'cjs', 'mjs'], |
38 | | - nodeModulesPaths: [ |
39 | | - path.resolve(__dirname, 'node_modules'), |
40 | | - clerkExpoPath && `${clerkMonorepoPath}/node_modules`, |
41 | | - clerkExpoPath && `${clerkExpoPath}/node_modules`, |
42 | | - ], |
43 | | - // This is a workaround for a to prevent multiple versions of react and react-native from being loaded. |
44 | | - // https://github.com/expo/expo/pull/26209 |
45 | | - blockList: [ |
46 | | - clerkExpoPath && new RegExp(`${clerkMonorepoPath}/node_modules/react`), |
47 | | - clerkExpoPath && new RegExp(`${clerkMonorepoPath}/node_modules/react-native`), |
48 | | - ], |
49 | | - }, |
50 | | -}; |
| 33 | +const config = getDefaultConfig(__dirname); |
51 | 34 |
|
52 | | -module.exports = { |
53 | | - ...config, |
54 | | -}; |
| 35 | +// Only customize Metro config when running from monorepo |
| 36 | +if (clerkMonorepoPath) { |
| 37 | + console.log('[Metro Config] Applying monorepo customizations'); |
| 38 | + config.watchFolders = [clerkMonorepoPath]; |
| 39 | + |
| 40 | + // Disable file watching to prevent infinite reload loops in integration tests |
| 41 | + config.watchFolders = [clerkMonorepoPath]; |
| 42 | + config.watcher = { |
| 43 | + healthCheck: { |
| 44 | + enabled: false, |
| 45 | + }, |
| 46 | + }; |
| 47 | + |
| 48 | + // Prioritize local node_modules over monorepo node_modules |
| 49 | + config.resolver.nodeModulesPaths = [path.resolve(__dirname, 'node_modules'), `${clerkMonorepoPath}/node_modules`]; |
| 50 | + |
| 51 | + // Explicitly map @clerk packages to their source locations |
| 52 | + // Point to the root of the package so Metro can properly resolve subpath exports |
| 53 | + config.resolver.extraNodeModules = { |
| 54 | + '@clerk/clerk-react': path.resolve(clerkMonorepoPath, 'packages/react'), |
| 55 | + '@clerk/clerk-expo': path.resolve(clerkMonorepoPath, 'packages/expo'), |
| 56 | + '@clerk/shared': path.resolve(clerkMonorepoPath, 'packages/shared'), |
| 57 | + '@clerk/types': path.resolve(clerkMonorepoPath, 'packages/types'), |
| 58 | + }; |
| 59 | + |
| 60 | + // This is a workaround to prevent multiple versions of react and react-native from being loaded. |
| 61 | + // Block React/React-Native in both monorepo root and all package node_modules |
| 62 | + // Use word boundaries to avoid blocking clerk-react |
| 63 | + // https://github.com/expo/expo/pull/26209 |
| 64 | + const escapedPath = clerkMonorepoPath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); |
| 65 | + config.resolver.blockList = [ |
| 66 | + // Block monorepo root node_modules for react/react-native/react-dom |
| 67 | + new RegExp(`${escapedPath}/node_modules/react/`), |
| 68 | + new RegExp(`${escapedPath}/node_modules/react$`), |
| 69 | + new RegExp(`${escapedPath}/node_modules/react-dom/`), |
| 70 | + new RegExp(`${escapedPath}/node_modules/react-dom$`), |
| 71 | + new RegExp(`${escapedPath}/node_modules/react-native/`), |
| 72 | + new RegExp(`${escapedPath}/node_modules/react-native$`), |
| 73 | + // Block react in monorepo's pnpm store |
| 74 | + new RegExp(`${escapedPath}/node_modules/\\.pnpm/.*/node_modules/react/`), |
| 75 | + new RegExp(`${escapedPath}/node_modules/\\.pnpm/.*/node_modules/react$`), |
| 76 | + new RegExp(`${escapedPath}/node_modules/\\.pnpm/.*/node_modules/react-dom/`), |
| 77 | + new RegExp(`${escapedPath}/node_modules/\\.pnpm/.*/node_modules/react-dom$`), |
| 78 | + new RegExp(`${escapedPath}/node_modules/\\.pnpm/.*/node_modules/react-native/`), |
| 79 | + new RegExp(`${escapedPath}/node_modules/\\.pnpm/.*/node_modules/react-native$`), |
| 80 | + // Block react/react-native/react-dom in all package node_modules |
| 81 | + new RegExp(`${escapedPath}/packages/.*/node_modules/react/`), |
| 82 | + new RegExp(`${escapedPath}/packages/.*/node_modules/react$`), |
| 83 | + new RegExp(`${escapedPath}/packages/.*/node_modules/react-dom/`), |
| 84 | + new RegExp(`${escapedPath}/packages/.*/node_modules/react-dom$`), |
| 85 | + new RegExp(`${escapedPath}/packages/.*/node_modules/react-native/`), |
| 86 | + new RegExp(`${escapedPath}/packages/.*/node_modules/react-native$`), |
| 87 | + ]; |
| 88 | + |
| 89 | + // Custom resolver to handle package.json subpath exports for @clerk packages |
| 90 | + // This enables Metro to resolve imports like '@clerk/clerk-react/internal' |
| 91 | + const originalResolveRequest = config.resolver.resolveRequest; |
| 92 | + config.resolver.resolveRequest = (context, moduleName, platform) => { |
| 93 | + // Check if this is a @clerk package with a subpath |
| 94 | + const clerkPackageMatch = moduleName.match(/^(@clerk\/[^/]+)\/(.+)$/); |
| 95 | + if (clerkPackageMatch && config.resolver.extraNodeModules) { |
| 96 | + const [, packageName, subpath] = clerkPackageMatch; |
| 97 | + const packageRoot = config.resolver.extraNodeModules[packageName]; |
| 98 | + |
| 99 | + if (packageRoot) { |
| 100 | + // Try to resolve via the subpath-workaround directory (e.g., internal/package.json) |
| 101 | + const subpathDir = path.join(packageRoot, subpath); |
| 102 | + try { |
| 103 | + const subpathPkg = require(path.join(subpathDir, 'package.json')); |
| 104 | + if (subpathPkg.main) { |
| 105 | + const resolvedPath = path.join(subpathDir, subpathPkg.main); |
| 106 | + return { type: 'sourceFile', filePath: resolvedPath }; |
| 107 | + } |
| 108 | + } catch (e) { |
| 109 | + // Subpath directory doesn't exist, continue with default resolution |
| 110 | + } |
| 111 | + } |
| 112 | + } |
| 113 | + |
| 114 | + // Fall back to default resolution |
| 115 | + if (originalResolveRequest) { |
| 116 | + return originalResolveRequest(context, moduleName, platform); |
| 117 | + } |
| 118 | + return context.resolveRequest(context, moduleName, platform); |
| 119 | + }; |
| 120 | +} |
| 121 | + |
| 122 | +module.exports = config; |
0 commit comments