@analogjs/vite-plugin-angular 2.5.0-beta.5 → 2.5.0-beta.50
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 +105 -282
- 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-beta.
|
|
3
|
+
"version": "2.5.0-beta.50",
|
|
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,9 +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);
|
|
334
|
+
}
|
|
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) {
|
|
343
|
+
const filePath = id.split('?')[0];
|
|
344
|
+
const resolved = isAbsolute(filePath)
|
|
345
|
+
? normalizePath(filePath)
|
|
346
|
+
: normalizePath(resolve(dirname(importer), filePath));
|
|
347
|
+
markStylePathSafe(resolvedConfig, resolved);
|
|
348
|
+
return resolved + '?inline';
|
|
537
349
|
}
|
|
538
350
|
// Map angular external styleUrls to the source file
|
|
539
351
|
if (isComponentStyleSheet(id)) {
|
|
@@ -545,6 +357,20 @@ export function angular(options) {
|
|
|
545
357
|
return undefined;
|
|
546
358
|
},
|
|
547
359
|
async load(id) {
|
|
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]);
|
|
373
|
+
}
|
|
548
374
|
// Map angular inline styles to the source text
|
|
549
375
|
if (isComponentStyleSheet(id)) {
|
|
550
376
|
const componentStyles = inlineComponentStyles?.get(getFilenameFromPath(id));
|
|
@@ -569,13 +395,6 @@ export function angular(options) {
|
|
|
569
395
|
!(options?.transformFilter(code, id) ?? true)) {
|
|
570
396
|
return;
|
|
571
397
|
}
|
|
572
|
-
// Analog compiler transform path
|
|
573
|
-
if (pluginOptions.useAnalogCompiler) {
|
|
574
|
-
if (id.includes('.ts?')) {
|
|
575
|
-
id = id.replace(/\?(.*)/, '');
|
|
576
|
-
}
|
|
577
|
-
return handleAnalogCompilerTransform(code, id);
|
|
578
|
-
}
|
|
579
398
|
if (pluginOptions.useAngularCompilationAPI) {
|
|
580
399
|
const isAngular = /(Component|Directive|Pipe|Injectable|NgModule)\(/.test(code);
|
|
581
400
|
if (!isAngular) {
|
|
@@ -646,24 +465,43 @@ export function angular(options) {
|
|
|
646
465
|
pendingCompilation = null;
|
|
647
466
|
}
|
|
648
467
|
const typescriptResult = fileEmitter(id);
|
|
649
|
-
|
|
650
|
-
|
|
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) {
|
|
651
482
|
this.warn(`${typescriptResult.warnings.join('\n')}`);
|
|
652
483
|
}
|
|
653
|
-
if (typescriptResult
|
|
484
|
+
if (typescriptResult.errors && typescriptResult.errors.length > 0) {
|
|
654
485
|
this.error(`${typescriptResult.errors.join('\n')}`);
|
|
655
486
|
}
|
|
656
|
-
|
|
657
|
-
let data = typescriptResult?.content ?? '';
|
|
487
|
+
let data = typescriptResult.content ?? '';
|
|
658
488
|
if (jit && data.includes('angular:jit:')) {
|
|
659
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)
|
|
660
492
|
templateUrls.forEach((templateUrlSet) => {
|
|
661
493
|
const [templateFile, resolvedTemplateUrl] = templateUrlSet.split('|');
|
|
662
|
-
data = data.replace(`angular:jit:template:file;${templateFile}`,
|
|
494
|
+
data = data.replace(`angular:jit:template:file;${templateFile}`, toVirtualRawId(resolvedTemplateUrl));
|
|
663
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)
|
|
664
501
|
styleUrls.forEach((styleUrlSet) => {
|
|
665
502
|
const [styleFile, resolvedStyleUrl] = styleUrlSet.split('|');
|
|
666
|
-
|
|
503
|
+
markStylePathSafe(resolvedConfig, resolvedStyleUrl);
|
|
504
|
+
data = data.replace(`angular:jit:style:file;${styleFile}`, resolvedStyleUrl + '?inline');
|
|
667
505
|
});
|
|
668
506
|
}
|
|
669
507
|
return {
|
|
@@ -684,10 +522,26 @@ export function angular(options) {
|
|
|
684
522
|
},
|
|
685
523
|
};
|
|
686
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();
|
|
687
539
|
return [
|
|
688
540
|
replaceFiles(pluginOptions.fileReplacements, pluginOptions.workspaceRoot),
|
|
689
|
-
|
|
690
|
-
pluginOptions.
|
|
541
|
+
compilationPlugin,
|
|
542
|
+
!pluginOptions.fastCompile &&
|
|
543
|
+
pluginOptions.liveReload &&
|
|
544
|
+
liveReloadPlugin({ classNames, fileEmitter }),
|
|
691
545
|
...(isTest && !isStackBlitz ? angularVitestPlugins() : []),
|
|
692
546
|
(jit &&
|
|
693
547
|
jitPlugin({
|
|
@@ -713,37 +567,6 @@ export function angular(options) {
|
|
|
713
567
|
absolute: true,
|
|
714
568
|
});
|
|
715
569
|
}
|
|
716
|
-
function createTsConfigGetter(tsconfigOrGetter) {
|
|
717
|
-
if (typeof tsconfigOrGetter === 'function') {
|
|
718
|
-
return tsconfigOrGetter;
|
|
719
|
-
}
|
|
720
|
-
return () => tsconfigOrGetter || '';
|
|
721
|
-
}
|
|
722
|
-
function getTsConfigPath(root, tsconfig, isProd, isTest, isLib) {
|
|
723
|
-
if (tsconfig && isAbsolute(tsconfig)) {
|
|
724
|
-
if (!existsSync(tsconfig)) {
|
|
725
|
-
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.`);
|
|
726
|
-
}
|
|
727
|
-
return tsconfig;
|
|
728
|
-
}
|
|
729
|
-
let tsconfigFilePath = './tsconfig.app.json';
|
|
730
|
-
if (isLib) {
|
|
731
|
-
tsconfigFilePath = isProd
|
|
732
|
-
? './tsconfig.lib.prod.json'
|
|
733
|
-
: './tsconfig.lib.json';
|
|
734
|
-
}
|
|
735
|
-
if (isTest) {
|
|
736
|
-
tsconfigFilePath = './tsconfig.spec.json';
|
|
737
|
-
}
|
|
738
|
-
if (tsconfig) {
|
|
739
|
-
tsconfigFilePath = tsconfig;
|
|
740
|
-
}
|
|
741
|
-
const resolvedPath = resolve(root, tsconfigFilePath);
|
|
742
|
-
if (!existsSync(resolvedPath)) {
|
|
743
|
-
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.`);
|
|
744
|
-
}
|
|
745
|
-
return resolvedPath;
|
|
746
|
-
}
|
|
747
570
|
function resolveTsConfigPath() {
|
|
748
571
|
const tsconfigValue = pluginOptions.tsconfigGetter();
|
|
749
572
|
return getTsConfigPath(tsConfigResolutionContext.root, tsconfigValue, tsConfigResolutionContext.isProd, isTest, tsConfigResolutionContext.isLib);
|