Skip to content

fix(plugin): resolve Windows path and symlink issues#400

Merged
ByteYue merged 3 commits intojackwener:mainfrom
sorlen008:fix/windows-plugin-paths
Mar 25, 2026
Merged

fix(plugin): resolve Windows path and symlink issues#400
ByteYue merged 3 commits intojackwener:mainfrom
sorlen008:fix/windows-plugin-paths

Conversation

@sorlen008
Copy link
Contributor

Fixes #392

What's broken on Windows

Three issues prevent the plugin system from working on Windows:

  1. new URL(import.meta.url).pathname returns /C:/Users/... — the leading slash before the drive letter breaks all path operations. Replaced with fileURLToPath(import.meta.url) which handles this correctly on all platforms.

  2. fs.symlinkSync(..., 'dir') requires admin privileges — Windows directory symlinks need elevated permissions. Changed to use NTFS junctions ('junction') on Windows, which work without admin. Unix keeps the original symlink behavior.

  3. which esbuild doesn't exist on Windows — changed to where esbuild on Windows, which esbuild on Unix.

Files changed

  • src/plugin.ts — 3 path fixes (fileURLToPath), junction on Windows, platform-aware which/where

Testing

  • npx tsc --noEmit — zero type errors
  • npm test — fixed 1 previously-failing test (resolveEsbuildBin). 3 remaining failures are pre-existing and unrelated.

sorlen008 and others added 2 commits March 24, 2026 23:57
- Replace `new URL(import.meta.url).pathname` with `fileURLToPath()` from
  node:url — the former returns `/C:/Users/...` on Windows (leading slash
  before drive letter), breaking path resolution for host linking and
  esbuild binary lookup.

- Use junction (`'junction'`) instead of directory symlink (`'dir'`) on
  Windows in linkHostOpencli — junctions don't require admin privileges,
  while `fs.symlinkSync(..., 'dir')` does on Windows.

- Use `where` instead of `which` on Windows for global esbuild lookup.

All changes are platform-conditional and preserve existing Unix behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- npm execFileSync needs shell:true on Windows (.cmd wrapper)
- esbuild binary is a shebang script, needs shell:true on Windows
- resolveEsbuildBin: prefer .cmd in node_modules/.bin/ on Windows
  over import.meta.resolve (which returns a shebang script)
- Updated test to accept .cmd extension on Windows

Found during UAT testing on Windows 11.
@sorlen008
Copy link
Contributor Author

UAT Results (Windows 11)

Test Result
Path resolution (no leading slash) PASS
Build (tsc --noEmit) PASS
Plugin install (YAML + TS) PASS (after additional fixes)
Plugin unit tests (26/26) PASS
Unix compatibility (platform checks) PASS

UAT found 3 additional Windows issues beyond the original fixes:

  1. npm needs shell: true on Windows (it's a .cmd wrapper)
  2. esbuild binary is a shebang script — needs shell: true on Windows
  3. resolveEsbuildBin should prefer .cmd in node_modules/.bin/ on Windows

All fixed in the latest commit.

Copy link
Collaborator

@ByteYue ByteYue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review of PR #400 — Windows Plugin Path and Symlink Fixes

Thanks for the contribution! This PR correctly identifies and addresses all three core Windows issues reported in #392. Here's my detailed review:

✅ What looks good

  1. fileURLToPath migration — Correctly replaces new URL(import.meta.url).pathname which produces broken paths like /C:/Users/... on Windows. The fileURLToPath import from node:url is the canonical way to handle this.

  2. NTFS junction fallback — Using 'junction' on Windows avoids the admin-privilege requirement for directory symlinks. Good platform detection with the isWindows const.

  3. shell: true for npm and esbuild — On Windows, npm is a .cmd wrapper and execFileSync can't invoke it directly without a shell. Same for the esbuild binary. The conditional spread ...(isWindows && { shell: true }) is clean.

  4. .cmd wrapper priority on Windows — The resolveEsbuildBin() refactor to prefer esbuild.cmd in node_modules/.bin/ on Windows is correct, since the raw esbuild binary is a shebang script that Windows can't execute directly.

  5. whichwhere on Windows — Correct platform-aware global binary lookup.

  6. Test update — The regex /esbuild(\.cmd)?$/ in the test is a reasonable cross-platform assertion.

🔧 Minor suggestions (will fix directly)

  1. The esbuild execFileSync in transpilePluginTs needs consideration — When resolveEsbuildBin() returns an .cmd path on Windows, the execFileSync(esbuildBin, ...) call in transpilePluginTs will use that .cmd file. With shell: true already added in the PR, this should work correctly. Good.

  2. Minor: where on Windows may return multiple lineswhere esbuild can return multiple paths. The current .trim() may leave just the first line on Unix (which) but on Windows it could return multiple lines. Consider using .split('\n')[0].trim() for safety.

Overall this is a solid, well-structured PR that correctly addresses the Windows compatibility issues. I'll checkout and apply the minor where fix mentioned above, then push.

'where esbuild' on Windows can return multiple matching paths, one per
line. Take only the first match to get a valid single path for
resolveEsbuildBin().
@ByteYue ByteYue merged commit d51f361 into jackwener:main Mar 25, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Plugin install on windows

2 participants