Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 28 additions & 27 deletions napi/angular-compiler/test/linker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
})
22 changes: 18 additions & 4 deletions napi/angular-compiler/vite-plugin/angular-linker-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
Loading