forked from voidzero-dev/oxc-angular-compiler
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathangular-linker-plugin.ts
More file actions
121 lines (107 loc) · 3.41 KB
/
angular-linker-plugin.ts
File metadata and controls
121 lines (107 loc) · 3.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { linkAngularPackage } from '#binding'
import type { Plugin } from 'vite'
/**
* Angular Linker plugin for Vite.
*
* Processes pre-compiled Angular library code from node_modules that contains
* partial compilation declarations (ɵɵngDeclare*). These declarations need to
* be "linked" (converted to full ɵɵdefine* calls) at build time.
*
* Without this plugin, Angular falls back to JIT compilation which requires
* @angular/compiler at runtime.
*
* Uses OXC's native Rust-based linker for fast, zero-dependency linking of all
* declaration types including ɵɵngDeclareComponent (with full template compilation).
*
* This plugin works in two phases:
* 1. During dependency optimization (Rolldown pre-bundling) via a Rolldown load plugin
* 2. During Vite's transform pipeline for non-optimized node_modules files
*/
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(?:\?.*)?$/
/**
* Run the OXC Rust linker on the given code.
*/
async function linkCode(
code: string,
id: string,
): Promise<{ code: string; map: string | null; linked: boolean }> {
const result = await linkAngularPackage(code, id)
return {
code: result.linked ? result.code : code,
map: result.map ?? null,
linked: result.linked,
}
}
export function angularLinkerPlugin(): Plugin {
return {
name: '@oxc-angular/vite-linker',
config(_, { command }) {
return {
optimizeDeps: {
rolldownOptions: {
transform: {
define: {
ngJitMode: 'false',
ngI18nClosureMode: 'false',
...(command === 'serve' ? {} : { ngDevMode: 'false' }),
},
},
plugins: [
{
name: 'angular-linker',
load: {
filter: {
id: /\.[cm]?js$/,
},
async handler(id: string) {
// Skip @angular/compiler and @angular/core
if (SKIP_REGEX.test(id)) {
return
}
const code = await this.fs.readFile(id, {
encoding: 'utf8',
})
// Quick check: skip files without partial declarations
if (!code.includes(LINKER_DECLARATION_PREFIX)) {
return
}
const result = await linkCode(code, id)
if (!result.linked) {
return
}
return result.code
},
},
},
],
},
},
}
},
transform: {
filter: {
id: NODE_MODULES_JS_REGEX,
code: LINKER_DECLARATION_PREFIX,
},
async handler(code, id) {
// Skip packages that don't need linking
if (SKIP_REGEX.test(id)) {
return
}
const result = await linkCode(code, id)
if (!result.linked) {
return
}
return {
code: result.code,
map: result.map,
}
},
},
}
}