chore(plugins): Vite 8 compatibility#788
Conversation
Summary by CodeRabbit
WalkthroughVite 8 compatibility refactor: The Vite plugin transitions from HTML post-processing to virtual module resolution for bundle injection, fixing Rolldown incompatibility. Code generation spacing logic refactors to per-token decisions. Test fixtures rename and all examples/templates migrate output directory from hidden ChangesBundle Injection via Virtual Module Resolution
Code Generation Token Spacing
Test Fixtures and Parser Tests
Configuration and Template Updates
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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 |
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 `@packages/plugin-vite/src/index.ts`:
- Around line 22-25: createJitarBundle is building import specifiers from the
output dir (paths.vite.output) and using path.join which yields backslashes on
Windows, and transform uses a process-global jitarImported flag that persists
across rebuilds; fix by (1) change callers (load) and createJitarBundle to
construct middleware ids from the source dir (paths.project.source) or otherwise
from locations that exist at dev-time instead of paths.vite.output, (2)
normalize generated import specifiers to POSIX style (use path.posix.join or
replace backslashes with '/') after assureExtension to ensure ESM-safe forward
slashes, and (3) stop using a process-local jitarImported guard in transform —
instead reset the guard per build (e.g. reinitialize in buildStart) or track
injection per-build using the plugin context (or a Map keyed by a build id) so
import 'jitar-bundle' is injected deterministically on the first .tsx under
paths.project.source each build; reference createJitarBundle, assureExtension,
load, transform, jitarImported, paths.vite.output and paths.project.source when
making the changes.
- Around line 181-190: The current transform(code, id) injects JITAR_BUNDLE_ID
into the first .tsx under paths.project.source using jitarImported, which misses
real Vite client entry modules (.ts/.js/.jsx) and can inject into a lazy
component; modify the plugin to implement configResolved(config) to read
Vite/Rollup input/entry points (e.g., config.build.rollupOptions.input /
config.input) and resolve those entry module ids (store them in a Set like
clientEntryIds), then change transform to check if id is in clientEntryIds (or
matches resolved paths under paths.project.source) and inject `import
'${JITAR_BUNDLE_ID}';\n` only for those entries (use jitarImported as a guard or
remove it if you inject into all resolved entries), ensuring you handle
.ts/.js/.jsx/.tsx resolutions consistently.
- Around line 89-90: The plugin currently uses a sticky boolean jitarImported so
transform() only injects import '${JITAR_BUNDLE_ID}' once ever, causing
nondeterministic output after HMR/rebuilds; fix by resetting that state at the
start of each compilation (in buildStart()) or, better, replace the boolean with
a tracked injectedModuleId and re-inject whenever transform() is called for that
specific module; update buildStart() to clear jitarImported/injectedModuleId and
adjust transform() logic to check/inject based on the tracked module id (use
JITAR_BUNDLE_ID, transform(), and buildStart() as reference points).
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 2b8ae293-bfd5-4801-996a-ad1a30cf83c5
📒 Files selected for processing (1)
packages/plugin-vite/src/index.ts
| transform(code, id) | ||
| { | ||
| // Add the jitar client bundle to the HTML if it wasn't imported | ||
| // by any of the application files. | ||
| // Import the Jitar bundle in the first application component | ||
|
|
||
| if (jitarBundleImported === true) | ||
| { | ||
| return html; | ||
| } | ||
|
|
||
| if (jitarBundleFilename === undefined) | ||
| if (id.startsWith(paths.project.source!) && id.endsWith('.tsx') && jitarImported === false) | ||
| { | ||
| // Dev mode: insert the pre generated jitar bundle | ||
| jitarImported = true; | ||
|
|
||
| if (paths.vite.assetOutput === undefined) | ||
| { | ||
| console.warn('Output path not found!'); | ||
|
|
||
| return html; | ||
| } | ||
|
|
||
| const filenames = fs.readdirSync(paths.vite.assetOutput); | ||
|
|
||
| const jitarFilename = filenames.find(fileName => fileName.startsWith(JITAR_BUNDLE_ID) && fileName.endsWith('.js')); | ||
|
|
||
| if (jitarFilename === undefined) | ||
| { | ||
| console.warn('Jitar bundle not found! Did you build the application first?'); | ||
|
|
||
| return html; | ||
| } | ||
|
|
||
| const jitarBundle = fs.readFileSync(path.join(paths.vite.assetOutput, jitarFilename), 'utf-8'); | ||
|
|
||
| return html.replace('<script', `<script type="module">${jitarBundle}</script>\n <script`); | ||
| return `import '${JITAR_BUNDLE_ID}';\n${code}`; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C2 "transform\\(code, id\\)|id\\.endsWith\\('\\.tsx'\\)|rollupOptions|input" packages/plugin-vite/src/index.tsRepository: MaskingTechnology/jitar
Length of output: 2047
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# show the whole plugin section around transform and its surrounding variables
sed -n '1,260p' packages/plugin-vite/src/index.ts | cat -nRepository: MaskingTechnology/jitar
Length of output: 7670
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# search for client entry/module id resolution patterns in this file and plugin-vite package
rg -n "configResolved\\(|resolvedConfig\\.|rollupOptions|\\binput\\b|transformIndexHtml|client entry|entry\\b|main\\.(t|j)sx|main\\.(t|j)s|index\\.html" packages/plugin-vite/src/index.tsRepository: MaskingTechnology/jitar
Length of output: 1007
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "JITAR_BUNDLE_ID|jitarImported|transform\\(code, id\\)|endsWith\\('\\.tsx'\\)" packages/plugin-vite/src/index.tsRepository: MaskingTechnology/jitar
Length of output: 500
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# check other files in plugin-vite for entry selection logic
rg -n "transform\\(code, id\\)|transformIndexHtml|rollupOptions|\\binput\\b|entry" packages/plugin-vite/src -SRepository: MaskingTechnology/jitar
Length of output: 1236
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# if typescript config exists, check plugin config usage maybe sets sourceRoot etc
rg -n "projectRoot|sourceRoot|main\\." -S packages/plugin-vite/srcRepository: MaskingTechnology/jitar
Length of output: 473
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# look for any other injection mechanism in the repo
rg -n "JITAR_BUNDLE_ID" -S packages | head -n 50Repository: MaskingTechnology/jitar
Length of output: 420
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# show just tail around where jitarImported declared
rg -n "let\\s+jitarImported|jitarImported\\s*=" -n packages/plugin-vite/src/index.tsRepository: MaskingTechnology/jitar
Length of output: 251
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# show the whole plugin section around transform and its surrounding variables
sed -n '1,260p' packages/plugin-vite/src/index.ts | cat -nRepository: MaskingTechnology/jitar
Length of output: 7670
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# search for client entry/module id resolution patterns in this file
rg -n "configResolved\\(|resolvedConfig\\.|rollupOptions|\\binput\\b|transformIndexHtml|entry\\b" packages/plugin-vite/src/index.tsRepository: MaskingTechnology/jitar
Length of output: 1007
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# locate the exact injection logic details
rg -n "JITAR_BUNDLE_ID|jitarImported|transform\\(code, id\\)|endsWith\\('\\.tsx'\\)" packages/plugin-vite/src/index.tsRepository: MaskingTechnology/jitar
Length of output: 500
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# check other files in plugin-vite for entry selection logic / other injection hooks
rg -n "transform\\(code, id\\)|transformIndexHtml|rollupOptions|\\binput\\b|entry\\b" packages/plugin-vite/src -SRepository: MaskingTechnology/jitar
Length of output: 1236
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# look for any other usage of the bundle injection id across packages
rg -n "JITAR_BUNDLE_ID" -S packages | head -n 50Repository: MaskingTechnology/jitar
Length of output: 420
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# confirm how jitarImported is declared/initialized
rg -n "jitarImported" packages/plugin-vite/src/index.tsRepository: MaskingTechnology/jitar
Length of output: 251
Inject Jitar bundle into the real Vite client entry (not the first transformed .tsx).
transform(code, id)injects only forid.startsWith(paths.project.source!) && id.endsWith('.tsx')and only for the first such transformed module (jitarImportedboolean), so.ts/.js/.jsxentrypoints never get the bundle.- For TSX apps, “first transformed
.tsxunder sourceRoot” is not necessarily the eagerly loaded client entry; injection order can differ, so it can land too late or in a lazy component.
Resolve the actual client entry module(s) from Vite/Rollup config in configResolved and inject into those ids instead of relying on the first .tsx seen in transform.
🤖 Prompt for 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.
In `@packages/plugin-vite/src/index.ts` around lines 181 - 190, The current
transform(code, id) injects JITAR_BUNDLE_ID into the first .tsx under
paths.project.source using jitarImported, which misses real Vite client entry
modules (.ts/.js/.jsx) and can inject into a lazy component; modify the plugin
to implement configResolved(config) to read Vite/Rollup input/entry points
(e.g., config.build.rollupOptions.input / config.input) and resolve those entry
module ids (store them in a Set like clientEntryIds), then change transform to
check if id is in clientEntryIds (or matches resolved paths under
paths.project.source) and inject `import '${JITAR_BUNDLE_ID}';\n` only for those
entries (use jitarImported as a guard or remove it if you inject into all
resolved entries), ensuring you handle .ts/.js/.jsx/.tsx resolutions
consistently.
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 `@packages/plugin-vite/src/index.ts`:
- Around line 185-187: The check for isFirstAppComponent uses
id.startsWith(paths.project.source!) which can match sibling folders; update the
guard to verify id is actually inside the source root by comparing resolved
paths (e.g., compute path.relative(paths.project.source!, id) or join the source
with a path.sep and ensure the relative path does not start with '..' or is not
absolute), so change the condition around jitarImported/isFirstAppComponent to
use that path-boundary check (referencing isFirstAppComponent, jitarImported,
id, and paths.project.source) before treating a file as the first app component.
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 894b5c85-eea0-4c3a-af1c-1211e10bea47
📒 Files selected for processing (1)
packages/plugin-vite/src/index.ts
| const isFirstAppComponent = jitarImported === false | ||
| && id.startsWith(paths.project.source!) | ||
| && (id.endsWith('.ts') || id.endsWith('.tsx')); |
There was a problem hiding this comment.
Guard the source-root check with a real path boundary.
Line 186 uses startsWith(paths.project.source!), which also matches siblings like /repo/src-legacy/... when the actual source root is /repo/src. Because this branch is gated by the one-shot jitarImported flag, a false positive can consume the injection and the real app entry never imports jitar-bundle.
Suggested fix
+ const cleanId = id.split('?', 1)[0];
+ const sourceRoot = paths.project.source!;
+ const isUnderSourceRoot = cleanId === sourceRoot
+ || cleanId.startsWith(`${sourceRoot}/`);
const isFirstAppComponent = jitarImported === false
- && id.startsWith(paths.project.source!)
- && (id.endsWith('.ts') || id.endsWith('.tsx'));
+ && isUnderSourceRoot
+ && (cleanId.endsWith('.ts') || cleanId.endsWith('.tsx'));📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const isFirstAppComponent = jitarImported === false | |
| && id.startsWith(paths.project.source!) | |
| && (id.endsWith('.ts') || id.endsWith('.tsx')); | |
| const cleanId = id.split('?', 1)[0]; | |
| const sourceRoot = paths.project.source!; | |
| const isUnderSourceRoot = cleanId === sourceRoot | |
| || cleanId.startsWith(`${sourceRoot}/`); | |
| const isFirstAppComponent = jitarImported === false | |
| && isUnderSourceRoot | |
| && (cleanId.endsWith('.ts') || cleanId.endsWith('.tsx')); |
🤖 Prompt for 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.
In `@packages/plugin-vite/src/index.ts` around lines 185 - 187, The check for
isFirstAppComponent uses id.startsWith(paths.project.source!) which can match
sibling folders; update the guard to verify id is actually inside the source
root by comparing resolved paths (e.g., compute
path.relative(paths.project.source!, id) or join the source with a path.sep and
ensure the relative path does not start with '..' or is not absolute), so change
the condition around jitarImported/isFirstAppComponent to use that path-boundary
check (referencing isFirstAppComponent, jitarImported, id, and
paths.project.source) before treating a file as the first app component.
keywords like 'of', 'in' etc. didn't get prefixed and postfixed with spaces resulting into broken apps.
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 `@packages/analysis/src/static/Coder.ts`:
- Around line 64-87: The spacing logic in `#isPrefixKeyword` and `#isInfixKeyword`
misses many Keyword enum values so adjacent keywords can be concatenated; update
these two methods in Coder.ts to enumerate all Keyword members that require
separation (e.g., add import, export, default, else, case, extends, do, if, for,
while, break, continue, try, catch, finally, switch, and any others from the
Keyword enum that should be treated as prefix or infix) or replace the ad-hoc
checks with a single central set/lookup (e.g., a Set<Keyword>
keywordNeedsSpacing) and have `#isPrefixKeyword/`#isInfixKeyword consult that set
so every keyword that needs surrounding whitespace is covered. Ensure
`#isInfixKeyword` still handles tokens like OF/IN/AS/FROM and that no Keyword
values are left out.
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: b4e070c7-073a-4b7f-abf5-d203d548e2cc
📒 Files selected for processing (10)
packages/analysis/src/static/Coder.tspackages/analysis/test/static/Parser.spec.tspackages/analysis/test/static/fixtures/index.tspackages/analysis/test/static/fixtures/modules.fixture.tspackages/analysis/test/static/fixtures/variables.fixture.tspackages/init/templates/backend/.gitignorepackages/init/templates/react/.gitignorepackages/init/templates/react/package.jsonpackages/init/templates/vue/.gitignorepackages/init/templates/vue/package.json
|
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 `@packages/plugin-vite/src/index.ts`:
- Around line 152-153: The injection guard variable jitarImported must be
checked and set inside the transform hook instead of inside load to avoid a race
where multiple concurrent transforms trigger injection; update the logic so
transform inspects jitarImported === false, performs the single
import('jitar-bundle') injection and then sets jitarImported = true, and remove
or stop setting jitarImported in load (also apply the same move for the other
injection block currently around the 188-199 code that uses jitarImported) so
that injection is deterministic and only happens once.
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 10dba756-28d5-463f-928d-89967ed99ad0
📒 Files selected for processing (28)
.npmrcdocumentation/docs/integrate/vite-plugin.mdexamples/.gitignoreexamples/access-protection/jitar.jsonexamples/access-protection/package.jsonexamples/data-transportation/jitar.jsonexamples/data-transportation/package.jsonexamples/error-handling/jitar.jsonexamples/error-handling/package.jsonexamples/health-checks/jitar.jsonexamples/health-checks/package.jsonexamples/hello-world/jitar.jsonexamples/hello-world/package.jsonexamples/load-balancing/jitar.jsonexamples/load-balancing/package.jsonexamples/middleware/jitar.jsonexamples/middleware/package.jsonexamples/multi-version/jitar.jsonexamples/multi-version/package.jsonexamples/resources/jitar.jsonexamples/resources/package.jsonexamples/segmentation/jitar.jsonexamples/segmentation/package.jsonpackages/analysis/src/static/Coder.tspackages/analysis/src/static/definitions/TokenType.tspackages/analysis/test/static/Parser.spec.tspackages/plugin-vite/package.jsonpackages/plugin-vite/src/index.ts
| jitarImported = true; | ||
|
|
There was a problem hiding this comment.
Move injection guard to transform to prevent race condition.
transform checks jitarImported === false but load sets it to true. Since transforms can run concurrently before any triggers the bundle load, multiple modules may inject import 'jitar-bundle'. While ES module deduplication prevents duplicate execution, setting the flag in transform ensures deterministic single-injection.
♻️ Proposed fix
load(id)
{
if (id === JITAR_BUNDLE_RESOLVE_ID)
{
- jitarImported = true;
-
return createJitarBundle(middlewares, paths.vite.output!);
} transform(code, id)
{
// Import the Jitar bundle from the first application component
const isFirstAppComponent = jitarImported === false
&& id.startsWith(paths.project.source!)
&& (id.endsWith('.js') || id.endsWith('.ts') || id.endsWith('.jsx') || id.endsWith('.tsx'));
if (isFirstAppComponent)
{
+ jitarImported = true;
return `import '${JITAR_BUNDLE_ID}';\n${code}`;
}
return code;
}Also applies to: 188-199
🤖 Prompt for 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.
In `@packages/plugin-vite/src/index.ts` around lines 152 - 153, The injection
guard variable jitarImported must be checked and set inside the transform hook
instead of inside load to avoid a race where multiple concurrent transforms
trigger injection; update the logic so transform inspects jitarImported ===
false, performs the single import('jitar-bundle') injection and then sets
jitarImported = true, and remove or stop setting jitarImported in load (also
apply the same move for the other injection block currently around the 188-199
code that uses jitarImported) so that injection is deterministic and only
happens once.



Fixes #787 #786
Changes proposed in this pull request:
@MaskingTechnology/jitar