diff --git a/napi/angular-compiler/test/linker.test.ts b/napi/angular-compiler/test/linker.test.ts index 11ec34525..4a0356177 100644 --- a/napi/angular-compiler/test/linker.test.ts +++ b/napi/angular-compiler/test/linker.test.ts @@ -139,61 +139,62 @@ describe('Angular linker - chunk file linking', () => { }) }) -describe('NODE_MODULES_JS_REGEX filter matching', () => { - // This is the fixed regex from angular-linker-plugin.ts - const NODE_MODULES_JS_REGEX = /node_modules[\\/].*\.[cm]?js(?:\?.*)?$/ +describe('Linker transform filter matching', () => { + // These mirror the two-stage filter from angular-linker-plugin.ts: + // 1. Broad static filter (NODE_MODULES_JS_REGEX) for Vite's filter mechanism + // 2. Precise handler-level check (JS_EXT_REGEX) inside the transform handler + const NODE_MODULES_JS_REGEX = /node_modules/ + const JS_EXT_REGEX = /\.[cm]?js(?:\?.*)?$/ + + function matches(id: string) { + return NODE_MODULES_JS_REGEX.test(id) && JS_EXT_REGEX.test(id) + } it('should match standard Angular FESM files', () => { - expect(NODE_MODULES_JS_REGEX.test('node_modules/@angular/common/fesm2022/common.mjs')).toBe( - true, - ) + expect(matches('node_modules/@angular/common/fesm2022/common.mjs')).toBe(true) }) it('should match chunk files', () => { - expect( - NODE_MODULES_JS_REGEX.test( - 'node_modules/@angular/common/fesm2022/_platform_location-chunk.mjs', - ), - ).toBe(true) + expect(matches('node_modules/@angular/common/fesm2022/_platform_location-chunk.mjs')).toBe(true) }) it('should match absolute paths', () => { expect( - NODE_MODULES_JS_REGEX.test( + matches( '/Users/dev/project/node_modules/@angular/common/fesm2022/_platform_location-chunk.mjs', ), ).toBe(true) }) it('should match paths with Vite query strings', () => { - expect( - NODE_MODULES_JS_REGEX.test('node_modules/@angular/common/fesm2022/common.mjs?v=abc123'), - ).toBe(true) + expect(matches('node_modules/@angular/common/fesm2022/common.mjs?v=abc123')).toBe(true) }) it('should match chunk files with Vite query strings', () => { expect( - NODE_MODULES_JS_REGEX.test( - 'node_modules/@angular/common/fesm2022/_platform_location-chunk.mjs?v=df7b0864', - ), + matches('node_modules/@angular/common/fesm2022/_platform_location-chunk.mjs?v=df7b0864'), ).toBe(true) }) it('should match Windows-style backslash paths', () => { - expect(NODE_MODULES_JS_REGEX.test('node_modules\\@angular\\common\\fesm2022\\common.mjs')).toBe( - true, - ) + expect(matches('node_modules\\@angular\\common\\fesm2022\\common.mjs')).toBe(true) }) it('should match .js and .cjs files', () => { - expect(NODE_MODULES_JS_REGEX.test('node_modules/@ngrx/store/fesm2022/ngrx-store.js')).toBe(true) - expect(NODE_MODULES_JS_REGEX.test('node_modules/some-lib/index.cjs')).toBe(true) + expect(matches('node_modules/@ngrx/store/fesm2022/ngrx-store.js')).toBe(true) + expect(matches('node_modules/some-lib/index.cjs')).toBe(true) + }) + + it('should match PrimeNG files (excluded from optimizeDeps)', () => { + expect(matches('node_modules/primeng/fesm2022/primeng-table.mjs')).toBe(true) + expect(matches('node_modules/primeng/fesm2022/primeng-table.mjs?v=abc123')).toBe(true) }) it('should not match non-JS files', () => { - expect(NODE_MODULES_JS_REGEX.test('node_modules/@angular/common/fesm2022/common.d.ts')).toBe( - false, - ) - expect(NODE_MODULES_JS_REGEX.test('src/app/app.component.ts')).toBe(false) + expect(matches('node_modules/@angular/common/fesm2022/common.d.ts')).toBe(false) + }) + + it('should not match application source files', () => { + expect(matches('src/app/app.component.ts')).toBe(false) }) }) diff --git a/napi/angular-compiler/vite-plugin/angular-linker-plugin.ts b/napi/angular-compiler/vite-plugin/angular-linker-plugin.ts index 551b44ee6..954b727bb 100644 --- a/napi/angular-compiler/vite-plugin/angular-linker-plugin.ts +++ b/napi/angular-compiler/vite-plugin/angular-linker-plugin.ts @@ -24,9 +24,14 @@ const LINKER_DECLARATION_PREFIX = '\u0275\u0275ngDeclare' // Skip these packages - they don't need linking const SKIP_REGEX = /[\\/]@angular[\\/](?:compiler|core)[\\/]/ -// Match JS files in node_modules (Angular FESM bundles) -// Allows optional query strings (?v=...) that Vite appends to module IDs -const NODE_MODULES_JS_REGEX = /node_modules[\\/].*\.[cm]?js(?:\?.*)?$/ +// Broad filter for the transform hook — deliberately simple so that every +// Vite/Rolldown version can evaluate it. Precise extension + query-string +// checks are done inside the handler. +const NODE_MODULES_JS_REGEX = /node_modules/ + +// Precise check run inside the handler: matches .js / .mjs / .cjs with an +// optional Vite query string (?v=…) and works on both Unix and Windows paths. +const JS_EXT_REGEX = /\.[cm]?js(?:\?.*)?$/ /** * Run the OXC Rust linker on the given code. @@ -97,9 +102,18 @@ export function angularLinkerPlugin(): Plugin { transform: { filter: { id: NODE_MODULES_JS_REGEX, - code: LINKER_DECLARATION_PREFIX, }, async handler(code, id) { + // Precise extension check (covers .js, .mjs, .cjs with optional ?v=… query) + if (!JS_EXT_REGEX.test(id)) { + return + } + + // Quick check: skip files without partial declarations + if (!code.includes(LINKER_DECLARATION_PREFIX)) { + return + } + // Skip packages that don't need linking if (SKIP_REGEX.test(id)) { return