@analogjs/vite-plugin-angular 2.5.0-beta.9 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/package.json +23 -5
- package/src/lib/angular-vite-plugin.d.ts +12 -1
- package/src/lib/angular-vite-plugin.js +102 -300
- package/src/lib/angular-vite-plugin.js.map +1 -1
- package/src/lib/angular-vitest-plugin.js +2 -2
- package/src/lib/angular-vitest-plugin.js.map +1 -1
- package/src/lib/compiler/angular-version.d.ts +19 -0
- package/src/lib/compiler/angular-version.js +42 -0
- package/src/lib/compiler/angular-version.js.map +1 -0
- package/src/lib/compiler/class-field-lowering.d.ts +23 -0
- package/src/lib/compiler/class-field-lowering.js +213 -0
- package/src/lib/compiler/class-field-lowering.js.map +1 -0
- package/src/lib/compiler/compile.d.ts +44 -0
- package/src/lib/compiler/compile.js +1160 -0
- package/src/lib/compiler/compile.js.map +1 -0
- package/src/lib/compiler/constants.d.ts +18 -0
- package/src/lib/compiler/constants.js +48 -0
- package/src/lib/compiler/constants.js.map +1 -0
- package/src/lib/compiler/debug.d.ts +22 -0
- package/src/lib/compiler/debug.js +35 -0
- package/src/lib/compiler/debug.js.map +1 -0
- package/src/lib/compiler/defer.d.ts +47 -0
- package/src/lib/compiler/defer.js +203 -0
- package/src/lib/compiler/defer.js.map +1 -0
- package/src/lib/compiler/dts-reader.d.ts +35 -0
- package/src/lib/compiler/dts-reader.js +526 -0
- package/src/lib/compiler/dts-reader.js.map +1 -0
- package/src/lib/compiler/hmr.d.ts +16 -0
- package/src/lib/compiler/hmr.js +80 -0
- package/src/lib/compiler/hmr.js.map +1 -0
- package/src/lib/compiler/index.d.ts +7 -0
- package/src/lib/compiler/index.js +8 -0
- package/src/lib/compiler/index.js.map +1 -0
- package/src/lib/compiler/jit-metadata.d.ts +14 -0
- package/src/lib/compiler/jit-metadata.js +224 -0
- package/src/lib/compiler/jit-metadata.js.map +1 -0
- package/src/lib/compiler/jit-transform.d.ts +24 -0
- package/src/lib/compiler/jit-transform.js +269 -0
- package/src/lib/compiler/jit-transform.js.map +1 -0
- package/src/lib/compiler/js-emitter.d.ts +10 -0
- package/src/lib/compiler/js-emitter.js +502 -0
- package/src/lib/compiler/js-emitter.js.map +1 -0
- package/src/lib/compiler/metadata.d.ts +57 -0
- package/src/lib/compiler/metadata.js +894 -0
- package/src/lib/compiler/metadata.js.map +1 -0
- package/src/lib/compiler/registry.d.ts +49 -0
- package/src/lib/compiler/registry.js +273 -0
- package/src/lib/compiler/registry.js.map +1 -0
- package/src/lib/compiler/resource-inliner.d.ts +21 -0
- package/src/lib/compiler/resource-inliner.js +200 -0
- package/src/lib/compiler/resource-inliner.js.map +1 -0
- package/src/lib/compiler/style-ast.d.ts +8 -0
- package/src/lib/compiler/style-ast.js +110 -0
- package/src/lib/compiler/style-ast.js.map +1 -0
- package/src/lib/compiler/styles.d.ts +13 -0
- package/src/lib/compiler/styles.js +60 -0
- package/src/lib/compiler/styles.js.map +1 -0
- package/src/lib/compiler/test-helpers.d.ts +7 -0
- package/src/lib/compiler/test-helpers.js +28 -0
- package/src/lib/compiler/test-helpers.js.map +1 -0
- package/src/lib/compiler/type-elision.d.ts +26 -0
- package/src/lib/compiler/type-elision.js +313 -0
- package/src/lib/compiler/type-elision.js.map +1 -0
- package/src/lib/compiler/utils.d.ts +10 -0
- package/src/lib/compiler/utils.js +95 -0
- package/src/lib/compiler/utils.js.map +1 -0
- package/src/lib/fast-compile-plugin.d.ts +28 -0
- package/src/lib/fast-compile-plugin.js +404 -0
- package/src/lib/fast-compile-plugin.js.map +1 -0
- package/src/lib/utils/plugin-config.d.ts +45 -0
- package/src/lib/utils/plugin-config.js +89 -0
- package/src/lib/utils/plugin-config.js.map +1 -0
- package/src/lib/utils/safe-module-paths.d.ts +16 -0
- package/src/lib/utils/safe-module-paths.js +26 -0
- package/src/lib/utils/safe-module-paths.js.map +1 -0
- package/src/lib/utils/virtual-ids.d.ts +4 -0
- package/src/lib/utils/virtual-ids.js +30 -0
- package/src/lib/utils/virtual-ids.js.map +1 -0
- package/src/lib/utils/virtual-resources.d.ts +19 -0
- package/src/lib/utils/virtual-resources.js +47 -0
- package/src/lib/utils/virtual-resources.js.map +1 -0
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @analogjs/vite-plugin-angular
|
|
2
2
|
|
|
3
|
+
[](https://registry.vite.dev/plugin/@analogjs/vite-plugin-angular)
|
|
4
|
+
|
|
3
5
|
A Vite plugin for building Angular applications
|
|
4
6
|
|
|
5
7
|
## Install
|
|
@@ -48,6 +50,28 @@ export default defineConfig({
|
|
|
48
50
|
|
|
49
51
|
> The `angular` plugin should be listed **first** in the plugins array.
|
|
50
52
|
|
|
53
|
+
## Fast Compile Mode
|
|
54
|
+
|
|
55
|
+
`fastCompile` opts the plugin into a single-pass compilation path that emits Ivy instructions directly and skips Angular's template type-checking. It's intended for content-focused apps and faster dev iteration where build throughput matters more than inline type-safety feedback.
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
export default defineConfig({
|
|
59
|
+
plugins: [angular({ fastCompile: true })],
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
When `fastCompile` is enabled, template and input type errors will not surface during compilation — run `ngc -p tsconfig.app.json --noEmit` as a separate step in your build script to keep full type safety:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"scripts": {
|
|
68
|
+
"build": "ngc -p tsconfig.app.json --noEmit && vite build"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The fast compile path currently passes ~91% of Angular's conformance suite. Behavior and output may change between minor releases.
|
|
74
|
+
|
|
51
75
|
## Setting up the TypeScript config
|
|
52
76
|
|
|
53
77
|
The integration needs a `tsconfig.app.json` at the root of the project for compilation.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@analogjs/vite-plugin-angular",
|
|
3
|
-
"version": "2.5.0
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"description": "Vite Plugin for Angular",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
27
|
"@angular-devkit/build-angular": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0",
|
|
28
|
-
"@angular/build": "^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0"
|
|
28
|
+
"@angular/build": "^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0",
|
|
29
|
+
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
|
29
30
|
},
|
|
30
31
|
"peerDependenciesMeta": {
|
|
31
32
|
"@angular-devkit/build-angular": {
|
|
@@ -33,10 +34,28 @@
|
|
|
33
34
|
},
|
|
34
35
|
"@angular/build": {
|
|
35
36
|
"optional": true
|
|
37
|
+
},
|
|
38
|
+
"vite": {
|
|
39
|
+
"optional": true
|
|
36
40
|
}
|
|
37
41
|
},
|
|
42
|
+
"compatiblePackages": {
|
|
43
|
+
"vite": [
|
|
44
|
+
"^6.0.0",
|
|
45
|
+
"^7.0.0",
|
|
46
|
+
"^8.0.0"
|
|
47
|
+
],
|
|
48
|
+
"rollup": [
|
|
49
|
+
"^4.0.0"
|
|
50
|
+
],
|
|
51
|
+
"rolldown": [
|
|
52
|
+
"^1.0.0"
|
|
53
|
+
]
|
|
54
|
+
},
|
|
38
55
|
"dependencies": {
|
|
39
|
-
"
|
|
56
|
+
"magic-string": "^0.30.21",
|
|
57
|
+
"obug": "^2.1.1",
|
|
58
|
+
"oxc-parser": "^0.121.0",
|
|
40
59
|
"tinyglobby": "^0.2.14",
|
|
41
60
|
"ts-morph": "^21.0.0"
|
|
42
61
|
},
|
|
@@ -49,8 +68,7 @@
|
|
|
49
68
|
"@analogjs/storybook-angular",
|
|
50
69
|
"@analogjs/vite-plugin-angular",
|
|
51
70
|
"@analogjs/vite-plugin-nitro",
|
|
52
|
-
"@analogjs/vitest-angular"
|
|
53
|
-
"@analogjs/angular-compiler"
|
|
71
|
+
"@analogjs/vitest-angular"
|
|
54
72
|
],
|
|
55
73
|
"migrations": "./migrations/migration.json"
|
|
56
74
|
},
|
|
@@ -30,9 +30,20 @@ export interface PluginOptions {
|
|
|
30
30
|
liveReload?: boolean;
|
|
31
31
|
disableTypeChecking?: boolean;
|
|
32
32
|
fileReplacements?: FileReplacement[];
|
|
33
|
+
/**
|
|
34
|
+
* Opt into the fast compile path. Skips Angular's template type-checking
|
|
35
|
+
* and routes compilation through an internal single-pass transform.
|
|
36
|
+
* Defaults to `false`.
|
|
37
|
+
*/
|
|
38
|
+
fastCompile?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Compilation output mode used when `fastCompile` is enabled.
|
|
41
|
+
* - `'full'` (default): Emit final Ivy definitions for application builds.
|
|
42
|
+
* - `'partial'`: Emit partial declarations for library publishing.
|
|
43
|
+
*/
|
|
44
|
+
fastCompileMode?: 'full' | 'partial';
|
|
33
45
|
experimental?: {
|
|
34
46
|
useAngularCompilationAPI?: boolean;
|
|
35
|
-
useAnalogCompiler?: boolean;
|
|
36
47
|
};
|
|
37
48
|
}
|
|
38
49
|
export declare function angular(options?: PluginOptions): Plugin[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { basename, dirname, isAbsolute, join, relative, resolve, } from 'node:path';
|
|
3
3
|
import * as vite from 'vite';
|
|
4
4
|
import * as compilerCli from '@angular/compiler-cli';
|
|
@@ -8,7 +8,6 @@ import { globSync } from 'tinyglobby';
|
|
|
8
8
|
import { defaultClientConditions, normalizePath, preprocessCSS, } from 'vite';
|
|
9
9
|
import { buildOptimizerPlugin } from './angular-build-optimizer-plugin.js';
|
|
10
10
|
import { jitPlugin } from './angular-jit-plugin.js';
|
|
11
|
-
import { createCompilerPlugin, createRolldownCompilerPlugin, } from './compiler-plugin.js';
|
|
12
11
|
import { StyleUrlsResolver, TemplateUrlsResolver, } from './component-resolvers.js';
|
|
13
12
|
import { augmentHostWithCaching, augmentHostWithResources, augmentProgramWithVersioning, mergeTransformers, } from './host.js';
|
|
14
13
|
import { angularVitestPlugins } from './angular-vitest-plugin.js';
|
|
@@ -20,7 +19,11 @@ import { nxFolderPlugin } from './nx-folder-plugin.js';
|
|
|
20
19
|
import { replaceFiles, } from './plugins/file-replacements.plugin.js';
|
|
21
20
|
import { routerPlugin } from './router-plugin.js';
|
|
22
21
|
import { createHash } from 'node:crypto';
|
|
23
|
-
import {
|
|
22
|
+
import { fastCompilePlugin } from './fast-compile-plugin.js';
|
|
23
|
+
import { TS_EXT_REGEX, createTsConfigGetter, getTsConfigPath, createDepOptimizerConfig, } from './utils/plugin-config.js';
|
|
24
|
+
import { VIRTUAL_RAW_PREFIX, toVirtualRawId } from './utils/virtual-ids.js';
|
|
25
|
+
import { loadVirtualRawModule, rewriteHtmlRawImport, } from './utils/virtual-resources.js';
|
|
26
|
+
import { markStylePathSafe } from './utils/safe-module-paths.js';
|
|
24
27
|
export var DiagnosticModes;
|
|
25
28
|
(function (DiagnosticModes) {
|
|
26
29
|
DiagnosticModes[DiagnosticModes["None"] = 0] = "None";
|
|
@@ -29,12 +32,6 @@ export var DiagnosticModes;
|
|
|
29
32
|
DiagnosticModes[DiagnosticModes["Semantic"] = 4] = "Semantic";
|
|
30
33
|
DiagnosticModes[DiagnosticModes["All"] = 7] = "All";
|
|
31
34
|
})(DiagnosticModes || (DiagnosticModes = {}));
|
|
32
|
-
/**
|
|
33
|
-
* TypeScript file extension regex
|
|
34
|
-
* Match .(c or m)ts, .ts extensions with an optional ? for query params
|
|
35
|
-
* Ignore .tsx extensions
|
|
36
|
-
*/
|
|
37
|
-
const TS_EXT_REGEX = /\.[cm]?(ts)[^x]?\??/;
|
|
38
35
|
const classNames = new Map();
|
|
39
36
|
export function angular(options) {
|
|
40
37
|
/**
|
|
@@ -60,10 +57,10 @@ export function angular(options) {
|
|
|
60
57
|
disableTypeChecking: options?.disableTypeChecking ?? true,
|
|
61
58
|
fileReplacements: options?.fileReplacements ?? [],
|
|
62
59
|
useAngularCompilationAPI: options?.experimental?.useAngularCompilationAPI ?? false,
|
|
63
|
-
|
|
60
|
+
fastCompile: options?.fastCompile ?? false,
|
|
61
|
+
fastCompileMode: options?.fastCompileMode ?? 'full',
|
|
64
62
|
};
|
|
65
63
|
let resolvedConfig;
|
|
66
|
-
// Store config context needed for getTsConfigPath resolution
|
|
67
64
|
let tsConfigResolutionContext = null;
|
|
68
65
|
const ts = require('typescript');
|
|
69
66
|
let builder;
|
|
@@ -113,126 +110,6 @@ export function angular(options) {
|
|
|
113
110
|
// Previously the compilation was recreated on every pass, which meant Angular
|
|
114
111
|
// never had prior state and could never produce HMR payloads.
|
|
115
112
|
let angularCompilation;
|
|
116
|
-
// Analog compiler state (used when experimental.useAnalogCompiler is true)
|
|
117
|
-
const analogRegistry = new Map();
|
|
118
|
-
const analogResourceToSource = new Map();
|
|
119
|
-
/** Tracks which npm packages have already had their .d.ts files scanned. */
|
|
120
|
-
const scannedDtsPackages = new Set();
|
|
121
|
-
let analogProjectRoot = '';
|
|
122
|
-
async function initAnalogCompiler() {
|
|
123
|
-
if (jit)
|
|
124
|
-
return; // JIT: no registry scan needed
|
|
125
|
-
// Scan all source files to build the registry
|
|
126
|
-
analogRegistry.clear();
|
|
127
|
-
scannedDtsPackages.clear();
|
|
128
|
-
const resolvedTsConfigPath = resolveTsConfigPath();
|
|
129
|
-
analogProjectRoot = dirname(resolvedTsConfigPath);
|
|
130
|
-
const config = compilerCli.readConfiguration(resolvedTsConfigPath);
|
|
131
|
-
const results = await Promise.all(config.rootNames.map(async (file) => {
|
|
132
|
-
try {
|
|
133
|
-
const code = await fsPromises.readFile(file, 'utf-8');
|
|
134
|
-
return analogScanFile(code, file);
|
|
135
|
-
}
|
|
136
|
-
catch {
|
|
137
|
-
return []; // Skip unreadable files
|
|
138
|
-
}
|
|
139
|
-
}));
|
|
140
|
-
for (const entries of results) {
|
|
141
|
-
for (const entry of entries) {
|
|
142
|
-
analogRegistry.set(entry.className, entry);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Lazily scan .d.ts files for external packages imported by the given source.
|
|
148
|
-
* Each package is scanned at most once and the results are cached in the registry.
|
|
149
|
-
*/
|
|
150
|
-
function ensureDtsRegistryForSource(code, id) {
|
|
151
|
-
for (const pkg of analogCollectImportedPackages(code, id)) {
|
|
152
|
-
if (scannedDtsPackages.has(pkg))
|
|
153
|
-
continue;
|
|
154
|
-
scannedDtsPackages.add(pkg);
|
|
155
|
-
try {
|
|
156
|
-
const dtsEntries = analogScanPackageDts(pkg, analogProjectRoot);
|
|
157
|
-
for (const entry of dtsEntries) {
|
|
158
|
-
if (!analogRegistry.has(entry.className)) {
|
|
159
|
-
analogRegistry.set(entry.className, entry);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
catch {
|
|
164
|
-
// Package may not have .d.ts files or may not be Angular
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
async function handleAnalogCompilerTransform(code, id) {
|
|
169
|
-
if (!/(Component|Directive|Pipe|Injectable|NgModule)\(/.test(code)) {
|
|
170
|
-
return undefined;
|
|
171
|
-
}
|
|
172
|
-
// JIT mode
|
|
173
|
-
if (jit) {
|
|
174
|
-
const result = analogJitTransform(code, id);
|
|
175
|
-
return { code: result.code, map: result.map };
|
|
176
|
-
}
|
|
177
|
-
// Inline external templateUrl/styleUrl(s) into the source before compilation
|
|
178
|
-
// using OXC parser for precise AST-based rewriting.
|
|
179
|
-
code = inlineResourceUrls(code, id);
|
|
180
|
-
// Pre-resolve inline styles that need preprocessing (SCSS/Sass/Less)
|
|
181
|
-
let resolvedStyles;
|
|
182
|
-
let resolvedInlineStyles;
|
|
183
|
-
if (pluginOptions.inlineStylesExtension !== 'css') {
|
|
184
|
-
const styleStrings = extractInlineStylesOxc(code, id);
|
|
185
|
-
if (styleStrings.length > 0) {
|
|
186
|
-
resolvedInlineStyles = new Map();
|
|
187
|
-
for (let i = 0; i < styleStrings.length; i++) {
|
|
188
|
-
try {
|
|
189
|
-
const fakePath = id.replace(/\.ts$/, `.inline-${i}.${pluginOptions.inlineStylesExtension}`);
|
|
190
|
-
const processed = await preprocessCSS(styleStrings[i], fakePath, resolvedConfig);
|
|
191
|
-
resolvedInlineStyles.set(i, processed.code);
|
|
192
|
-
}
|
|
193
|
-
catch {
|
|
194
|
-
// Skip styles that can't be preprocessed
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
if (resolvedInlineStyles.size === 0)
|
|
198
|
-
resolvedInlineStyles = undefined;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
// Lazily scan .d.ts files for any external packages this file imports,
|
|
202
|
-
// so pre-compiled directives (e.g. RouterLinkActive) are in the registry
|
|
203
|
-
// before template compilation needs them.
|
|
204
|
-
ensureDtsRegistryForSource(code, id);
|
|
205
|
-
const result = analogCompile(code, id, {
|
|
206
|
-
registry: analogRegistry,
|
|
207
|
-
resolvedStyles,
|
|
208
|
-
resolvedInlineStyles,
|
|
209
|
-
});
|
|
210
|
-
// Track resource dependencies for HMR
|
|
211
|
-
for (const dep of result.resourceDependencies) {
|
|
212
|
-
analogResourceToSource.set(dep, id);
|
|
213
|
-
}
|
|
214
|
-
// Strip TypeScript-only syntax that the analog compiler preserves.
|
|
215
|
-
// Use OXC to reliably strip all TS syntax (type annotations, generics,
|
|
216
|
-
// interfaces, etc.) so the output is valid JavaScript for both client
|
|
217
|
-
// and SSR environments.
|
|
218
|
-
const stripped = await vite.transformWithOxc(result.code, id, {
|
|
219
|
-
lang: 'ts',
|
|
220
|
-
sourcemap: false,
|
|
221
|
-
decorator: { legacy: false, emitDecoratorMetadata: false },
|
|
222
|
-
});
|
|
223
|
-
let outputCode = stripped.code;
|
|
224
|
-
// Append HMR code in dev mode
|
|
225
|
-
if (watchMode && pluginOptions.liveReload) {
|
|
226
|
-
const fileDeclarations = [...analogRegistry.values()].filter((e) => e.fileName === id);
|
|
227
|
-
if (fileDeclarations.length > 0) {
|
|
228
|
-
// Local deps: other Angular classes in the same file that components
|
|
229
|
-
// may reference as template dependencies.
|
|
230
|
-
const localDepClassNames = fileDeclarations.map((e) => e.className);
|
|
231
|
-
outputCode += generateHmrCode(fileDeclarations, localDepClassNames);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
return { code: outputCode, map: result.map };
|
|
235
|
-
}
|
|
236
113
|
function angularPlugin() {
|
|
237
114
|
let isProd = false;
|
|
238
115
|
if (angularFullVersion < 190000 || isTest) {
|
|
@@ -254,7 +131,6 @@ export function angular(options) {
|
|
|
254
131
|
}
|
|
255
132
|
return {
|
|
256
133
|
name: '@analogjs/vite-plugin-angular',
|
|
257
|
-
...(pluginOptions.useAnalogCompiler ? { enforce: 'pre' } : {}),
|
|
258
134
|
async config(config, { command }) {
|
|
259
135
|
watchMode = command === 'serve';
|
|
260
136
|
isProd =
|
|
@@ -268,62 +144,26 @@ export function angular(options) {
|
|
|
268
144
|
};
|
|
269
145
|
// Do a preliminary resolution for esbuild plugin (before configResolved)
|
|
270
146
|
const preliminaryTsConfigPath = resolveTsConfigPath();
|
|
271
|
-
// When useAnalogCompiler is true, configure the built-in OXC transform
|
|
272
|
-
// to strip TypeScript but NOT lower decorators. The analog compiler
|
|
273
|
-
// handles decorator processing in its transform hook. This avoids the
|
|
274
|
-
// ordering conflict where lowered decorators can't be found by the
|
|
275
|
-
// compiler, while still ensuring all .ts files get TypeScript stripped
|
|
276
|
-
// (including those excluded from the analog compiler's transform filter).
|
|
277
147
|
const esbuild = pluginOptions.useAngularCompilationAPI
|
|
278
148
|
? undefined
|
|
279
|
-
:
|
|
280
|
-
? false
|
|
281
|
-
: (config.esbuild ?? false);
|
|
149
|
+
: (config.esbuild ?? false);
|
|
282
150
|
const oxc = pluginOptions.useAngularCompilationAPI
|
|
283
151
|
? undefined
|
|
284
|
-
:
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
plugins: [
|
|
294
|
-
createRolldownCompilerPlugin({
|
|
295
|
-
tsconfig: preliminaryTsConfigPath,
|
|
296
|
-
sourcemap: !isProd,
|
|
297
|
-
advancedOptimizations: isProd,
|
|
298
|
-
jit,
|
|
299
|
-
incremental: watchMode,
|
|
300
|
-
}),
|
|
301
|
-
],
|
|
302
|
-
};
|
|
303
|
-
const esbuildOptions = {
|
|
304
|
-
plugins: [
|
|
305
|
-
createCompilerPlugin({
|
|
306
|
-
tsconfig: preliminaryTsConfigPath,
|
|
307
|
-
sourcemap: !isProd,
|
|
308
|
-
advancedOptimizations: isProd,
|
|
309
|
-
jit,
|
|
310
|
-
incremental: watchMode,
|
|
311
|
-
}, isTest, !isAstroIntegration),
|
|
312
|
-
],
|
|
313
|
-
define: defineOptions,
|
|
314
|
-
};
|
|
152
|
+
: (config.oxc ?? false);
|
|
153
|
+
const depOptimizer = createDepOptimizerConfig({
|
|
154
|
+
tsconfig: preliminaryTsConfigPath,
|
|
155
|
+
isProd,
|
|
156
|
+
jit,
|
|
157
|
+
watchMode,
|
|
158
|
+
isTest,
|
|
159
|
+
isAstroIntegration,
|
|
160
|
+
});
|
|
315
161
|
return {
|
|
316
162
|
...(vite.rolldownVersion ? { oxc } : { esbuild }),
|
|
317
|
-
|
|
318
|
-
include: ['rxjs/operators', 'rxjs'],
|
|
319
|
-
exclude: ['@angular/platform-server'],
|
|
320
|
-
...(vite.rolldownVersion
|
|
321
|
-
? { rolldownOptions }
|
|
322
|
-
: { esbuildOptions }),
|
|
323
|
-
},
|
|
163
|
+
...depOptimizer,
|
|
324
164
|
resolve: {
|
|
325
165
|
conditions: [
|
|
326
|
-
|
|
166
|
+
...depOptimizer.resolve.conditions,
|
|
327
167
|
...(config.resolve?.conditions || defaultClientConditions),
|
|
328
168
|
],
|
|
329
169
|
},
|
|
@@ -352,26 +192,6 @@ export function angular(options) {
|
|
|
352
192
|
},
|
|
353
193
|
configureServer(server) {
|
|
354
194
|
viteServer = server;
|
|
355
|
-
if (pluginOptions.useAnalogCompiler) {
|
|
356
|
-
// Watch for new .ts files and scan them into the registry
|
|
357
|
-
server.watcher.on('add', (filePath) => {
|
|
358
|
-
if (filePath.endsWith('.ts') &&
|
|
359
|
-
!filePath.endsWith('.spec.ts') &&
|
|
360
|
-
!filePath.endsWith('.d.ts')) {
|
|
361
|
-
try {
|
|
362
|
-
const code = require('fs').readFileSync(filePath, 'utf-8');
|
|
363
|
-
const entries = analogScanFile(code, filePath);
|
|
364
|
-
for (const entry of entries) {
|
|
365
|
-
analogRegistry.set(entry.className, entry);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
catch {
|
|
369
|
-
// Skip unreadable files
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
});
|
|
373
|
-
return;
|
|
374
|
-
}
|
|
375
195
|
// Add/unlink changes the TypeScript program shape, not just file
|
|
376
196
|
// contents, so we need to invalidate both include discovery and the
|
|
377
197
|
// cached tsconfig root names before recompiling.
|
|
@@ -385,10 +205,6 @@ export function angular(options) {
|
|
|
385
205
|
});
|
|
386
206
|
},
|
|
387
207
|
async buildStart() {
|
|
388
|
-
if (pluginOptions.useAnalogCompiler) {
|
|
389
|
-
await initAnalogCompiler();
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
392
208
|
// Defer the first compilation in test mode
|
|
393
209
|
if (!isVitestVscode) {
|
|
394
210
|
await performCompilation(resolvedConfig);
|
|
@@ -397,35 +213,6 @@ export function angular(options) {
|
|
|
397
213
|
}
|
|
398
214
|
},
|
|
399
215
|
async handleHotUpdate(ctx) {
|
|
400
|
-
// Analog compiler HMR path
|
|
401
|
-
if (pluginOptions.useAnalogCompiler) {
|
|
402
|
-
// Resource file changes → invalidate parent .ts module
|
|
403
|
-
if (analogResourceToSource.has(ctx.file)) {
|
|
404
|
-
const parentSource = analogResourceToSource.get(ctx.file);
|
|
405
|
-
const parentModule = ctx.server.moduleGraph.getModuleById(parentSource);
|
|
406
|
-
if (parentModule) {
|
|
407
|
-
return [parentModule];
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
if (TS_EXT_REGEX.test(ctx.file)) {
|
|
411
|
-
const [fileId] = ctx.file.split('?');
|
|
412
|
-
const code = require('fs').readFileSync(fileId, 'utf-8');
|
|
413
|
-
// Remove old entries from this file
|
|
414
|
-
const oldEntries = [...analogRegistry.entries()]
|
|
415
|
-
.filter(([_, v]) => v.fileName === fileId)
|
|
416
|
-
.map(([k]) => k);
|
|
417
|
-
for (const key of oldEntries) {
|
|
418
|
-
analogRegistry.delete(key);
|
|
419
|
-
}
|
|
420
|
-
// Rescan the changed file
|
|
421
|
-
const newEntries = analogScanFile(code, fileId);
|
|
422
|
-
for (const entry of newEntries) {
|
|
423
|
-
analogRegistry.set(entry.className, entry);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
// Let Vite handle the rest — the transform hook will recompile
|
|
427
|
-
return ctx.modules;
|
|
428
|
-
}
|
|
429
216
|
if (TS_EXT_REGEX.test(ctx.file)) {
|
|
430
217
|
let [fileId] = ctx.file.split('?');
|
|
431
218
|
pendingCompilation = performCompilation(resolvedConfig, [fileId]);
|
|
@@ -531,23 +318,34 @@ export function angular(options) {
|
|
|
531
318
|
return ctx.modules;
|
|
532
319
|
},
|
|
533
320
|
resolveId(id, importer) {
|
|
321
|
+
if (id.startsWith(VIRTUAL_RAW_PREFIX)) {
|
|
322
|
+
return `\0${id}`;
|
|
323
|
+
}
|
|
534
324
|
if (jit && id.startsWith('angular:jit:')) {
|
|
535
|
-
const
|
|
536
|
-
|
|
325
|
+
const filePath = normalizePath(resolve(dirname(importer), id.split(';')[1]));
|
|
326
|
+
if (id.includes(':style')) {
|
|
327
|
+
// Mark the style path as safe so Vite's Denied ID check
|
|
328
|
+
// passes, then let Vite's native CSS pipeline handle the
|
|
329
|
+
// ?inline import (preprocessing, test.css, etc.).
|
|
330
|
+
markStylePathSafe(resolvedConfig, filePath);
|
|
331
|
+
return filePath + '?inline';
|
|
332
|
+
}
|
|
333
|
+
return toVirtualRawId(filePath);
|
|
537
334
|
}
|
|
538
|
-
//
|
|
539
|
-
//
|
|
540
|
-
|
|
541
|
-
if (
|
|
335
|
+
// User `.html?raw` imports get rewritten to virtual ids so
|
|
336
|
+
// Vite's server.fs Denied ID check stays out of the way.
|
|
337
|
+
const rawRewrite = rewriteHtmlRawImport(id, importer);
|
|
338
|
+
if (rawRewrite)
|
|
339
|
+
return rawRewrite;
|
|
340
|
+
// User `.scss?inline` / `.css?inline` imports: resolve and mark
|
|
341
|
+
// safe so Vite's native CSS pipeline handles them.
|
|
342
|
+
if (/\.(css|scss|sass|less)\?inline$/.test(id) && importer) {
|
|
542
343
|
const filePath = id.split('?')[0];
|
|
543
344
|
const resolved = isAbsolute(filePath)
|
|
544
345
|
? normalizePath(filePath)
|
|
545
|
-
: importer
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
if (resolved) {
|
|
549
|
-
return resolved + '?analog-raw';
|
|
550
|
-
}
|
|
346
|
+
: normalizePath(resolve(dirname(importer), filePath));
|
|
347
|
+
markStylePathSafe(resolvedConfig, resolved);
|
|
348
|
+
return resolved + '?inline';
|
|
551
349
|
}
|
|
552
350
|
// Map angular external styleUrls to the source file
|
|
553
351
|
if (isComponentStyleSheet(id)) {
|
|
@@ -559,12 +357,19 @@ export function angular(options) {
|
|
|
559
357
|
return undefined;
|
|
560
358
|
},
|
|
561
359
|
async load(id) {
|
|
562
|
-
//
|
|
563
|
-
//
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
360
|
+
// Virtual raw ids (templates) come from the transform-time
|
|
361
|
+
// substitution below and the resolveId rewrite for user
|
|
362
|
+
// `.html?raw` imports. Style ?inline imports now flow through
|
|
363
|
+
// Vite's native CSS pipeline via safeModulePaths.
|
|
364
|
+
const rawModule = await loadVirtualRawModule(this, id);
|
|
365
|
+
if (rawModule !== undefined)
|
|
366
|
+
return rawModule;
|
|
367
|
+
// Vitest fallback: the module-runner calls ensureEntryFromUrl
|
|
368
|
+
// before transformRequest, which can skip resolveId. Mark the
|
|
369
|
+
// path safe here so the Denied ID check passes, then let Vite's
|
|
370
|
+
// CSS pipeline handle the rest.
|
|
371
|
+
if (/\.(css|scss|sass|less)\?inline$/.test(id)) {
|
|
372
|
+
markStylePathSafe(resolvedConfig, id.split('?')[0]);
|
|
568
373
|
}
|
|
569
374
|
// Map angular inline styles to the source text
|
|
570
375
|
if (isComponentStyleSheet(id)) {
|
|
@@ -590,13 +395,6 @@ export function angular(options) {
|
|
|
590
395
|
!(options?.transformFilter(code, id) ?? true)) {
|
|
591
396
|
return;
|
|
592
397
|
}
|
|
593
|
-
// Analog compiler transform path
|
|
594
|
-
if (pluginOptions.useAnalogCompiler) {
|
|
595
|
-
if (id.includes('.ts?')) {
|
|
596
|
-
id = id.replace(/\?(.*)/, '');
|
|
597
|
-
}
|
|
598
|
-
return handleAnalogCompilerTransform(code, id);
|
|
599
|
-
}
|
|
600
398
|
if (pluginOptions.useAngularCompilationAPI) {
|
|
601
399
|
const isAngular = /(Component|Directive|Pipe|Injectable|NgModule)\(/.test(code);
|
|
602
400
|
if (!isAngular) {
|
|
@@ -667,24 +465,43 @@ export function angular(options) {
|
|
|
667
465
|
pendingCompilation = null;
|
|
668
466
|
}
|
|
669
467
|
const typescriptResult = fileEmitter(id);
|
|
670
|
-
|
|
671
|
-
|
|
468
|
+
// File not in the Angular program — skip and let other plugins
|
|
469
|
+
// or Vite's built-in transform handle it. Warn if it looks like
|
|
470
|
+
// an Angular file that should have been compiled.
|
|
471
|
+
if (!typescriptResult) {
|
|
472
|
+
const isAngular = !id.includes('@ng/component') &&
|
|
473
|
+
/(Component|Directive|Pipe|Injectable|NgModule)\(/.test(code);
|
|
474
|
+
if (isAngular) {
|
|
475
|
+
this.warn(`[@analogjs/vite-plugin-angular]: "${id}" contains Angular decorators but is not in the TypeScript program. ` +
|
|
476
|
+
`Ensure it is included in your tsconfig.`);
|
|
477
|
+
}
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
if (typescriptResult.warnings &&
|
|
481
|
+
typescriptResult.warnings.length > 0) {
|
|
672
482
|
this.warn(`${typescriptResult.warnings.join('\n')}`);
|
|
673
483
|
}
|
|
674
|
-
if (typescriptResult
|
|
484
|
+
if (typescriptResult.errors && typescriptResult.errors.length > 0) {
|
|
675
485
|
this.error(`${typescriptResult.errors.join('\n')}`);
|
|
676
486
|
}
|
|
677
|
-
|
|
678
|
-
let data = typescriptResult?.content ?? '';
|
|
487
|
+
let data = typescriptResult.content ?? '';
|
|
679
488
|
if (jit && data.includes('angular:jit:')) {
|
|
680
489
|
data = data.replace(/angular:jit:style:inline;/g, 'virtual:angular:jit:style:inline;');
|
|
490
|
+
// Templates use virtual ids (no extension) so Vite's asset/CSS
|
|
491
|
+
// plugins don't interfere. (#2263)
|
|
681
492
|
templateUrls.forEach((templateUrlSet) => {
|
|
682
493
|
const [templateFile, resolvedTemplateUrl] = templateUrlSet.split('|');
|
|
683
|
-
data = data.replace(`angular:jit:template:file;${templateFile}`,
|
|
494
|
+
data = data.replace(`angular:jit:template:file;${templateFile}`, toVirtualRawId(resolvedTemplateUrl));
|
|
684
495
|
});
|
|
496
|
+
// External styles use native ?inline imports. We mark each
|
|
497
|
+
// path as safe in Vite's safeModulePaths so the Denied ID
|
|
498
|
+
// security check passes, and Vite's CSS pipeline handles
|
|
499
|
+
// preprocessing, test.css, and browser/node differences
|
|
500
|
+
// natively. (#2263, #2310)
|
|
685
501
|
styleUrls.forEach((styleUrlSet) => {
|
|
686
502
|
const [styleFile, resolvedStyleUrl] = styleUrlSet.split('|');
|
|
687
|
-
|
|
503
|
+
markStylePathSafe(resolvedConfig, resolvedStyleUrl);
|
|
504
|
+
data = data.replace(`angular:jit:style:file;${styleFile}`, resolvedStyleUrl + '?inline');
|
|
688
505
|
});
|
|
689
506
|
}
|
|
690
507
|
return {
|
|
@@ -705,10 +522,26 @@ export function angular(options) {
|
|
|
705
522
|
},
|
|
706
523
|
};
|
|
707
524
|
}
|
|
525
|
+
const compilationPlugin = pluginOptions.fastCompile
|
|
526
|
+
? fastCompilePlugin({
|
|
527
|
+
tsconfigGetter: pluginOptions.tsconfigGetter,
|
|
528
|
+
workspaceRoot: pluginOptions.workspaceRoot,
|
|
529
|
+
inlineStylesExtension: pluginOptions.inlineStylesExtension,
|
|
530
|
+
jit,
|
|
531
|
+
liveReload: pluginOptions.liveReload,
|
|
532
|
+
supportedBrowsers: pluginOptions.supportedBrowsers,
|
|
533
|
+
transformFilter: options?.transformFilter,
|
|
534
|
+
isTest,
|
|
535
|
+
isAstroIntegration,
|
|
536
|
+
fastCompileMode: pluginOptions.fastCompileMode,
|
|
537
|
+
})
|
|
538
|
+
: angularPlugin();
|
|
708
539
|
return [
|
|
709
540
|
replaceFiles(pluginOptions.fileReplacements, pluginOptions.workspaceRoot),
|
|
710
|
-
|
|
711
|
-
pluginOptions.
|
|
541
|
+
compilationPlugin,
|
|
542
|
+
!pluginOptions.fastCompile &&
|
|
543
|
+
pluginOptions.liveReload &&
|
|
544
|
+
liveReloadPlugin({ classNames, fileEmitter }),
|
|
712
545
|
...(isTest && !isStackBlitz ? angularVitestPlugins() : []),
|
|
713
546
|
(jit &&
|
|
714
547
|
jitPlugin({
|
|
@@ -734,37 +567,6 @@ export function angular(options) {
|
|
|
734
567
|
absolute: true,
|
|
735
568
|
});
|
|
736
569
|
}
|
|
737
|
-
function createTsConfigGetter(tsconfigOrGetter) {
|
|
738
|
-
if (typeof tsconfigOrGetter === 'function') {
|
|
739
|
-
return tsconfigOrGetter;
|
|
740
|
-
}
|
|
741
|
-
return () => tsconfigOrGetter || '';
|
|
742
|
-
}
|
|
743
|
-
function getTsConfigPath(root, tsconfig, isProd, isTest, isLib) {
|
|
744
|
-
if (tsconfig && isAbsolute(tsconfig)) {
|
|
745
|
-
if (!existsSync(tsconfig)) {
|
|
746
|
-
console.error(`[@analogjs/vite-plugin-angular]: Unable to resolve tsconfig at ${tsconfig}. This causes compilation issues. Check the path or set the "tsconfig" property with an absolute path.`);
|
|
747
|
-
}
|
|
748
|
-
return tsconfig;
|
|
749
|
-
}
|
|
750
|
-
let tsconfigFilePath = './tsconfig.app.json';
|
|
751
|
-
if (isLib) {
|
|
752
|
-
tsconfigFilePath = isProd
|
|
753
|
-
? './tsconfig.lib.prod.json'
|
|
754
|
-
: './tsconfig.lib.json';
|
|
755
|
-
}
|
|
756
|
-
if (isTest) {
|
|
757
|
-
tsconfigFilePath = './tsconfig.spec.json';
|
|
758
|
-
}
|
|
759
|
-
if (tsconfig) {
|
|
760
|
-
tsconfigFilePath = tsconfig;
|
|
761
|
-
}
|
|
762
|
-
const resolvedPath = resolve(root, tsconfigFilePath);
|
|
763
|
-
if (!existsSync(resolvedPath)) {
|
|
764
|
-
console.error(`[@analogjs/vite-plugin-angular]: Unable to resolve tsconfig at ${resolvedPath}. This causes compilation issues. Check the path or set the "tsconfig" property with an absolute path.`);
|
|
765
|
-
}
|
|
766
|
-
return resolvedPath;
|
|
767
|
-
}
|
|
768
570
|
function resolveTsConfigPath() {
|
|
769
571
|
const tsconfigValue = pluginOptions.tsconfigGetter();
|
|
770
572
|
return getTsConfigPath(tsConfigResolutionContext.root, tsconfigValue, tsConfigResolutionContext.isProd, isTest, tsConfigResolutionContext.isLib);
|
|
@@ -944,8 +746,8 @@ export function angular(options) {
|
|
|
944
746
|
annotationsAs: 'decorators',
|
|
945
747
|
enableResourceInlining: false,
|
|
946
748
|
noEmitOnError: false,
|
|
947
|
-
mapRoot:
|
|
948
|
-
sourceRoot:
|
|
749
|
+
mapRoot: '',
|
|
750
|
+
sourceRoot: '',
|
|
949
751
|
supportTestBed: false,
|
|
950
752
|
supportJitMode: false,
|
|
951
753
|
});
|