Skip to content

fix(vite-plugin-angular): bypass server.fs restrictions on ?raw template imports#2259

Merged
brandonroberts merged 1 commit into
betafrom
fix/vite-7.3.2-raw-denied-id
Apr 7, 2026
Merged

fix(vite-plugin-angular): bypass server.fs restrictions on ?raw template imports#2259
brandonroberts merged 1 commit into
betafrom
fix/vite-7.3.2-raw-denied-id

Conversation

@brandonroberts

@brandonroberts brandonroberts commented Apr 7, 2026

Copy link
Copy Markdown
Member

PR Checklist

Vite 7.3.2 includes security fixes (GHSA-v2wj-q39q-566r, GHSA-4w7w-66w2-5vf9) that tighten server.fs enforcement for ?raw query parameters. The plugin resolves Angular templateUrl references as ?raw imports internally, which are now blocked with "Denied ID" errors — breaking Vitest tests and dev server for components with external templates.

Closes #2256

Affected scope

  • Primary scope: vite-plugin-angular
  • Secondary scopes: none

Recommended merge strategy for maintainer [optional]

  • Squash merge
  • Rebase merge
  • Other

What is the new behavior?

  • The resolveId hook remaps angular:jit:template imports from ?raw to a custom ?analog-raw query parameter
  • A new resolveId handler intercepts any .html?raw import and remaps it to ?analog-raw, preventing the ID from reaching Vite's stricter ?raw security check
  • The load hook handles ?analog-raw IDs by reading the file directly with fsPromises.readFile and returning the content as a default export
  • All three code paths that generate ?raw template imports (JIT resolveId, transform hook markers, angular-compiler JIT transform) are covered without modifying any of them

This avoids the workaround of adding server.fs.allow which weakens the security fix.

Test plan

  • nx format:check
  • pnpm build
  • pnpm test
  • Manual verification with Vite 7.3.2 and a component using templateUrl

Additional:

  • Existing vite-plugin-angular tests pass (52/52)
  • Existing angular-compiler tests pass (466/466)
  • New tests verify resolveId remaps angular:jit:template and .html?raw imports to ?analog-raw
  • New test verifies .html?raw interception works without JIT mode

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

The ?analog-raw query parameter is an internal implementation detail — no public API changes. The jit-transform.ts and transform hook still emit ?raw in generated code; the new resolveId handler intercepts these before Vite can block them.

@netlify

netlify Bot commented Apr 7, 2026

Copy link
Copy Markdown

Deploy Preview for analog-blog ready!

Name Link
🔨 Latest commit 20d4dcb
🔍 Latest deploy log https://app.netlify.com/projects/analog-blog/deploys/69d5005a8555b0000804c507
😎 Deploy Preview https://deploy-preview-2259--analog-blog.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Apr 7, 2026

Copy link
Copy Markdown

Deploy Preview for analog-app ready!

Name Link
🔨 Latest commit 20d4dcb
🔍 Latest deploy log https://app.netlify.com/projects/analog-app/deploys/69d5005a7b97a40008d812c9
😎 Deploy Preview https://deploy-preview-2259--analog-app.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Apr 7, 2026

Copy link
Copy Markdown

Deploy Preview for analog-docs ready!

Name Link
🔨 Latest commit 20d4dcb
🔍 Latest deploy log https://app.netlify.com/projects/analog-docs/deploys/69d5005a734c040008f4c0ea
😎 Deploy Preview https://deploy-preview-2259--analog-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions github-actions Bot added scope:angular-compiler Changes in @analogjs/angular-compiler scope:vite-plugin-angular Changes in @analogjs/vite-plugin-angular labels Apr 7, 2026
@coderabbitai

coderabbitai Bot commented Apr 7, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The plugin is updated to work around Vite 7.3.2's security restrictions on ?raw query parameters for file access. The implementation replaces the standard ?raw suffix with a custom ?analog-raw suffix that the plugin handles directly. Changes include: (1) updated JIT resolution to emit ?analog-raw instead of ?raw, (2) new interception logic that remaps .html?raw imports to use ?analog-raw with normalized file paths, and (3) a new load hook that reads ?analog-raw files from disk and exports them as string modules. Tests verify the remapping behavior and confirm compatibility with non-JIT configurations.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Changes fully address #2256 by implementing the ?analog-raw remapping strategy to bypass Vite's ?raw security restrictions without weakening server.fs.
Out of Scope Changes check ✅ Passed All changes are directly scoped to resolving the linked issue: resolveId interception, load hook handling, and test coverage for the ?analog-raw remapping.
Description check ✅ Passed The PR description clearly relates to the changeset: it explains the motivation (Vite 7.3.2 security fixes breaking ?raw imports), the solution (remapping to ?analog-raw), and technical implementation details that align with the code changes.
Title check ✅ Passed The title follows Conventional Commit style with supported package scope and clearly describes the core fix: remapping ?raw template imports to bypass Vite 7.3.2's server.fs restrictions.

✏️ 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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@brandonroberts brandonroberts force-pushed the fix/vite-7.3.2-raw-denied-id branch from 60e335c to 314d0de Compare April 7, 2026 13:01
… ?raw template imports

Vite 7.3.2 tightened server.fs enforcement for ?raw query parameters,
blocking Angular JIT template imports with "Denied ID" errors. Replace
?raw with a custom ?analog-raw query parameter and handle template
loading directly in the plugin's load hook, bypassing Vite's stricter
security checks without weakening server.fs protections.

Closes #2256

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@brandonroberts brandonroberts force-pushed the fix/vite-7.3.2-raw-denied-id branch from 314d0de to 20d4dcb Compare April 7, 2026 13:02
@github-actions github-actions Bot removed the scope:angular-compiler Changes in @analogjs/angular-compiler label Apr 7, 2026
@brandonroberts brandonroberts changed the title fix(vite-plugin-angular): bypass Vite 7.3.2 server.fs restrictions on ?raw template imports fix(vite-plugin-angular): bypass server.fs restrictions on ?raw template imports Apr 7, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/vite-plugin-angular/src/lib/angular-vite-plugin.ts (1)

780-787: Consider adding error handling for file read failures.

If resolveId returns a path for a file that doesn't exist (e.g., typo in templateUrl), the readFile call will throw an unhandled ENOENT error with a raw stack trace. A descriptive error message would improve developer experience.

💡 Optional: wrap with descriptive error
       if (id.endsWith('?analog-raw')) {
         const filePath = id.slice(0, -'?analog-raw'.length);
-        const content = await fsPromises.readFile(filePath, 'utf-8');
-        return `export default ${JSON.stringify(content)}`;
+        try {
+          const content = await fsPromises.readFile(filePath, 'utf-8');
+          return `export default ${JSON.stringify(content)}`;
+        } catch (e) {
+          throw new Error(
+            `[`@analogjs/vite-plugin-angular`] Failed to load template: ${filePath}`,
+            { cause: e },
+          );
+        }
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vite-plugin-angular/src/lib/angular-vite-plugin.ts` around lines 780
- 787, The load hook's readFile call can throw unhandled ENOENT errors; wrap the
fsPromises.readFile(filePath, 'utf-8') call inside a try/catch in the async
load(id) function and handle failures by raising a descriptive error that
includes the computed filePath and the original error message (use
this.error(...) if the plugin context is available, otherwise throw a new
Error). Ensure the catch only rethrows after attaching the descriptive context
so consumers see a clear message when a templateUrl/path is missing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/vite-plugin-angular/src/lib/angular-vite-plugin.ts`:
- Around line 780-787: The load hook's readFile call can throw unhandled ENOENT
errors; wrap the fsPromises.readFile(filePath, 'utf-8') call inside a try/catch
in the async load(id) function and handle failures by raising a descriptive
error that includes the computed filePath and the original error message (use
this.error(...) if the plugin context is available, otherwise throw a new
Error). Ensure the catch only rethrows after attaching the descriptive context
so consumers see a clear message when a templateUrl/path is missing.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 842d9864-364d-4a93-878a-d92945677de6

📥 Commits

Reviewing files that changed from the base of the PR and between 5a16403 and 20d4dcb.

📒 Files selected for processing (2)
  • packages/vite-plugin-angular/src/lib/angular-vite-plugin.spec.ts
  • packages/vite-plugin-angular/src/lib/angular-vite-plugin.ts

@brandonroberts brandonroberts merged commit 87512a2 into beta Apr 7, 2026
30 checks passed
@brandonroberts brandonroberts deleted the fix/vite-7.3.2-raw-denied-id branch April 7, 2026 13:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope:vite-plugin-angular Changes in @analogjs/vite-plugin-angular

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Vitest fails with "Denied ID" error on Vite 7.3.2 for Angular template ?raw imports

1 participant