Skip to content

Commit e25e172

Browse files
ntottenclaude
andcommitted
Fix plugin loading for Prettier v2 and improve module resolution
- Use require.resolve with createRequire from target directory - Only convert plugin paths to file:// URLs for Prettier v3+ - For Prettier v2, pass absolute paths that require() can handle 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 79813c8 commit e25e172

File tree

2 files changed

+24
-11
lines changed

2 files changed

+24
-11
lines changed

src/PrettierEditService.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,20 @@ import { isAboveV3 } from "./utils/versions.js";
3333
import { resolveModuleEntry } from "./utils/resolve-module-entry.js";
3434

3535
/**
36-
* Resolve plugin paths to file:// URLs that Prettier can import.
36+
* Resolve plugin paths for Prettier.
3737
* Matches Prettier CLI behavior:
3838
* - URLs pass through
39-
* - Absolute paths → file:// URL
40-
* - Relative paths (./plugin.js) → resolved relative to file, file:// URL
39+
* - Absolute paths → kept as-is or converted to file:// URL (for v3)
40+
* - Relative paths (./plugin.js) → resolved relative to file
4141
* - Package names → resolved from file's directory via createRequire
42+
*
43+
* @param useFileUrls - If true, converts paths to file:// URLs (needed for Prettier v3+ ESM import)
44+
* If false, returns absolute paths (for Prettier v2 require())
4245
*/
4346
async function resolvePluginPaths(
4447
plugins: (string | PrettierPlugin)[] | undefined,
4548
fileName: string,
49+
useFileUrls: boolean,
4650
): Promise<(string | PrettierPlugin)[]> {
4751
if (!plugins) {
4852
return [];
@@ -64,22 +68,25 @@ async function resolvePluginPaths(
6468
continue;
6569
}
6670

67-
// Absolute paths → file:// URL
71+
// Absolute paths
6872
if (path.isAbsolute(plugin)) {
69-
resolvedPlugins.push(pathToFileURL(plugin).href);
73+
resolvedPlugins.push(
74+
useFileUrls ? pathToFileURL(plugin).href : plugin,
75+
);
7076
continue;
7177
}
7278

7379
// Relative paths (./foo or ../foo) → resolve relative to file
7480
if (plugin.startsWith(".")) {
75-
resolvedPlugins.push(pathToFileURL(path.resolve(dir, plugin)).href);
81+
const resolved = path.resolve(dir, plugin);
82+
resolvedPlugins.push(useFileUrls ? pathToFileURL(resolved).href : resolved);
7683
continue;
7784
}
7885

7986
// Package names → resolve from file's directory using createRequire
8087
try {
8188
const resolved = resolveModuleEntry(dir, plugin);
82-
resolvedPlugins.push(pathToFileURL(resolved).href);
89+
resolvedPlugins.push(useFileUrls ? pathToFileURL(resolved).href : resolved);
8390
} catch {
8491
// If resolution fails, pass through and let Prettier handle/report the error
8592
resolvedPlugins.push(plugin);
@@ -351,9 +358,11 @@ export default class PrettierEditService implements Disposable {
351358
this.statusBar.update(FormatterStatus.Disabled);
352359
} else if (resolvedConfig?.plugins) {
353360
// Resolve plugin paths so getSupportInfo can discover their languages
361+
// We're inside isAboveV3 check, so use file:// URLs for ESM import
354362
plugins = await resolvePluginPaths(
355363
resolvedConfig.plugins,
356364
documentUri.fsPath,
365+
true, // Use file:// URLs for Prettier v3+
357366
);
358367
}
359368
}
@@ -520,10 +529,13 @@ export default class PrettierEditService implements Disposable {
520529
}
521530
}
522531

523-
// Resolve plugin paths to file:// URLs for Prettier to import
532+
// Resolve plugin paths for Prettier
533+
// For v3+, use file:// URLs (ESM import); for v2, use absolute paths (require)
534+
const useFileUrls = isAboveV3(prettierInstance.version);
524535
const resolvedPlugins = await resolvePluginPaths(
525536
resolvedConfig?.plugins,
526537
fileName,
538+
useFileUrls,
527539
);
528540
this.loggingService.logInfo("Resolved plugins:", resolvedPlugins);
529541

src/utils/resolve-module-entry.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ export function resolveModuleEntry(
1313
fromDirectory: string,
1414
moduleName: string,
1515
): string {
16-
// Create require from a fake file in the directory to resolve the module
17-
const fakeModuleFile = path.join(fromDirectory, "noop.js");
18-
const require = createRequire(pathToFileURL(fakeModuleFile).href);
16+
// Create a require function rooted in the target directory
17+
// We use a fake file path since createRequire needs a file, not a directory
18+
const fakeFile = path.join(fromDirectory, "noop.js");
19+
const require = createRequire(pathToFileURL(fakeFile).href);
1920
return require.resolve(moduleName);
2021
}

0 commit comments

Comments
 (0)