Skip to content

Commit fa2083f

Browse files
committed
fix: loader: typescript module resolver not resolving to source path of symlinked module
1 parent 5bba969 commit fa2083f

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

packages/payload/src/bin/loader/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { fileURLToPath, pathToFileURL } from 'url'
66

77
import { CLIENT_EXTENSIONS } from './clientExtensions.js'
88
import { compile } from './compile.js'
9+
import { resolveOriginalPath } from './resolveOriginalPath.js'
910

1011
interface ResolveContext {
1112
conditions: string[]
@@ -115,7 +116,7 @@ export const resolve: ResolveFn = async (specifier, context, nextResolve) => {
115116
return {
116117
format: resolvedIsTS ? 'ts' : undefined,
117118
shortCircuit: true,
118-
url: pathToFileURL(resolvedModule.resolvedFileName).href,
119+
url: pathToFileURL(await resolveOriginalPath(resolvedModule.resolvedFileName)).href, // The typescript module resolver does not resolve to the original path, but to the symlinked path, if present. This can cause issues
119120
}
120121
}
121122

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import fs from 'fs/promises'
2+
import path from 'path'
3+
4+
/**
5+
* In case any directory in the path contains symlinks, this function attempts to detect that resolves the original path.
6+
*
7+
* Example Input: /Users/alessio/Documents/GitHub/payload-3.0-alpha-demo/node_modules/tailwindcss/resolveConfig.js
8+
* The "tailwindcss" in this example is a symlinked directory.
9+
*
10+
* Example Output: /Users/alessio/Documents/GitHub/payload-3.0-alpha-demo/node_modules/.pnpm/tailwindcss@3.4.3/node_modules/tailwindcss/resolveConfig.js
11+
*/
12+
export async function resolveOriginalPath(filePath: string) {
13+
try {
14+
// Normalize and split the path
15+
const parts = path.resolve(filePath).split(path.sep)
16+
17+
let currentPath = '/'
18+
// skip the first slash
19+
for (const part of parts.slice(1)) {
20+
currentPath = path.join(currentPath, part)
21+
22+
// Check if the current path component is a symlink
23+
const stats = await fs.lstat(currentPath)
24+
if (stats.isSymbolicLink()) {
25+
// Resolve the symlink
26+
const resolvedLink = await fs.readlink(currentPath)
27+
currentPath = path.join(path.dirname(currentPath), resolvedLink)
28+
}
29+
}
30+
31+
return currentPath
32+
} catch (error) {
33+
console.error('Error resolving path:', error)
34+
}
35+
}

0 commit comments

Comments
 (0)