Fix linkWorkspaceSource vite plugin on Windows - #4325
Conversation
📝 WalkthroughWalkthroughChangesThe build-plugins package now exports dedicated Vite plugins for workspace source linking and PrismJS core injection. Vitest tooling and tests cover both plugins, while documentation adds usage and cross-platform path guidance. Vite build plugins
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related issues
Possibly related PRs
Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant ViteDevServer
participant linkWorkspaceSource
participant AppPackageJson
participant WorkspacePackage
ViteDevServer->>linkWorkspaceSource: Resolve workspace import during vite serve
linkWorkspaceSource->>AppPackageJson: Read workspace dependencies
linkWorkspaceSource->>WorkspacePackage: Inspect exports and source files
WorkspacePackage-->>linkWorkspaceSource: Return dist export targets
linkWorkspaceSource-->>ViteDevServer: Resolve corresponding src module
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
frontend/packages/build-plugins/package.jsonESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox. frontend/packages/build-plugins/src/vite/__tests__/link-workspace-source.test.tsESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox. frontend/packages/build-plugins/src/vite/__tests__/prismjs-inject-core.test.tsESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
b781513 to
910de1e
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@frontend/packages/build-plugins/src/vite/link-workspace-source.ts`:
- Around line 55-154: Add unit tests for
frontend/packages/build-plugins/src/vite/link-workspace-source.ts:55-154
covering buildWorkspaceLinks export dist-to-src mapping,
linkWorkspaceSource.resolveId specifier redirection, and alias mis-substitution
correction; also add tests for
frontend/packages/build-plugins/src/vite/prismjs-inject-core.ts:23-34 covering
transform regex matches, exclusion of prism-core.js, and injected import output,
targeting at least 80% coverage.
- Around line 117-128: Guard the packageJson read in the linked-package
processing flow with the same error handling used for realpathSync, so failures
from readJson(join(packageDir, 'package.json')) are caught and that package is
skipped. Keep processing other workspace packages and preserve the existing
export-linking logic for successfully read manifests.
- Around line 62-93: Update resolveId’s workspace path comparisons to normalize
Windows drive-letter casing before the appSrcRoot, packageSrcRoots, and importer
prefix checks. Use the casing-normalized paths for startsWith and for
calculating the source suffix passed to join, while retaining the original
normalized paths where needed for resolving the existing file.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 8a35b048-6a4c-4cfc-98c4-60adff0f1e03
📒 Files selected for processing (4)
frontend/packages/build-plugins/README.mdfrontend/packages/build-plugins/src/vite/index.tsfrontend/packages/build-plugins/src/vite/link-workspace-source.tsfrontend/packages/build-plugins/src/vite/prismjs-inject-core.ts
910de1e to
2e9f049
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@frontend/packages/build-plugins/src/vite/__tests__/link-workspace-source.test.ts`:
- Around line 109-110: Normalize all expected path values in the
linkWorkspaceSource() tests before comparing them with POSIX-normalized Vite
IDs. In
frontend/packages/build-plugins/src/vite/__tests__/link-workspace-source.test.ts,
update lines 109-110, 125, 185-187, and 213 to wrap each specified join(...)
expected path with normalizePath(...).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 65383053-485b-467d-a5ee-1914d1340ed1
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (11)
frontend/AGENTS.mdfrontend/packages/build-plugins/README.mdfrontend/packages/build-plugins/package.jsonfrontend/packages/build-plugins/src/vite/__tests__/link-workspace-source.test.tsfrontend/packages/build-plugins/src/vite/__tests__/prismjs-inject-core.test.tsfrontend/packages/build-plugins/src/vite/index.tsfrontend/packages/build-plugins/src/vite/link-workspace-source.tsfrontend/packages/build-plugins/src/vite/prismjs-inject-core.tsfrontend/packages/build-plugins/tsconfig.jsonfrontend/packages/build-plugins/tsconfig.spec.jsonfrontend/packages/build-plugins/vitest.config.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- frontend/packages/build-plugins/README.md
- frontend/packages/build-plugins/src/vite/index.ts
… into per-file modules `linkWorkspaceSource` compared `resolveId`'s `source`/`importer` paths against `appSrcRoot` using `path.sep`-joined prefixes. On Windows, `path.sep` is `\`, but Vite always resolves ids to POSIX-style paths (`/`), so the `startsWith` checks never matched and the app's `@`-alias re-rooting for linked packages silently failed. Normalize all of `appSrcRoot`, `source`, `importer`, `packageSrcRoots`, and the result of `resolveExistingFile` with Vite's `normalizePath` before comparing, so the plugin works the same on Windows as on POSIX systems. `normalizePath` only converts `\` to `/`; it doesn't normalize Windows drive-letter casing (`C:` vs `c:`), which can still differ between `appRoot` and `packageDir` since they come from different APIs (Vite's resolved config root vs `realpathSync`). Add a case-insensitive comparison on Windows only for the `resolveId` prefix checks, so real workspace source imports aren't skipped due to a casing mismatch. Guard the linked package's `package.json` read in `buildWorkspaceLinks` with the same try/catch used around `realpathSync`, so a malformed or missing manifest in one linked workspace package is skipped instead of throwing synchronously inside `configResolved` and aborting dev-server startup for the whole app. While in this file, also move `prismjsInjectCore` and `linkWorkspaceSource` out of the shared `src/vite/index.ts` into their own files (`prismjs-inject-core.ts` and `link-workspace-source.ts`), following the "one file per plugin" convention already documented in the package README. `index.ts` is now a thin barrel re-exporting both plugins and the `LinkWorkspaceSourceOptions` type. Also document `linkWorkspaceSource` in the README, which previously only covered `prismjsInjectCore`. Add a "Cross-OS Path Handling" section to frontend/AGENTS.md capturing this normalize-before-comparing rule, so future build tooling and Node scripts don't reintroduce the same Windows-only breakage. Add a vitest setup for the package and unit tests for both plugins: export/dist-to-source mapping, specifier redirection, the alias mis-substitution correction, the new casing and error-handling guards, and the prismjs transform hook's regex matching. Assert against `normalizePath`-wrapped expectations, since the plugin always returns POSIX-style ids even where the test scaffolding uses `path.join`.
2e9f049 to
82598d3
Compare
linkWorkspaceSource vite plugin on Windows
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
@coderabbitai help |
ChatThere are 3 ways to chat with CodeRabbit:
CodeRabbit commands
Other keywords and placeholders
Status, support, documentation and community
|
|
@coderabbitai full review |
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@frontend/packages/build-plugins/src/vite/link-workspace-source.ts`:
- Around line 48-50: Update WorkspacePackageJson and the package export mapping
logic in frontend/packages/build-plugins/src/vite/link-workspace-source.ts:48-50
and :137-144 to handle string exports and root condition objects, mapping "." or
root conditions to the package name while normalizing valid "./..." subpaths
without treating targets as export keys. Extend
frontend/packages/build-plugins/src/vite/__tests__/link-workspace-source.test.ts:95-128
with coverage for string root exports, conditional root exports, and normalized
subpath mappings.
In `@frontend/packages/build-plugins/src/vite/prismjs-inject-core.ts`:
- Around line 28-29: Update the comment immediately above the return in the
Prism injection transform to accurately state that map: null is explicitly
returned, removing the claim that it is omitted. Keep the implementation
unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 14ad3076-7cd0-4dff-908e-d7045afb41e7
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (11)
frontend/AGENTS.mdfrontend/packages/build-plugins/README.mdfrontend/packages/build-plugins/package.jsonfrontend/packages/build-plugins/src/vite/__tests__/link-workspace-source.test.tsfrontend/packages/build-plugins/src/vite/__tests__/prismjs-inject-core.test.tsfrontend/packages/build-plugins/src/vite/index.tsfrontend/packages/build-plugins/src/vite/link-workspace-source.tsfrontend/packages/build-plugins/src/vite/prismjs-inject-core.tsfrontend/packages/build-plugins/tsconfig.jsonfrontend/packages/build-plugins/tsconfig.spec.jsonfrontend/packages/build-plugins/vitest.config.ts
Purpose
linkWorkspaceSource(the Vite plugin that redirects@thunderid/*workspace imports to package source duringvite serve) comparedresolveId'ssource/importerpaths againstappSrcRootusingpath.sep-joined prefixes. On Windows,path.sepis\, but Vite always resolves ids to POSIX-style paths (/), so thestartsWithchecks never matched and the app's@-alias re-rooting for linked packages silently failed on Windows.While fixing this, also split the two Vite plugins (
prismjsInjectCoreandlinkWorkspaceSource) out of the sharedsrc/vite/index.tsinto their own files, following the "one file per plugin" convention already documented in the@thunderid/build-pluginsREADME.Approach
appSrcRoot,source,importer,packageSrcRoots, and the result ofresolveExistingFilewith Vite'snormalizePathbefore comparing, so path prefix checks work the same on Windows as on POSIX systems.normalizePathdoesn't normalize Windows drive-letter casing (C:vsc:), which can still differ betweenappRootandpackageDirsince they come from different APIs. Add a case-insensitive comparison for theresolveIdprefix checks on Windows only, so real workspace source imports aren't skipped due to a casing mismatch.package.jsonread inbuildWorkspaceLinkswith the same try/catch used aroundrealpathSync, so a malformed or missing manifest in one linked package is skipped instead of throwing synchronously insideconfigResolvedand aborting dev-server startup for the whole app.prismjsInjectCoreintosrc/vite/prismjs-inject-core.tsandlinkWorkspaceSource(plus its private helpers) intosrc/vite/link-workspace-source.ts.src/vite/index.tsis now a thin barrel re-exporting both plugins and theLinkWorkspaceSourceOptionstype.linkWorkspaceSourcein the package README, which previously only coveredprismjsInjectCore.@thunderid/build-plugins/viteAPI; both consumers (apps/console,apps/gate) are unaffected.frontend/AGENTS.mdcapturing this normalize-before-comparing rule, so future build tooling and Node scripts don't reintroduce the same Windows-only breakage.transformhook's regex matching.Related Issues
Related PRs
Checklist
breaking changelabel added.Security checks
Summary by CodeRabbit
@thunderid/*workspace imports to the linked packages’ TypeScriptsrcduringvite serve.