Skip to content

fix(vite-plugin-angular): JIT style resolveId uses ?? (double question mark) instead of ? — SCSS not preprocessed #2094

@AlonMiz

Description

@AlonMiz

Bug Description

The resolveId hook in angular-vite-plugin.ts (line 507) uses ?? (double question mark) for the style/template URL suffix:

return `${normalizePath(
  resolve(dirname(importer as string), path),
)}??${id.includes(':style') ? 'inline' : 'raw'}`;

This produces URLs like path??inline instead of path?inline.

Why This Is Wrong

  • ?inline → URL search params: { inline: '' } ✅ (Vite recognizes this as an inline CSS import)
  • ??inline → URL search params: { '?inline': '' } ❌ (Vite does NOT recognize this)
new URL("file:///path/to/file?inline").searchParams  // { inline: "" } ✅
new URL("file:///path/to/file??inline").searchParams  // { "?inline": "" } ❌

Impact

With ??inline, Vite's CSS pipeline does not process the file, so SCSS/LESS files are loaded as raw text without preprocessing. This causes production builds (e.g., Storybook) to contain raw SCSS (e.g., &.class-name nesting) instead of compiled CSS.

Reproduction

  1. Create an Angular component with an external .scss styleUrl
  2. Build with @analogjs/vite-plugin-angular in JIT mode (jit: true)
  3. Inspect the production bundle — SCSS is not compiled to CSS

Expected Behavior

Style files should be resolved with ?inline (single ?) so Vite runs them through the CSS preprocessor pipeline (SCSS → CSS).

Fix

Change ?? to ? in the resolveId hook:

- )}??${id.includes(':style') ? 'inline' : 'raw'}`;
+ )}?${id.includes(':style') ? 'inline' : 'raw'}`;

This is a regression from commit bcb6da9 (PR #2024), which correctly added the style/template differentiation but used ?? instead of ?.

Workaround

Add an enforce: 'pre' Vite plugin that intercepts angular:jit:style:file; IDs and resolves them with ?inline:

{
  name: 'angular-jit-scss-inline-resolve',
  enforce: 'pre',
  resolveId(id, importer) {
    if (id.startsWith('angular:jit:style:file;') && importer) {
      const filePath = id.split(';')[1];
      return normalizePath(resolve(dirname(importer), filePath)) + '?inline';
    }
  }
}

Versions

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions