Skip to content

Commit 54e1418

Browse files
fix: use createRequire for node_modules resolution in VSCode extension (#1171)
* fix: use createRequire for node_modules resolution in VSCode extension The VSCode extension server is bundled with webpack, which replaces `require` with its own module system. webpack's `require.resolve` does not support the `paths` option and returns a numeric module ID rather than a file path, causing "Cannot find module" errors for custom check packages (e.g. `@grafikr/theme-check-extension/recommended.yml`). Replace `require.resolve(pathLike, { paths: getAncestorNodeModules(root) })` with `createRequire` from `node:module`, which creates a real Node.js require function that bypasses webpack's substitution. Node.js's native module resolution already traverses ancestor node_modules directories automatically, so `getAncestorNodeModules` is no longer needed. Fixes #1170 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: add changeset for node_modules resolution fix Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Update packages/theme-check-node/src/config/resolve/read-yaml.ts --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 6fe8023 commit 54e1418

2 files changed

Lines changed: 14 additions & 13 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@shopify/theme-check-node': patch
3+
---
4+
5+
Fix VSCode extension failing to resolve custom check packages from node_modules (e.g. `extends: '@acme/theme-check-extension/recommended.yml'`). The extension server is webpack-bundled, so `require.resolve` was being handled by webpack instead of Node.js, returning a module ID rather than a file path. Now uses `createRequire` from `node:module` to get real Node.js resolution.

packages/theme-check-node/src/config/resolve/read-yaml.ts

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { CheckSettings, Modes, Severity } from '@shopify/theme-check-common';
22
import { realpathSync } from 'node:fs';
33
import fs from 'node:fs/promises';
4+
import { createRequire } from 'node:module';
45
import path from 'node:path';
56
import { parse } from 'yaml';
67
import { AbsolutePath } from '../../temp';
@@ -172,7 +173,14 @@ function resolvePath(
172173
return path.resolve(root, pathLike);
173174
}
174175

175-
return realpathSync(require.resolve(pathLike, { paths: getAncestorNodeModules(root)! }));
176+
// Use createRequire to get the real Node.js require rather than webpack's
177+
// substitute. When the VSCode extension server is bundled, `require.resolve`
178+
// becomes webpack's version which doesn't support the `paths` option and
179+
// returns a numeric module ID instead of a file path. createRequire creates
180+
// a real Node.js require function that resolves from the given directory,
181+
// traversing ancestor node_modules automatically.
182+
const req = createRequire(path.join(root, '__placeholder'));
183+
return realpathSync(req.resolve(pathLike));
176184
}
177185

178186
/**
@@ -237,15 +245,3 @@ function isString(thing: unknown): thing is string {
237245
function asArray<T>(thing: T | T[]): T[] {
238246
return Array.isArray(thing) ? thing : [thing];
239247
}
240-
241-
function getAncestorNodeModules(dir: string): string[] {
242-
const root = path.parse(dir).root;
243-
const nodeModulesPaths: string[] = [];
244-
245-
while (dir !== root) {
246-
nodeModulesPaths.push(path.join(dir, 'node_modules'));
247-
dir = path.dirname(dir);
248-
}
249-
250-
return nodeModulesPaths;
251-
}

0 commit comments

Comments
 (0)