@analogjs/vite-plugin-angular 3.0.0-alpha.22 → 3.0.0-alpha.24
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/package.json +5 -3
- package/src/lib/angular-vite-plugin.d.ts +13 -0
- package/src/lib/angular-vite-plugin.js +136 -29
- package/src/lib/angular-vite-plugin.js.map +1 -1
- package/src/lib/host.js +15 -0
- package/src/lib/host.js.map +1 -1
- package/src/lib/live-reload-plugin.js +6 -0
- package/src/lib/live-reload-plugin.js.map +1 -1
- package/src/lib/utils/debug-harness.d.ts +23 -0
- package/src/lib/utils/debug-harness.js +88 -0
- package/src/lib/utils/debug-harness.js.map +1 -0
- package/src/lib/utils/debug-log-file.d.ts +5 -0
- package/src/lib/utils/debug-log-file.js +56 -0
- package/src/lib/utils/debug-log-file.js.map +1 -0
- package/src/lib/utils/debug.d.ts +21 -0
- package/src/lib/utils/debug.js +25 -0
- package/src/lib/utils/debug.js.map +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@analogjs/vite-plugin-angular",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.24",
|
|
4
4
|
"description": "Vite Plugin for Angular",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -36,9 +36,11 @@
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"
|
|
39
|
+
"es-toolkit": "^1.45.1",
|
|
40
|
+
"obug": "^2.1.1",
|
|
41
|
+
"oxc-parser": "^0.123.0",
|
|
40
42
|
"oxc-resolver": "^11.19.1",
|
|
41
|
-
"rolldown": "^1.0.0-rc.
|
|
43
|
+
"rolldown": "^1.0.0-rc.13",
|
|
42
44
|
"tinyglobby": "^0.2.15"
|
|
43
45
|
},
|
|
44
46
|
"builders": "./src/lib/tools/builders.json",
|
|
@@ -2,6 +2,7 @@ import { NgtscProgram } from "@angular/compiler-cli";
|
|
|
2
2
|
import * as ts from "typescript";
|
|
3
3
|
import { Plugin } from "vite";
|
|
4
4
|
import type { StylePreprocessor } from "./style-preprocessor.js";
|
|
5
|
+
import { type DebugOption } from "./utils/debug.js";
|
|
5
6
|
import { FileReplacement } from "./plugins/file-replacements.plugin.js";
|
|
6
7
|
export declare enum DiagnosticModes {
|
|
7
8
|
None = 0,
|
|
@@ -35,6 +36,18 @@ export interface PluginOptions {
|
|
|
35
36
|
useAngularCompilationAPI?: boolean;
|
|
36
37
|
};
|
|
37
38
|
/**
|
|
39
|
+
* Enable debug logging for specific scopes.
|
|
40
|
+
*
|
|
41
|
+
* - `true` → enables all `analog:angular:*` scopes
|
|
42
|
+
* - `string[]` → enables listed namespaces (e.g. `['analog:angular:compiler']`)
|
|
43
|
+
* - `{ scopes?, mode? }` → object form with optional `mode: 'build' | 'dev'`
|
|
44
|
+
* to restrict output to a specific Vite command (omit for both)
|
|
45
|
+
*
|
|
46
|
+
* Also responds to the `DEBUG` env var (Node.js) or `localStorage.debug`
|
|
47
|
+
* (browser), using the `obug` convention.
|
|
48
|
+
*/
|
|
49
|
+
debug?: DebugOption;
|
|
50
|
+
/**
|
|
38
51
|
* Optional preprocessor that transforms component CSS before it enters Vite's
|
|
39
52
|
* preprocessCSS pipeline. Runs on every component stylesheet (both external
|
|
40
53
|
* `.component.css` files and inline `styles: [...]` blocks).
|
|
@@ -4,6 +4,7 @@ import { buildOptimizerPlugin } from "./angular-build-optimizer-plugin.js";
|
|
|
4
4
|
import { jitPlugin } from "./angular-jit-plugin.js";
|
|
5
5
|
import { createCompilerPlugin, createRolldownCompilerPlugin } from "./compiler-plugin.js";
|
|
6
6
|
import { StyleUrlsResolver, TemplateUrlsResolver } from "./component-resolvers.js";
|
|
7
|
+
import { activateDeferredDebug, applyDebugOption, debugCompilationApi, debugCompiler, debugHmr, debugStyles, debugTailwind } from "./utils/debug.js";
|
|
7
8
|
import { augmentHostWithCaching, augmentHostWithResources, augmentProgramWithVersioning, mergeTransformers } from "./host.js";
|
|
8
9
|
import { angularVitestPlugins } from "./angular-vitest-plugin.js";
|
|
9
10
|
import { pendingTasksPlugin } from "./angular-pending-tasks.plugin.js";
|
|
@@ -11,6 +12,7 @@ import { liveReloadPlugin } from "./live-reload-plugin.js";
|
|
|
11
12
|
import { nxFolderPlugin } from "./nx-folder-plugin.js";
|
|
12
13
|
import { replaceFiles } from "./plugins/file-replacements.plugin.js";
|
|
13
14
|
import { routerPlugin } from "./router-plugin.js";
|
|
15
|
+
import { union } from "es-toolkit";
|
|
14
16
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
15
17
|
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
16
18
|
import * as compilerCli from "@angular/compiler-cli";
|
|
@@ -49,18 +51,33 @@ function buildStylePreprocessor(options) {
|
|
|
49
51
|
if (tw) {
|
|
50
52
|
const rootStylesheet = tw.rootStylesheet;
|
|
51
53
|
const prefixes = tw.prefixes;
|
|
54
|
+
debugTailwind("configured", {
|
|
55
|
+
rootStylesheet,
|
|
56
|
+
prefixes
|
|
57
|
+
});
|
|
52
58
|
tailwindPreprocessor = (code, filename) => {
|
|
53
|
-
if (code.includes("@reference") || code.includes("@import \"tailwindcss\"") || code.includes("@import 'tailwindcss'"))
|
|
54
|
-
|
|
59
|
+
if (code.includes("@reference") || code.includes("@import \"tailwindcss\"") || code.includes("@import 'tailwindcss'")) {
|
|
60
|
+
debugTailwind("skip (already has @reference or is root)", { filename });
|
|
61
|
+
return code;
|
|
62
|
+
}
|
|
63
|
+
if (!(prefixes ? prefixes.some((prefix) => code.includes(prefix)) : code.includes("@apply"))) {
|
|
64
|
+
debugTailwind("skip (no Tailwind usage detected)", { filename });
|
|
65
|
+
return code;
|
|
66
|
+
}
|
|
67
|
+
debugTailwind("injected @reference", { filename });
|
|
55
68
|
return `@reference "${relative(dirname(filename), rootStylesheet)}";\n${code}`;
|
|
56
69
|
};
|
|
57
70
|
}
|
|
58
|
-
if (tailwindPreprocessor && userPreprocessor)
|
|
59
|
-
|
|
60
|
-
|
|
71
|
+
if (tailwindPreprocessor && userPreprocessor) {
|
|
72
|
+
debugTailwind("chained with user stylePreprocessor");
|
|
73
|
+
return (code, filename) => {
|
|
74
|
+
return userPreprocessor(tailwindPreprocessor(code, filename), filename);
|
|
75
|
+
};
|
|
76
|
+
}
|
|
61
77
|
return tailwindPreprocessor ?? userPreprocessor;
|
|
62
78
|
}
|
|
63
79
|
function angular(options) {
|
|
80
|
+
applyDebugOption(options?.debug, options?.workspaceRoot);
|
|
64
81
|
/**
|
|
65
82
|
* Normalize plugin options so defaults
|
|
66
83
|
* are used for values not provided.
|
|
@@ -129,16 +146,22 @@ function angular(options) {
|
|
|
129
146
|
let angularCompilation;
|
|
130
147
|
function angularPlugin() {
|
|
131
148
|
let isProd = false;
|
|
132
|
-
if (angularFullVersion < 19e4 || isTest)
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
149
|
+
if (angularFullVersion < 19e4 || isTest) {
|
|
150
|
+
pluginOptions.liveReload = false;
|
|
151
|
+
debugHmr("liveReload disabled", {
|
|
152
|
+
angularVersion: angularFullVersion,
|
|
153
|
+
isTest
|
|
154
|
+
});
|
|
138
155
|
}
|
|
156
|
+
if (pluginOptions.useAngularCompilationAPI) if (angularFullVersion < 200100) {
|
|
157
|
+
pluginOptions.useAngularCompilationAPI = false;
|
|
158
|
+
debugCompilationApi("disabled: Angular version %s < 20.1", angularFullVersion);
|
|
159
|
+
console.warn("[@analogjs/vite-plugin-angular]: The Angular Compilation API is only available with Angular v20.1 and later");
|
|
160
|
+
} else debugCompilationApi("enabled (Angular %s)", angularFullVersion);
|
|
139
161
|
return {
|
|
140
162
|
name: "@analogjs/vite-plugin-angular",
|
|
141
163
|
async config(config, { command }) {
|
|
164
|
+
activateDeferredDebug(command);
|
|
142
165
|
watchMode = command === "serve";
|
|
143
166
|
isProd = config.mode === "production" || process.env.NODE_ENV === "production";
|
|
144
167
|
tsConfigResolutionContext = {
|
|
@@ -149,6 +172,7 @@ function angular(options) {
|
|
|
149
172
|
const preliminaryTsConfigPath = resolveTsConfigPath();
|
|
150
173
|
const esbuild = pluginOptions.useAngularCompilationAPI ? void 0 : config.esbuild ?? false;
|
|
151
174
|
const oxc = pluginOptions.useAngularCompilationAPI ? void 0 : config.oxc ?? false;
|
|
175
|
+
if (pluginOptions.useAngularCompilationAPI) debugCompilationApi("esbuild/oxc disabled, Angular handles transforms");
|
|
152
176
|
const defineOptions = {
|
|
153
177
|
ngJitMode: "false",
|
|
154
178
|
ngI18nClosureMode: "false",
|
|
@@ -189,6 +213,7 @@ function angular(options) {
|
|
|
189
213
|
if (pluginOptions.useAngularCompilationAPI) {
|
|
190
214
|
externalComponentStyles = /* @__PURE__ */ new Map();
|
|
191
215
|
inlineComponentStyles = /* @__PURE__ */ new Map();
|
|
216
|
+
debugStyles("style maps initialized (Angular Compilation API)");
|
|
192
217
|
}
|
|
193
218
|
if (!jit) styleTransform = (code, filename) => preprocessCSS(code, filename, config);
|
|
194
219
|
if (isTest) testWatchMode = !(config.server.watch === null) || config.test?.watch === true || testWatchMode;
|
|
@@ -212,15 +237,25 @@ function angular(options) {
|
|
|
212
237
|
async handleHotUpdate(ctx) {
|
|
213
238
|
if (TS_EXT_REGEX.test(ctx.file)) {
|
|
214
239
|
const [fileId] = ctx.file.split("?");
|
|
240
|
+
debugHmr("TS file changed", {
|
|
241
|
+
file: ctx.file,
|
|
242
|
+
fileId
|
|
243
|
+
});
|
|
215
244
|
pendingCompilation = performCompilation(resolvedConfig, [fileId]);
|
|
216
245
|
let result;
|
|
217
246
|
if (pluginOptions.liveReload) {
|
|
218
247
|
await pendingCompilation;
|
|
219
248
|
pendingCompilation = null;
|
|
220
249
|
result = fileEmitter(fileId);
|
|
250
|
+
debugHmr("TS file emitted", {
|
|
251
|
+
fileId,
|
|
252
|
+
hmrEligible: !!result?.hmrEligible,
|
|
253
|
+
hasClassName: !!classNames.get(fileId)
|
|
254
|
+
});
|
|
221
255
|
}
|
|
222
256
|
if (pluginOptions.liveReload && result?.hmrEligible && classNames.get(fileId)) {
|
|
223
257
|
const relativeFileId = `${normalizePath(relative(process.cwd(), fileId))}@${classNames.get(fileId)}`;
|
|
258
|
+
debugHmr("sending component update", { relativeFileId });
|
|
224
259
|
sendHMRComponentUpdate(ctx.server, relativeFileId);
|
|
225
260
|
return ctx.modules.map((mod) => {
|
|
226
261
|
if (mod.id === ctx.file) return markModuleSelfAccepting(mod);
|
|
@@ -229,6 +264,7 @@ function angular(options) {
|
|
|
229
264
|
}
|
|
230
265
|
}
|
|
231
266
|
if (/\.(html|htm|css|less|sass|scss)$/.test(ctx.file)) {
|
|
267
|
+
debugHmr("resource file changed", { file: ctx.file });
|
|
232
268
|
fileTransformMap.delete(ctx.file.split("?")[0]);
|
|
233
269
|
/**
|
|
234
270
|
* Check to see if this was a direct request
|
|
@@ -240,6 +276,10 @@ function angular(options) {
|
|
|
240
276
|
if (pluginOptions.liveReload && isDirect?.id && isDirect.file) {
|
|
241
277
|
if (isDirect.type === "css" && isComponentStyleSheet(isDirect.id)) {
|
|
242
278
|
const { encapsulation } = getComponentStyleSheetMeta(isDirect.id);
|
|
279
|
+
debugStyles("HMR: component stylesheet changed", {
|
|
280
|
+
file: isDirect.file,
|
|
281
|
+
encapsulation
|
|
282
|
+
});
|
|
243
283
|
if (encapsulation !== "shadow") {
|
|
244
284
|
ctx.server.ws.send({
|
|
245
285
|
type: "update",
|
|
@@ -274,6 +314,10 @@ function angular(options) {
|
|
|
274
314
|
if (updates.length > 0) {
|
|
275
315
|
await pendingCompilation;
|
|
276
316
|
pendingCompilation = null;
|
|
317
|
+
debugHmr("resource importer component updates", {
|
|
318
|
+
file: ctx.file,
|
|
319
|
+
updateCount: updates.length
|
|
320
|
+
});
|
|
277
321
|
updates.forEach((updateId) => {
|
|
278
322
|
const impRelativeFileId = `${normalizePath(relative(process.cwd(), updateId))}@${classNames.get(updateId)}`;
|
|
279
323
|
sendHMRComponentUpdate(ctx.server, impRelativeFileId);
|
|
@@ -285,6 +329,7 @@ function angular(options) {
|
|
|
285
329
|
}
|
|
286
330
|
return mods;
|
|
287
331
|
}
|
|
332
|
+
debugHmr("full reload — unrecognized file type", { file: ctx.file });
|
|
288
333
|
classNames.clear();
|
|
289
334
|
return ctx.modules;
|
|
290
335
|
},
|
|
@@ -294,14 +339,28 @@ function angular(options) {
|
|
|
294
339
|
return `${normalizePath(resolve(dirname(importer), path))}?${id.includes(":style") ? "inline" : "raw"}`;
|
|
295
340
|
}
|
|
296
341
|
if (isComponentStyleSheet(id)) {
|
|
297
|
-
const
|
|
298
|
-
|
|
342
|
+
const filename = getFilenameFromPath(id);
|
|
343
|
+
const componentStyles = externalComponentStyles?.get(filename);
|
|
344
|
+
if (componentStyles) {
|
|
345
|
+
debugStyles("resolveId: mapped external stylesheet", {
|
|
346
|
+
filename,
|
|
347
|
+
resolvedPath: componentStyles
|
|
348
|
+
});
|
|
349
|
+
return componentStyles + new URL(id, "http://localhost").search;
|
|
350
|
+
}
|
|
299
351
|
}
|
|
300
352
|
},
|
|
301
353
|
async load(id) {
|
|
302
354
|
if (isComponentStyleSheet(id)) {
|
|
303
|
-
const
|
|
304
|
-
|
|
355
|
+
const filename = getFilenameFromPath(id);
|
|
356
|
+
const componentStyles = inlineComponentStyles?.get(filename);
|
|
357
|
+
if (componentStyles) {
|
|
358
|
+
debugStyles("load: served inline component stylesheet", {
|
|
359
|
+
filename,
|
|
360
|
+
length: componentStyles.length
|
|
361
|
+
});
|
|
362
|
+
return componentStyles;
|
|
363
|
+
}
|
|
305
364
|
}
|
|
306
365
|
},
|
|
307
366
|
transform: {
|
|
@@ -319,7 +378,10 @@ function angular(options) {
|
|
|
319
378
|
*/
|
|
320
379
|
if (options?.transformFilter && !(options?.transformFilter(code, id) ?? true)) return;
|
|
321
380
|
if (pluginOptions.useAngularCompilationAPI) {
|
|
322
|
-
if (!/(Component|Directive|Pipe|Injectable|NgModule)\(/.test(code))
|
|
381
|
+
if (!/(Component|Directive|Pipe|Injectable|NgModule)\(/.test(code)) {
|
|
382
|
+
debugCompilationApi("transform skip (non-Angular file)", { id });
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
323
385
|
}
|
|
324
386
|
/**
|
|
325
387
|
* Skip transforming content files
|
|
@@ -330,10 +392,16 @@ function angular(options) {
|
|
|
330
392
|
*/
|
|
331
393
|
if (pluginOptions.liveReload && isComponentStyleSheet(id)) {
|
|
332
394
|
const { encapsulation, componentId } = getComponentStyleSheetMeta(id);
|
|
333
|
-
if (encapsulation === "emulated" && componentId)
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
395
|
+
if (encapsulation === "emulated" && componentId) {
|
|
396
|
+
debugStyles("applying emulated view encapsulation", {
|
|
397
|
+
stylesheet: id.split("?")[0],
|
|
398
|
+
componentId
|
|
399
|
+
});
|
|
400
|
+
return {
|
|
401
|
+
code: ngCompiler.encapsulateStyle(code, componentId),
|
|
402
|
+
map: null
|
|
403
|
+
};
|
|
404
|
+
}
|
|
337
405
|
}
|
|
338
406
|
if (id.includes(".ts?")) id = id.replace(/\?(.*)/, "");
|
|
339
407
|
fileTransformMap.set(id, code);
|
|
@@ -353,6 +421,11 @@ function angular(options) {
|
|
|
353
421
|
}
|
|
354
422
|
}
|
|
355
423
|
const hasComponent = code.includes("@Component");
|
|
424
|
+
debugCompiler("transform", {
|
|
425
|
+
id,
|
|
426
|
+
codeLength: code.length,
|
|
427
|
+
hasComponent
|
|
428
|
+
});
|
|
356
429
|
const templateUrls = hasComponent ? templateUrlsResolver.resolve(code, id) : [];
|
|
357
430
|
const styleUrls = hasComponent ? styleUrlsResolver.resolve(code, id) : [];
|
|
358
431
|
if (hasComponent && watchMode) for (const urlSet of [...templateUrls, ...styleUrls]) {
|
|
@@ -458,7 +531,10 @@ function angular(options) {
|
|
|
458
531
|
angularCompilation ??= await createAngularCompilation(!!pluginOptions.jit, false);
|
|
459
532
|
const modifiedFiles = ids?.length ? new Set(ids.map((file) => normalizePath(file))) : void 0;
|
|
460
533
|
if (modifiedFiles?.size) sourceFileCache$1.invalidate(modifiedFiles);
|
|
461
|
-
if (modifiedFiles?.size && angularCompilation.update)
|
|
534
|
+
if (modifiedFiles?.size && angularCompilation.update) {
|
|
535
|
+
debugCompilationApi("incremental update", { files: [...modifiedFiles] });
|
|
536
|
+
await angularCompilation.update(modifiedFiles);
|
|
537
|
+
}
|
|
462
538
|
const resolvedTsConfigPath = resolveTsConfigPath();
|
|
463
539
|
const compilationResult = await angularCompilation.initialize(resolvedTsConfigPath, {
|
|
464
540
|
fileReplacements: toAngularCompilationFileReplacements(pluginOptions.fileReplacements, pluginOptions.workspaceRoot),
|
|
@@ -469,8 +545,17 @@ function angular(options) {
|
|
|
469
545
|
if (pluginOptions.liveReload && watchMode) {
|
|
470
546
|
const stylesheetId = createHash("sha256").update(containingFile).update(className).update(String(order)).update(preprocessedData).digest("hex") + "." + pluginOptions.inlineStylesExtension;
|
|
471
547
|
inlineComponentStyles.set(stylesheetId, preprocessedData);
|
|
548
|
+
debugStyles("stylesheet deferred to Vite pipeline (liveReload)", {
|
|
549
|
+
stylesheetId,
|
|
550
|
+
resourceFile: resourceFile ?? "(inline)"
|
|
551
|
+
});
|
|
472
552
|
return stylesheetId;
|
|
473
553
|
}
|
|
554
|
+
debugStyles("stylesheet processed inline via preprocessCSS (no liveReload)", {
|
|
555
|
+
filename,
|
|
556
|
+
resourceFile: resourceFile ?? "(inline)",
|
|
557
|
+
dataLength: preprocessedData.length
|
|
558
|
+
});
|
|
474
559
|
let stylesheetResult;
|
|
475
560
|
try {
|
|
476
561
|
stylesheetResult = await preprocessCSS(preprocessedData, `${filename}?direct`, resolvedConfig);
|
|
@@ -488,6 +573,12 @@ function angular(options) {
|
|
|
488
573
|
tsCompilerOptions["externalRuntimeStyles"] = true;
|
|
489
574
|
tsCompilerOptions["supportTestBed"] = true;
|
|
490
575
|
}
|
|
576
|
+
debugCompiler("tsCompilerOptions (compilation API)", {
|
|
577
|
+
liveReload: pluginOptions.liveReload,
|
|
578
|
+
watchMode,
|
|
579
|
+
externalRuntimeStyles: !!tsCompilerOptions["externalRuntimeStyles"],
|
|
580
|
+
hmr: !!tsCompilerOptions["_enableHmr"]
|
|
581
|
+
});
|
|
491
582
|
if (tsCompilerOptions.compilationMode === "partial") {
|
|
492
583
|
tsCompilerOptions["supportTestBed"] = true;
|
|
493
584
|
tsCompilerOptions["supportJitMode"] = true;
|
|
@@ -502,11 +593,19 @@ function angular(options) {
|
|
|
502
593
|
});
|
|
503
594
|
compilationResult.externalStylesheets?.forEach((value, key) => {
|
|
504
595
|
externalComponentStyles?.set(`${value}.css`, key);
|
|
596
|
+
debugStyles("external stylesheet registered for resolveId mapping", {
|
|
597
|
+
filename: `${value}.css`,
|
|
598
|
+
resolvedPath: key
|
|
599
|
+
});
|
|
505
600
|
});
|
|
506
601
|
const diagnostics = await angularCompilation.diagnoseFiles(pluginOptions.disableTypeChecking ? DiagnosticModes.All & ~DiagnosticModes.Semantic : DiagnosticModes.All);
|
|
507
602
|
const errors = diagnostics.errors?.length ? diagnostics.errors : [];
|
|
508
603
|
const warnings = diagnostics.warnings?.length ? diagnostics.warnings : [];
|
|
509
604
|
const templateUpdates = mapTemplateUpdatesToFiles(compilationResult.templateUpdates);
|
|
605
|
+
if (templateUpdates.size > 0) debugHmr("compilation API template updates", {
|
|
606
|
+
count: templateUpdates.size,
|
|
607
|
+
files: [...templateUpdates.keys()]
|
|
608
|
+
});
|
|
510
609
|
for (const file of await angularCompilation.emitAffectedFiles()) {
|
|
511
610
|
const normalizedFilename = normalizePath(file.filename);
|
|
512
611
|
const templateUpdate = templateUpdates.get(normalizedFilename);
|
|
@@ -540,6 +639,7 @@ function angular(options) {
|
|
|
540
639
|
*/
|
|
541
640
|
async function _doPerformCompilation(config, ids) {
|
|
542
641
|
if (pluginOptions.useAngularCompilationAPI) {
|
|
642
|
+
debugCompilationApi("using compilation API path", { modifiedFiles: ids?.length ?? 0 });
|
|
543
643
|
await performAngularCompilation(config, ids);
|
|
544
644
|
return;
|
|
545
645
|
}
|
|
@@ -587,6 +687,10 @@ function angular(options) {
|
|
|
587
687
|
tsCompilerOptions["externalRuntimeStyles"] = true;
|
|
588
688
|
tsCompilerOptions["supportTestBed"] = true;
|
|
589
689
|
}
|
|
690
|
+
debugCompiler("tsCompilerOptions (NgtscProgram path)", {
|
|
691
|
+
externalRuntimeStyles: !!tsCompilerOptions["externalRuntimeStyles"],
|
|
692
|
+
hmr: !!tsCompilerOptions["_enableHmr"]
|
|
693
|
+
});
|
|
590
694
|
if (tsCompilerOptions["compilationMode"] === "partial") {
|
|
591
695
|
tsCompilerOptions["supportTestBed"] = true;
|
|
592
696
|
tsCompilerOptions["supportJitMode"] = true;
|
|
@@ -598,11 +702,7 @@ function angular(options) {
|
|
|
598
702
|
}
|
|
599
703
|
if (isTest) tsCompilerOptions["supportTestBed"] = true;
|
|
600
704
|
const replacements = pluginOptions.fileReplacements.map((rp) => join(pluginOptions.workspaceRoot, rp.ssr || rp.with));
|
|
601
|
-
rootNames =
|
|
602
|
-
...rootNames,
|
|
603
|
-
...includeCache,
|
|
604
|
-
...replacements
|
|
605
|
-
])];
|
|
705
|
+
rootNames = union(rootNames, includeCache, replacements);
|
|
606
706
|
const hostKey = JSON.stringify(tsCompilerOptions);
|
|
607
707
|
let host;
|
|
608
708
|
if (cachedHost && cachedHostKey === hostKey) host = cachedHost;
|
|
@@ -621,8 +721,10 @@ function angular(options) {
|
|
|
621
721
|
if (watchMode) augmentHostWithCaching(host, sourceFileCache$1);
|
|
622
722
|
}
|
|
623
723
|
if (!jit) {
|
|
624
|
-
|
|
625
|
-
|
|
724
|
+
const externalizeStyles = !!tsCompilerOptions["externalRuntimeStyles"];
|
|
725
|
+
inlineComponentStyles = externalizeStyles ? /* @__PURE__ */ new Map() : void 0;
|
|
726
|
+
externalComponentStyles = externalizeStyles ? /* @__PURE__ */ new Map() : void 0;
|
|
727
|
+
debugStyles("style maps initialized (NgtscProgram path)", { externalizeStyles });
|
|
626
728
|
augmentHostWithResources(host, styleTransform, {
|
|
627
729
|
inlineStylesExtension: pluginOptions.inlineStylesExtension,
|
|
628
730
|
isProd,
|
|
@@ -769,8 +871,13 @@ function getFileMetadata(program, angularCompiler, liveReload, disableTypeChecki
|
|
|
769
871
|
for (const node of sourceFile.statements) if (ts.isClassDeclaration(node) && node.name != null) {
|
|
770
872
|
hmrUpdateCode = angularCompiler?.emitHmrUpdateModule(node);
|
|
771
873
|
if (hmrUpdateCode) {
|
|
772
|
-
|
|
874
|
+
const className = node.name.getText();
|
|
875
|
+
classNames.set(file, className);
|
|
773
876
|
hmrEligible = true;
|
|
877
|
+
debugHmr("NgtscProgram emitHmrUpdateModule", {
|
|
878
|
+
file,
|
|
879
|
+
className
|
|
880
|
+
});
|
|
774
881
|
}
|
|
775
882
|
}
|
|
776
883
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"angular-vite-plugin.js","names":[],"sources":["../../../src/lib/angular-vite-plugin.ts"],"sourcesContent":["import { NgtscProgram } from '@angular/compiler-cli';\nimport { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport {\n basename,\n dirname,\n isAbsolute,\n join,\n relative,\n resolve,\n} from 'node:path';\nimport * as vite from 'vite';\n\nimport * as compilerCli from '@angular/compiler-cli';\nimport { createRequire } from 'node:module';\nimport * as ts from 'typescript';\nimport { type createAngularCompilation as createAngularCompilationType } from '@angular/build/private';\n\nimport * as ngCompiler from '@angular/compiler';\nimport { globSync } from 'tinyglobby';\nimport {\n defaultClientConditions,\n ModuleNode,\n normalizePath,\n Plugin,\n preprocessCSS,\n ResolvedConfig,\n ViteDevServer,\n} from 'vite';\nimport { buildOptimizerPlugin } from './angular-build-optimizer-plugin.js';\nimport { jitPlugin } from './angular-jit-plugin.js';\nimport {\n createCompilerPlugin,\n createRolldownCompilerPlugin,\n} from './compiler-plugin.js';\nimport {\n StyleUrlsResolver,\n TemplateUrlsResolver,\n} from './component-resolvers.js';\nimport {\n augmentHostWithCaching,\n augmentHostWithResources,\n augmentProgramWithVersioning,\n mergeTransformers,\n} from './host.js';\nimport type { StylePreprocessor } from './style-preprocessor.js';\n\nimport { angularVitestPlugins } from './angular-vitest-plugin.js';\nimport {\n createAngularCompilation,\n createJitResourceTransformer,\n SourceFileCache,\n angularFullVersion,\n} from './utils/devkit.js';\nimport { getJsTransformConfigKey, isRolldown } from './utils/rolldown.js';\nimport { type SourceFileCache as SourceFileCacheType } from './utils/source-file-cache.js';\n\nconst require = createRequire(import.meta.url);\n\nimport { pendingTasksPlugin } from './angular-pending-tasks.plugin.js';\nimport { liveReloadPlugin } from './live-reload-plugin.js';\nimport { EmitFileResult } from './models.js';\nimport { nxFolderPlugin } from './nx-folder-plugin.js';\nimport {\n FileReplacement,\n FileReplacementSSR,\n FileReplacementWith,\n replaceFiles,\n} from './plugins/file-replacements.plugin.js';\nimport { routerPlugin } from './router-plugin.js';\nimport { createHash } from 'node:crypto';\n\nexport enum DiagnosticModes {\n None = 0,\n Option = 1 << 0,\n Syntactic = 1 << 1,\n Semantic = 1 << 2,\n All = Option | Syntactic | Semantic,\n}\n\nexport interface PluginOptions {\n tsconfig?: string | (() => string);\n workspaceRoot?: string;\n inlineStylesExtension?: string;\n jit?: boolean;\n advanced?: {\n /**\n * Custom TypeScript transformers that are run before Angular compilation\n */\n tsTransformers?: ts.CustomTransformers;\n };\n supportedBrowsers?: string[];\n transformFilter?: (code: string, id: string) => boolean;\n /**\n * Additional files to include in compilation\n */\n include?: string[];\n additionalContentDirs?: string[];\n liveReload?: boolean;\n disableTypeChecking?: boolean;\n fileReplacements?: FileReplacement[];\n experimental?: {\n useAngularCompilationAPI?: boolean;\n };\n /**\n * Optional preprocessor that transforms component CSS before it enters Vite's\n * preprocessCSS pipeline. Runs on every component stylesheet (both external\n * `.component.css` files and inline `styles: [...]` blocks).\n *\n * @param code - Raw CSS content of the component stylesheet\n * @param filename - Resolved file path of the stylesheet (or containing .ts file for inline styles)\n * @returns Transformed CSS string, or the original code if no transformation is needed\n */\n stylePreprocessor?: StylePreprocessor;\n /**\n * First-class Tailwind CSS v4 integration for Angular component styles.\n *\n * Angular's compiler processes component CSS through Vite's `preprocessCSS()`,\n * which runs `@tailwindcss/vite` — but each component stylesheet is processed\n * in isolation without access to the root Tailwind configuration (prefix, @theme,\n * @custom-variant, @plugin definitions). This causes errors like:\n *\n * \"Cannot apply utility class `sa:grid` because the `sa` variant does not exist\"\n *\n * The `tailwindCss` option solves this by auto-injecting a `@reference` directive\n * into every component CSS file that uses Tailwind utilities, pointing it to the\n * root Tailwind stylesheet so `@tailwindcss/vite` can resolve the full configuration.\n *\n * @example Basic usage — reference a root Tailwind CSS file:\n * ```ts\n * import { resolve } from 'node:path';\n *\n * angular({\n * tailwindCss: {\n * rootStylesheet: resolve(__dirname, 'src/styles/tailwind.css'),\n * },\n * })\n * ```\n *\n * @example With prefix detection — only inject for files using specific prefixes:\n * ```ts\n * angular({\n * tailwindCss: {\n * rootStylesheet: resolve(__dirname, 'src/styles/tailwind.css'),\n * // Only inject @reference into files that use these prefixed classes\n * prefixes: ['sa:', 'tw:'],\n * },\n * })\n * ```\n *\n * @example AnalogJS platform — passed through the `vite` option:\n * ```ts\n * analog({\n * vite: {\n * tailwindCss: {\n * rootStylesheet: resolve(__dirname, '../../../libs/meritos/tailwind.config.css'),\n * },\n * },\n * })\n * ```\n */\n tailwindCss?: {\n /**\n * Absolute path to the root Tailwind CSS file that contains `@import \"tailwindcss\"`,\n * `@theme`, `@custom-variant`, and `@plugin` definitions.\n *\n * A `@reference` directive pointing to this file will be auto-injected into\n * component CSS files that use Tailwind utilities.\n */\n rootStylesheet: string;\n /**\n * Optional list of class prefixes to detect (e.g. `['sa:', 'tw:']`).\n * When provided, `@reference` is only injected into component CSS files that\n * contain at least one of these prefixes. When omitted, `@reference` is injected\n * into all component CSS files that contain `@apply` or `@` directives.\n *\n * @default undefined — inject into all component CSS files with `@apply`\n */\n prefixes?: string[];\n };\n}\n\n/**\n * TypeScript file extension regex\n * Match .(c or m)ts, .ts extensions with an optional ? for query params\n * Ignore .tsx extensions\n */\nconst TS_EXT_REGEX = /\\.[cm]?(ts)[^x]?\\??/;\nconst classNames = new Map();\n\ninterface DeclarationFile {\n declarationFileDir: string;\n declarationPath: string;\n data: string;\n}\n\n/**\n * Builds a resolved stylePreprocessor function from plugin options.\n * If `tailwindCss` is provided, creates an auto-reference injector.\n * If `stylePreprocessor` is also provided, chains them (tailwind first, then user).\n */\nfunction buildStylePreprocessor(\n options?: PluginOptions,\n): ((code: string, filename: string) => string) | undefined {\n const userPreprocessor = options?.stylePreprocessor;\n const tw = options?.tailwindCss;\n\n if (!tw && !userPreprocessor) {\n return undefined;\n }\n\n // Build the Tailwind @reference injector\n let tailwindPreprocessor:\n | ((code: string, filename: string) => string)\n | undefined;\n\n if (tw) {\n const rootStylesheet = tw.rootStylesheet;\n const prefixes = tw.prefixes;\n\n tailwindPreprocessor = (code: string, filename: string): string => {\n // Skip if already has @reference or is a root Tailwind file\n if (\n code.includes('@reference') ||\n code.includes('@import \"tailwindcss\"') ||\n code.includes(\"@import 'tailwindcss'\")\n ) {\n return code;\n }\n\n // Check if the file uses Tailwind utilities\n const needsReference = prefixes\n ? prefixes.some((prefix) => code.includes(prefix))\n : code.includes('@apply');\n\n if (!needsReference) {\n return code;\n }\n\n const refPath = relative(dirname(filename), rootStylesheet);\n return `@reference \"${refPath}\";\\n${code}`;\n };\n }\n\n // Chain: tailwind preprocessor first, then user preprocessor\n if (tailwindPreprocessor && userPreprocessor) {\n return (code: string, filename: string) => {\n const intermediate = tailwindPreprocessor!(code, filename);\n return userPreprocessor(intermediate, filename);\n };\n }\n\n return tailwindPreprocessor ?? userPreprocessor;\n}\n\nexport function angular(options?: PluginOptions): Plugin[] {\n /**\n * Normalize plugin options so defaults\n * are used for values not provided.\n */\n const pluginOptions = {\n tsconfigGetter: createTsConfigGetter(options?.tsconfig),\n workspaceRoot: options?.workspaceRoot ?? process.cwd(),\n inlineStylesExtension: options?.inlineStylesExtension ?? 'css',\n advanced: {\n tsTransformers: {\n before: options?.advanced?.tsTransformers?.before ?? [],\n after: options?.advanced?.tsTransformers?.after ?? [],\n afterDeclarations:\n options?.advanced?.tsTransformers?.afterDeclarations ?? [],\n },\n },\n supportedBrowsers: options?.supportedBrowsers ?? ['safari 15'],\n jit: options?.jit,\n include: options?.include ?? [],\n additionalContentDirs: options?.additionalContentDirs ?? [],\n liveReload: options?.liveReload ?? false,\n disableTypeChecking: options?.disableTypeChecking ?? true,\n fileReplacements: options?.fileReplacements ?? [],\n useAngularCompilationAPI:\n options?.experimental?.useAngularCompilationAPI ?? false,\n stylePreprocessor: buildStylePreprocessor(options),\n };\n\n let resolvedConfig: ResolvedConfig;\n // Store config context needed for getTsConfigPath resolution\n let tsConfigResolutionContext: {\n root: string;\n isProd: boolean;\n isLib: boolean;\n } | null = null;\n\n const ts = require('typescript');\n let builder: ts.BuilderProgram | ts.EmitAndSemanticDiagnosticsBuilderProgram;\n let nextProgram: NgtscProgram | undefined;\n // Caches (always rebuild Angular program per user request)\n const tsconfigOptionsCache = new Map<\n string,\n { options: ts.CompilerOptions; rootNames: string[] }\n >();\n let cachedHost: ts.CompilerHost | undefined;\n let cachedHostKey: string | undefined;\n let includeCache: string[] = [];\n function invalidateFsCaches() {\n includeCache = [];\n }\n function invalidateTsconfigCaches() {\n // `readConfiguration` caches the root file list, so hot-added pages can be\n // missing from Angular's compilation program until we clear this state.\n tsconfigOptionsCache.clear();\n cachedHost = undefined;\n cachedHostKey = undefined;\n }\n let watchMode = false;\n let testWatchMode = isTestWatchMode();\n let inlineComponentStyles: Map<string, string> | undefined;\n let externalComponentStyles: Map<string, string> | undefined;\n const sourceFileCache: SourceFileCacheType = new SourceFileCache();\n const isTest = process.env['NODE_ENV'] === 'test' || !!process.env['VITEST'];\n const isVitestVscode = !!process.env['VITEST_VSCODE'];\n const isStackBlitz = !!process.versions['webcontainer'];\n const isAstroIntegration = process.env['ANALOG_ASTRO'] === 'true';\n\n const jit =\n typeof pluginOptions?.jit !== 'undefined' ? pluginOptions.jit : isTest;\n let viteServer: ViteDevServer | undefined;\n\n const styleUrlsResolver = new StyleUrlsResolver();\n const templateUrlsResolver = new TemplateUrlsResolver();\n let outputFile: ((file: string) => void) | undefined;\n const outputFiles = new Map<string, EmitFileResult>();\n const fileEmitter = (file: string) => {\n outputFile?.(file);\n return outputFiles.get(normalizePath(file));\n };\n let initialCompilation = false;\n const declarationFiles: DeclarationFile[] = [];\n const fileTransformMap = new Map<string, string>();\n let styleTransform: (\n code: string,\n filename: string,\n ) => Promise<vite.PreprocessCSSResult>;\n let pendingCompilation: Promise<void> | null;\n let compilationLock = Promise.resolve();\n // Persistent Angular Compilation API instance. Kept alive across rebuilds so\n // Angular can diff previous state and emit `templateUpdates` for HMR.\n // Previously the compilation was recreated on every pass, which meant Angular\n // never had prior state and could never produce HMR payloads.\n let angularCompilation:\n | Awaited<ReturnType<typeof createAngularCompilationType>>\n | undefined;\n\n function angularPlugin(): Plugin {\n let isProd = false;\n\n if (angularFullVersion < 190000 || isTest) {\n pluginOptions.liveReload = false;\n }\n\n // liveReload and fileReplacements guards were previously here and forced\n // both options off when useAngularCompilationAPI was enabled. Those guards\n // have been removed because:\n // - liveReload: the persistent compilation instance (above) now gives\n // Angular the prior state it needs to emit `templateUpdates` for HMR\n // - fileReplacements: Angular's AngularHostOptions already accepts a\n // `fileReplacements` record — we now convert and pass it through in\n // `performAngularCompilation` via `toAngularCompilationFileReplacements`\n if (pluginOptions.useAngularCompilationAPI) {\n if (angularFullVersion < 200100) {\n pluginOptions.useAngularCompilationAPI = false;\n console.warn(\n '[@analogjs/vite-plugin-angular]: The Angular Compilation API is only available with Angular v20.1 and later',\n );\n }\n }\n\n return {\n name: '@analogjs/vite-plugin-angular',\n async config(config, { command }) {\n watchMode = command === 'serve';\n isProd =\n config.mode === 'production' ||\n process.env['NODE_ENV'] === 'production';\n\n // Store the config context for later resolution in configResolved\n tsConfigResolutionContext = {\n root: config.root || '.',\n isProd,\n isLib: !!config?.build?.lib,\n };\n\n // Do a preliminary resolution for esbuild plugin (before configResolved)\n const preliminaryTsConfigPath = resolveTsConfigPath();\n\n const esbuild = pluginOptions.useAngularCompilationAPI\n ? undefined\n : (config.esbuild ?? false);\n const oxc = pluginOptions.useAngularCompilationAPI\n ? undefined\n : (config.oxc ?? false);\n\n const defineOptions = {\n ngJitMode: 'false',\n ngI18nClosureMode: 'false',\n ...(watchMode ? {} : { ngDevMode: 'false' }),\n };\n const useRolldown = isRolldown();\n const jsTransformConfigKey = getJsTransformConfigKey();\n const jsTransformConfigValue =\n jsTransformConfigKey === 'oxc' ? oxc : esbuild;\n\n const rolldownOptions: vite.DepOptimizationOptions['rolldownOptions'] =\n {\n plugins: [\n createRolldownCompilerPlugin(\n {\n tsconfig: preliminaryTsConfigPath,\n sourcemap: !isProd,\n advancedOptimizations: isProd,\n jit,\n incremental: watchMode,\n },\n // Astro manages the transformer lifecycle externally.\n !isAstroIntegration,\n ),\n ],\n };\n\n const esbuildOptions: vite.DepOptimizationOptions['esbuildOptions'] = {\n plugins: [\n createCompilerPlugin(\n {\n tsconfig: preliminaryTsConfigPath,\n sourcemap: !isProd,\n advancedOptimizations: isProd,\n jit,\n incremental: watchMode,\n },\n isTest,\n !isAstroIntegration,\n ),\n ],\n define: defineOptions,\n };\n\n return {\n [jsTransformConfigKey]: jsTransformConfigValue,\n optimizeDeps: {\n include: ['rxjs/operators', 'rxjs'],\n exclude: ['@angular/platform-server'],\n ...(useRolldown ? { rolldownOptions } : { esbuildOptions }),\n },\n resolve: {\n conditions: [\n 'style',\n ...(config.resolve?.conditions || defaultClientConditions),\n ],\n },\n };\n },\n configResolved(config) {\n resolvedConfig = config;\n\n if (pluginOptions.useAngularCompilationAPI) {\n externalComponentStyles = new Map();\n inlineComponentStyles = new Map();\n }\n\n if (!jit) {\n styleTransform = (code: string, filename: string) =>\n preprocessCSS(code, filename, config);\n }\n\n if (isTest) {\n // set test watch mode\n // - vite override from vitest-angular\n // - @nx/vite executor set server.watch explicitly to undefined (watch)/null (watch=false)\n // - vite config for test.watch variable\n // - vitest watch mode detected from the command line\n testWatchMode =\n !(config.server.watch === null) ||\n (config as any).test?.watch === true ||\n testWatchMode;\n }\n },\n configureServer(server) {\n viteServer = server;\n // Add/unlink changes the TypeScript program shape, not just file\n // contents, so we need to invalidate both include discovery and the\n // cached tsconfig root names before recompiling.\n const invalidateCompilationOnFsChange = createFsWatcherCacheInvalidator(\n invalidateFsCaches,\n invalidateTsconfigCaches,\n () => performCompilation(resolvedConfig),\n );\n server.watcher.on('add', invalidateCompilationOnFsChange);\n server.watcher.on('unlink', invalidateCompilationOnFsChange);\n server.watcher.on('change', (file) => {\n if (file.includes('tsconfig')) {\n invalidateTsconfigCaches();\n }\n });\n },\n async buildStart() {\n // Defer the first compilation in test mode\n if (!isVitestVscode) {\n await performCompilation(resolvedConfig);\n pendingCompilation = null;\n\n initialCompilation = true;\n }\n },\n async handleHotUpdate(ctx) {\n if (TS_EXT_REGEX.test(ctx.file)) {\n const [fileId] = ctx.file.split('?');\n\n pendingCompilation = performCompilation(resolvedConfig, [fileId]);\n\n let result;\n\n if (pluginOptions.liveReload) {\n await pendingCompilation;\n pendingCompilation = null;\n result = fileEmitter(fileId);\n }\n\n if (\n pluginOptions.liveReload &&\n result?.hmrEligible &&\n classNames.get(fileId)\n ) {\n const relativeFileId = `${normalizePath(\n relative(process.cwd(), fileId),\n )}@${classNames.get(fileId)}`;\n\n sendHMRComponentUpdate(ctx.server, relativeFileId);\n\n return ctx.modules.map((mod) => {\n if (mod.id === ctx.file) {\n return markModuleSelfAccepting(mod);\n }\n\n return mod;\n });\n }\n }\n\n if (/\\.(html|htm|css|less|sass|scss)$/.test(ctx.file)) {\n fileTransformMap.delete(ctx.file.split('?')[0]);\n /**\n * Check to see if this was a direct request\n * for an external resource (styles, html).\n */\n const isDirect = ctx.modules.find(\n (mod) => ctx.file === mod.file && mod.id?.includes('?direct'),\n );\n const isInline = ctx.modules.find(\n (mod) => ctx.file === mod.file && mod.id?.includes('?inline'),\n );\n\n if (isDirect || isInline) {\n if (pluginOptions.liveReload && isDirect?.id && isDirect.file) {\n const isComponentStyle =\n isDirect.type === 'css' && isComponentStyleSheet(isDirect.id);\n if (isComponentStyle) {\n const { encapsulation } = getComponentStyleSheetMeta(\n isDirect.id,\n );\n\n // Track if the component uses ShadowDOM encapsulation\n // Shadow DOM components currently require a full reload.\n // Vite's CSS hot replacement does not support shadow root searching.\n if (encapsulation !== 'shadow') {\n ctx.server.ws.send({\n type: 'update',\n updates: [\n {\n type: 'css-update',\n timestamp: Date.now(),\n path: isDirect.url,\n acceptedPath: isDirect.file,\n },\n ],\n });\n\n return ctx.modules\n .filter((mod) => {\n // Component stylesheets will have 2 modules (*.component.scss and *.component.scss?direct&ngcomp=xyz&e=x)\n // We remove the module with the query params to prevent vite double logging the stylesheet name \"hmr update *.component.scss, *.component.scss?direct&ngcomp=xyz&e=x\"\n return mod.file !== ctx.file || mod.id !== isDirect.id;\n })\n .map((mod) => {\n if (mod.file === ctx.file) {\n return markModuleSelfAccepting(mod);\n }\n return mod;\n }) as ModuleNode[];\n }\n }\n }\n return ctx.modules;\n }\n\n const mods: ModuleNode[] = [];\n const updates: string[] = [];\n ctx.modules.forEach((mod) => {\n mod.importers.forEach((imp) => {\n ctx.server.moduleGraph.invalidateModule(imp);\n\n if (pluginOptions.liveReload && classNames.get(imp.id)) {\n updates.push(imp.id as string);\n } else {\n mods.push(imp);\n }\n });\n });\n\n pendingCompilation = performCompilation(resolvedConfig, [\n ...mods.map((mod) => mod.id as string),\n ...updates,\n ]);\n\n if (updates.length > 0) {\n await pendingCompilation;\n pendingCompilation = null;\n\n updates.forEach((updateId) => {\n const impRelativeFileId = `${normalizePath(\n relative(process.cwd(), updateId),\n )}@${classNames.get(updateId)}`;\n\n sendHMRComponentUpdate(ctx.server, impRelativeFileId);\n });\n\n return ctx.modules.map((mod) => {\n if (mod.id === ctx.file) {\n return markModuleSelfAccepting(mod);\n }\n\n return mod;\n });\n }\n\n return mods;\n }\n\n // clear HMR updates with a full reload\n classNames.clear();\n return ctx.modules;\n },\n resolveId(id, importer) {\n if (jit && id.startsWith('angular:jit:')) {\n const path = id.split(';')[1];\n return `${normalizePath(\n resolve(dirname(importer as string), path),\n )}?${id.includes(':style') ? 'inline' : 'raw'}`;\n }\n\n // Map angular external styleUrls to the source file\n if (isComponentStyleSheet(id)) {\n const componentStyles = externalComponentStyles?.get(\n getFilenameFromPath(id),\n );\n if (componentStyles) {\n return componentStyles + new URL(id, 'http://localhost').search;\n }\n }\n\n return undefined;\n },\n async load(id) {\n // Map angular inline styles to the source text\n if (isComponentStyleSheet(id)) {\n const componentStyles = inlineComponentStyles?.get(\n getFilenameFromPath(id),\n );\n if (componentStyles) {\n return componentStyles;\n }\n }\n\n return;\n },\n transform: {\n filter: {\n id: {\n include: [TS_EXT_REGEX],\n exclude: [/node_modules/, 'type=script', '@ng/component'],\n },\n },\n async handler(code, id) {\n /**\n * Check for options.transformFilter\n */\n if (\n options?.transformFilter &&\n !(options?.transformFilter(code, id) ?? true)\n ) {\n return;\n }\n\n if (pluginOptions.useAngularCompilationAPI) {\n const isAngular =\n /(Component|Directive|Pipe|Injectable|NgModule)\\(/.test(code);\n\n if (!isAngular) {\n return;\n }\n }\n\n /**\n * Skip transforming content files\n */\n if (id.includes('?') && id.includes('analog-content-')) {\n return;\n }\n\n /**\n * Encapsulate component stylesheets that use emulated encapsulation\n */\n if (pluginOptions.liveReload && isComponentStyleSheet(id)) {\n const { encapsulation, componentId } =\n getComponentStyleSheetMeta(id);\n if (encapsulation === 'emulated' && componentId) {\n const encapsulated = ngCompiler.encapsulateStyle(\n code,\n componentId,\n );\n return {\n code: encapsulated,\n map: null,\n };\n }\n }\n\n if (id.includes('.ts?')) {\n // Strip the query string off the ID\n // in case of a dynamically loaded file\n id = id.replace(/\\?(.*)/, '');\n }\n\n fileTransformMap.set(id, code);\n\n /**\n * Re-analyze on each transform\n * for test(Vitest)\n */\n if (isTest) {\n if (isVitestVscode && !initialCompilation) {\n // Do full initial compilation\n pendingCompilation = performCompilation(resolvedConfig);\n initialCompilation = true;\n }\n\n const tsMod = viteServer?.moduleGraph.getModuleById(id);\n if (tsMod) {\n const invalidated = tsMod.lastInvalidationTimestamp;\n\n if (testWatchMode && invalidated) {\n pendingCompilation = performCompilation(resolvedConfig, [id]);\n }\n }\n }\n\n const hasComponent = code.includes('@Component');\n const templateUrls = hasComponent\n ? templateUrlsResolver.resolve(code, id)\n : [];\n const styleUrls = hasComponent\n ? styleUrlsResolver.resolve(code, id)\n : [];\n\n if (hasComponent && watchMode) {\n for (const urlSet of [...templateUrls, ...styleUrls]) {\n // `urlSet` is a string where a relative path is joined with an\n // absolute path using the `|` symbol.\n // For example: `./app.component.html|/home/projects/analog/src/app/app.component.html`.\n const [, absoluteFileUrl] = urlSet.split('|');\n this.addWatchFile(absoluteFileUrl);\n }\n }\n\n if (pendingCompilation) {\n await pendingCompilation;\n pendingCompilation = null;\n }\n\n const typescriptResult = fileEmitter(id);\n\n if (\n typescriptResult?.warnings &&\n typescriptResult?.warnings.length > 0\n ) {\n this.warn(`${typescriptResult.warnings.join('\\n')}`);\n }\n\n if (typescriptResult?.errors && typescriptResult?.errors.length > 0) {\n this.error(`${typescriptResult.errors.join('\\n')}`);\n }\n\n // return fileEmitter\n let data = typescriptResult?.content ?? '';\n\n if (jit && data.includes('angular:jit:')) {\n data = data.replace(\n /angular:jit:style:inline;/g,\n 'virtual:angular:jit:style:inline;',\n );\n\n templateUrls.forEach((templateUrlSet) => {\n const [templateFile, resolvedTemplateUrl] =\n templateUrlSet.split('|');\n data = data.replace(\n `angular:jit:template:file;${templateFile}`,\n `${resolvedTemplateUrl}?raw`,\n );\n });\n\n styleUrls.forEach((styleUrlSet) => {\n const [styleFile, resolvedStyleUrl] = styleUrlSet.split('|');\n data = data.replace(\n `angular:jit:style:file;${styleFile}`,\n `${resolvedStyleUrl}?inline`,\n );\n });\n }\n\n return {\n code: data,\n map: null,\n };\n },\n },\n closeBundle() {\n declarationFiles.forEach(\n ({ declarationFileDir, declarationPath, data }) => {\n mkdirSync(declarationFileDir, { recursive: true });\n writeFileSync(declarationPath, data, 'utf-8');\n },\n );\n // Tear down the persistent compilation instance at end of build so it\n // does not leak memory across unrelated Vite invocations.\n angularCompilation?.close?.();\n angularCompilation = undefined;\n },\n };\n }\n\n return [\n replaceFiles(pluginOptions.fileReplacements, pluginOptions.workspaceRoot),\n angularPlugin(),\n pluginOptions.liveReload && liveReloadPlugin({ classNames, fileEmitter }),\n ...(isTest && !isStackBlitz ? angularVitestPlugins() : []),\n (jit &&\n jitPlugin({\n inlineStylesExtension: pluginOptions.inlineStylesExtension,\n })) as Plugin,\n buildOptimizerPlugin({\n supportedBrowsers: pluginOptions.supportedBrowsers,\n jit,\n }),\n routerPlugin(),\n angularFullVersion < 190004 && pendingTasksPlugin(),\n nxFolderPlugin(),\n ].filter(Boolean) as Plugin[];\n\n function findIncludes() {\n const workspaceRoot = normalizePath(resolve(pluginOptions.workspaceRoot));\n\n // Map include patterns to absolute workspace paths\n const globs = [\n ...pluginOptions.include.map((glob) => `${workspaceRoot}${glob}`),\n ];\n\n // Discover TypeScript files using tinyglobby\n return globSync(globs, {\n dot: true,\n absolute: true,\n });\n }\n\n function createTsConfigGetter(tsconfigOrGetter?: string | (() => string)) {\n if (typeof tsconfigOrGetter === 'function') {\n return tsconfigOrGetter;\n }\n\n return () => tsconfigOrGetter || '';\n }\n\n function getTsConfigPath(\n root: string,\n tsconfig: string,\n isProd: boolean,\n isTest: boolean,\n isLib: boolean,\n ) {\n if (tsconfig && isAbsolute(tsconfig)) {\n if (!existsSync(tsconfig)) {\n console.error(\n `[@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.`,\n );\n }\n\n return tsconfig;\n }\n\n let tsconfigFilePath = './tsconfig.app.json';\n\n if (isLib) {\n tsconfigFilePath = isProd\n ? './tsconfig.lib.prod.json'\n : './tsconfig.lib.json';\n }\n\n if (isTest) {\n tsconfigFilePath = './tsconfig.spec.json';\n }\n\n if (tsconfig) {\n tsconfigFilePath = tsconfig;\n }\n\n const resolvedPath = resolve(root, tsconfigFilePath);\n\n if (!existsSync(resolvedPath)) {\n console.error(\n `[@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.`,\n );\n }\n\n return resolvedPath;\n }\n\n function resolveTsConfigPath() {\n const tsconfigValue = pluginOptions.tsconfigGetter();\n\n return getTsConfigPath(\n tsConfigResolutionContext!.root,\n tsconfigValue,\n tsConfigResolutionContext!.isProd,\n isTest,\n tsConfigResolutionContext!.isLib,\n );\n }\n\n /**\n * Perform compilation using Angular's private Compilation API.\n *\n * Key differences from the standard `performCompilation` path:\n * 1. The compilation instance is reused across rebuilds (nullish-coalescing\n * assignment below) so Angular retains prior state and can diff it to\n * produce `templateUpdates` for HMR.\n * 2. `ids` (modified files) are forwarded to both the source-file cache and\n * `angularCompilation.update()` so that incremental re-analysis is\n * scoped to what actually changed.\n * 3. `fileReplacements` are converted and passed into Angular's host via\n * `toAngularCompilationFileReplacements`.\n * 4. `templateUpdates` from the compilation result are mapped back to\n * file-level HMR metadata (`hmrUpdateCode`, `hmrEligible`, `classNames`).\n */\n async function performAngularCompilation(\n config: ResolvedConfig,\n ids?: string[],\n ) {\n // Reuse the existing instance so Angular can diff against prior state.\n angularCompilation ??= await (\n createAngularCompilation as typeof createAngularCompilationType\n )(!!pluginOptions.jit, false);\n const modifiedFiles = ids?.length\n ? new Set(ids.map((file) => normalizePath(file)))\n : undefined;\n if (modifiedFiles?.size) {\n sourceFileCache.invalidate(modifiedFiles);\n }\n // Notify Angular of modified files before re-initialization so it can\n // scope its incremental analysis.\n if (modifiedFiles?.size && angularCompilation.update) {\n await angularCompilation.update(modifiedFiles);\n }\n\n const resolvedTsConfigPath = resolveTsConfigPath();\n const compilationResult = await angularCompilation.initialize(\n resolvedTsConfigPath,\n {\n // Convert Analog's browser-style `{ replace, with }` entries into the\n // `Record<string, string>` shape that Angular's AngularHostOptions\n // expects. SSR-only replacements (`{ replace, ssr }`) are intentionally\n // excluded — they stay on the Vite runtime side.\n fileReplacements: toAngularCompilationFileReplacements(\n pluginOptions.fileReplacements,\n pluginOptions.workspaceRoot,\n ),\n modifiedFiles,\n async transformStylesheet(\n data,\n containingFile,\n resourceFile,\n order,\n className,\n ) {\n const filename =\n resourceFile ??\n containingFile.replace(\n '.ts',\n `.${pluginOptions.inlineStylesExtension}`,\n );\n\n // Apply any user-defined stylesheet preprocessing before Vite transforms it.\n const preprocessedData = pluginOptions.stylePreprocessor\n ? (pluginOptions.stylePreprocessor(data, filename) ?? data)\n : data;\n\n if (pluginOptions.liveReload && watchMode) {\n // Store the preprocessed (but not yet CSS-transformed) data so that\n // Vite's serve-time pipeline handles PostCSS / Tailwind processing\n // exactly once when the load hook returns this CSS. Running\n // preprocessCSS() here would strip directives like @reference before\n // the CSS re-enters the transform pipeline, causing plugins such as\n // @tailwindcss/vite to fail on the second pass.\n // Guard must match the externalRuntimeStyles condition (line ~927)\n // because the Angular compiler only emits external style references\n // when externalRuntimeStyles is enabled.\n const id = createHash('sha256')\n .update(containingFile)\n .update(className as string)\n .update(String(order))\n .update(preprocessedData)\n .digest('hex');\n const stylesheetId = id + '.' + pluginOptions.inlineStylesExtension;\n inlineComponentStyles!.set(stylesheetId, preprocessedData);\n return stylesheetId;\n }\n\n // Non-liveReload: the CSS is returned directly to the Angular\n // compiler and never re-enters Vite's pipeline, so we must run\n // preprocessCSS() eagerly here.\n let stylesheetResult;\n\n try {\n stylesheetResult = await preprocessCSS(\n preprocessedData,\n `${filename}?direct`,\n resolvedConfig,\n );\n } catch (e) {\n console.error(`${e}`);\n }\n\n return stylesheetResult?.code || '';\n },\n processWebWorker(workerFile, containingFile) {\n return '';\n },\n },\n (tsCompilerOptions) => {\n if (pluginOptions.liveReload && watchMode) {\n tsCompilerOptions['_enableHmr'] = true;\n tsCompilerOptions['externalRuntimeStyles'] = true;\n // Workaround for https://github.com/angular/angular/issues/59310\n // Force extra instructions to be generated for HMR w/defer\n tsCompilerOptions['supportTestBed'] = true;\n }\n\n if (tsCompilerOptions.compilationMode === 'partial') {\n // These options can't be false in partial mode\n tsCompilerOptions['supportTestBed'] = true;\n tsCompilerOptions['supportJitMode'] = true;\n }\n\n if (!isTest && config.build?.lib) {\n tsCompilerOptions['declaration'] = true;\n tsCompilerOptions['declarationMap'] = watchMode;\n tsCompilerOptions['inlineSources'] = true;\n }\n\n if (isTest) {\n // Allow `TestBed.overrideXXX()` APIs.\n tsCompilerOptions['supportTestBed'] = true;\n }\n\n return tsCompilerOptions;\n },\n );\n\n compilationResult.externalStylesheets?.forEach((value, key) => {\n externalComponentStyles?.set(`${value}.css`, key);\n });\n\n const diagnostics = await angularCompilation.diagnoseFiles(\n pluginOptions.disableTypeChecking\n ? DiagnosticModes.All & ~DiagnosticModes.Semantic\n : DiagnosticModes.All,\n );\n\n const errors = diagnostics.errors?.length ? diagnostics.errors : [];\n const warnings = diagnostics.warnings?.length ? diagnostics.warnings : [];\n // Angular encodes template updates as `encodedFilePath@ClassName` keys.\n // `mapTemplateUpdatesToFiles` decodes them back to absolute file paths so\n // we can attach HMR metadata to the correct `EmitFileResult` below.\n const templateUpdates = mapTemplateUpdatesToFiles(\n compilationResult.templateUpdates,\n );\n\n for (const file of await angularCompilation.emitAffectedFiles()) {\n const normalizedFilename = normalizePath(file.filename);\n const templateUpdate = templateUpdates.get(normalizedFilename);\n\n if (templateUpdate) {\n classNames.set(normalizedFilename, templateUpdate.className);\n }\n\n // Surface Angular's HMR payloads into Analog's existing live-reload\n // flow via the `hmrUpdateCode` / `hmrEligible` fields.\n outputFiles.set(normalizedFilename, {\n content: file.contents,\n dependencies: [],\n errors: errors.map((error: { text?: string }) => error.text || ''),\n warnings: warnings.map(\n (warning: { text?: string }) => warning.text || '',\n ),\n hmrUpdateCode: templateUpdate?.code,\n hmrEligible: !!templateUpdate?.code,\n });\n }\n }\n\n async function performCompilation(config: ResolvedConfig, ids?: string[]) {\n let resolve: (() => unknown) | undefined;\n const previousLock = compilationLock;\n compilationLock = new Promise<void>((r) => {\n resolve = r;\n });\n try {\n await previousLock;\n await _doPerformCompilation(config, ids);\n } finally {\n resolve!();\n }\n }\n\n /**\n * This method share mutable state and performs the actual compilation work.\n * It should not be called concurrently. Use `performCompilation` which wraps this method in a lock to ensure only one compilation runs at a time.\n */\n async function _doPerformCompilation(config: ResolvedConfig, ids?: string[]) {\n // Forward `ids` (modified files) so the Compilation API path can do\n // incremental re-analysis instead of a full recompile on every change.\n if (pluginOptions.useAngularCompilationAPI) {\n await performAngularCompilation(config, ids);\n return;\n }\n\n const isProd = config.mode === 'production';\n const modifiedFiles = new Set<string>(ids ?? []);\n sourceFileCache.invalidate(modifiedFiles);\n\n if (ids?.length) {\n for (const id of ids || []) {\n fileTransformMap.delete(id);\n }\n }\n\n // Cached include discovery (invalidated only on FS events)\n if (pluginOptions.include.length > 0 && includeCache.length === 0) {\n includeCache = findIncludes();\n }\n\n const resolvedTsConfigPath = resolveTsConfigPath();\n const tsconfigKey = [\n resolvedTsConfigPath,\n isProd ? 'prod' : 'dev',\n isTest ? 'test' : 'app',\n config.build?.lib ? 'lib' : 'nolib',\n ].join('|');\n let cached = tsconfigOptionsCache.get(tsconfigKey);\n\n if (!cached) {\n const read = compilerCli.readConfiguration(resolvedTsConfigPath, {\n suppressOutputPathCheck: true,\n outDir: undefined,\n sourceMap: false,\n inlineSourceMap: !isProd,\n inlineSources: !isProd,\n declaration: false,\n declarationMap: false,\n allowEmptyCodegenFiles: false,\n annotationsAs: 'decorators',\n enableResourceInlining: false,\n noEmitOnError: false,\n mapRoot: undefined,\n sourceRoot: undefined,\n supportTestBed: false,\n supportJitMode: false,\n });\n cached = { options: read.options, rootNames: read.rootNames };\n tsconfigOptionsCache.set(tsconfigKey, cached);\n }\n\n // Clone options before mutation (preserve cache purity)\n const tsCompilerOptions = { ...cached.options };\n let rootNames = [...cached.rootNames];\n\n if (pluginOptions.liveReload && watchMode) {\n tsCompilerOptions['_enableHmr'] = true;\n tsCompilerOptions['externalRuntimeStyles'] = true;\n // Workaround for https://github.com/angular/angular/issues/59310\n // Force extra instructions to be generated for HMR w/defer\n tsCompilerOptions['supportTestBed'] = true;\n }\n\n if (tsCompilerOptions['compilationMode'] === 'partial') {\n // These options can't be false in partial mode\n tsCompilerOptions['supportTestBed'] = true;\n tsCompilerOptions['supportJitMode'] = true;\n }\n\n if (!isTest && config.build?.lib) {\n tsCompilerOptions['declaration'] = true;\n tsCompilerOptions['declarationMap'] = watchMode;\n tsCompilerOptions['inlineSources'] = true;\n }\n\n if (isTest) {\n // Allow `TestBed.overrideXXX()` APIs.\n tsCompilerOptions['supportTestBed'] = true;\n }\n\n const replacements = pluginOptions.fileReplacements.map((rp) =>\n join(\n pluginOptions.workspaceRoot,\n (rp as FileReplacementSSR).ssr || (rp as FileReplacementWith).with,\n ),\n );\n // Merge + dedupe root names\n rootNames = [...new Set([...rootNames, ...includeCache, ...replacements])];\n const hostKey = JSON.stringify(tsCompilerOptions);\n let host: ts.CompilerHost;\n\n if (cachedHost && cachedHostKey === hostKey) {\n host = cachedHost;\n } else {\n host = ts.createIncrementalCompilerHost(tsCompilerOptions, {\n ...ts.sys,\n readFile(path: string, encoding: string) {\n if (fileTransformMap.has(path)) {\n return fileTransformMap.get(path);\n }\n\n const file = ts.sys.readFile.call(null, path, encoding);\n\n if (file) {\n fileTransformMap.set(path, file);\n }\n\n return file;\n },\n });\n cachedHost = host;\n cachedHostKey = hostKey;\n\n // Only store cache if in watch mode\n if (watchMode) {\n augmentHostWithCaching(host, sourceFileCache);\n }\n }\n\n if (!jit) {\n inlineComponentStyles = tsCompilerOptions['externalRuntimeStyles']\n ? new Map()\n : undefined;\n externalComponentStyles = tsCompilerOptions['externalRuntimeStyles']\n ? new Map()\n : undefined;\n augmentHostWithResources(host, styleTransform, {\n inlineStylesExtension: pluginOptions.inlineStylesExtension,\n isProd,\n inlineComponentStyles,\n externalComponentStyles,\n sourceFileCache,\n stylePreprocessor: pluginOptions.stylePreprocessor,\n });\n }\n\n /**\n * Creates a new NgtscProgram to analyze/re-analyze\n * the source files and create a file emitter.\n * This is shared between an initial build and a hot update.\n */\n let typeScriptProgram: ts.Program;\n let angularCompiler: NgtscProgram['compiler'];\n const oldBuilder =\n builder ?? ts.readBuilderProgram(tsCompilerOptions, host);\n\n if (!jit) {\n // Create the Angular specific program that contains the Angular compiler\n const angularProgram: NgtscProgram = new compilerCli.NgtscProgram(\n rootNames,\n tsCompilerOptions,\n host,\n nextProgram,\n );\n angularCompiler = angularProgram.compiler;\n typeScriptProgram = angularProgram.compiler.getCurrentProgram();\n augmentProgramWithVersioning(typeScriptProgram);\n\n builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(\n typeScriptProgram,\n host,\n oldBuilder as ts.EmitAndSemanticDiagnosticsBuilderProgram,\n );\n\n nextProgram = angularProgram;\n } else {\n builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(\n rootNames,\n tsCompilerOptions,\n host,\n oldBuilder as ts.EmitAndSemanticDiagnosticsBuilderProgram,\n );\n\n typeScriptProgram = builder.getProgram();\n }\n\n if (!watchMode) {\n // When not in watch mode, the startup cost of the incremental analysis can be avoided by\n // using an abstract builder that only wraps a TypeScript program.\n builder = ts.createAbstractBuilder(typeScriptProgram, host, oldBuilder);\n }\n\n if (angularCompiler!) {\n await angularCompiler.analyzeAsync();\n }\n\n const beforeTransformers = jit\n ? [\n compilerCli.constructorParametersDownlevelTransform(\n builder.getProgram(),\n ),\n createJitResourceTransformer(() =>\n builder.getProgram().getTypeChecker(),\n ),\n ]\n : [];\n\n const transformers = mergeTransformers(\n { before: beforeTransformers },\n jit ? {} : angularCompiler!.prepareEmit().transformers,\n );\n\n const fileMetadata = getFileMetadata(\n builder,\n angularCompiler!,\n pluginOptions.liveReload,\n pluginOptions.disableTypeChecking,\n );\n\n const writeFileCallback: ts.WriteFileCallback = (\n _filename,\n content,\n _a,\n _b,\n sourceFiles,\n ) => {\n if (!sourceFiles?.length) {\n return;\n }\n\n const filename = normalizePath(sourceFiles[0].fileName);\n\n if (filename.includes('ngtypecheck.ts') || filename.includes('.d.')) {\n return;\n }\n\n const metadata = watchMode ? fileMetadata(filename) : {};\n\n outputFiles.set(filename, {\n content,\n dependencies: [],\n errors: metadata.errors,\n warnings: metadata.warnings,\n hmrUpdateCode: metadata.hmrUpdateCode,\n hmrEligible: metadata.hmrEligible,\n });\n };\n\n const writeOutputFile = (id: string) => {\n const sourceFile = builder.getSourceFile(id);\n if (!sourceFile) {\n return;\n }\n\n let content = '';\n builder.emit(\n sourceFile,\n (filename, data) => {\n if (/\\.[cm]?js$/.test(filename)) {\n content = data;\n }\n\n if (\n !watchMode &&\n !isTest &&\n /\\.d\\.ts/.test(filename) &&\n !filename.includes('.ngtypecheck.')\n ) {\n // output to library root instead /src\n const declarationPath = resolve(\n config.root,\n config.build.outDir,\n relative(config.root, filename),\n ).replace('/src/', '/');\n\n const declarationFileDir = declarationPath\n .replace(basename(filename), '')\n .replace('/src/', '/');\n\n declarationFiles.push({\n declarationFileDir,\n declarationPath,\n data,\n });\n }\n },\n undefined /* cancellationToken */,\n undefined /* emitOnlyDtsFiles */,\n transformers,\n );\n\n writeFileCallback(id, content, false, undefined, [sourceFile]);\n\n if (angularCompiler) {\n angularCompiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);\n }\n };\n\n if (watchMode) {\n if (ids && ids.length > 0) {\n ids.forEach((id) => writeOutputFile(id));\n } else {\n /**\n * Only block the server from starting up\n * during testing.\n */\n if (isTest) {\n // TypeScript will loop until there are no more affected files in the program\n while (\n (\n builder as ts.EmitAndSemanticDiagnosticsBuilderProgram\n ).emitNextAffectedFile(\n writeFileCallback,\n undefined,\n undefined,\n transformers,\n )\n ) {\n /* empty */\n }\n }\n }\n }\n\n if (!isTest) {\n /**\n * Perf: Output files on demand so the dev server\n * isn't blocked when emitting files.\n */\n outputFile = writeOutputFile;\n }\n }\n}\n\nexport function createFsWatcherCacheInvalidator(\n invalidateFsCaches: () => void,\n invalidateTsconfigCaches: () => void,\n performCompilation: () => Promise<void>,\n): () => Promise<void> {\n return async (): Promise<void> => {\n invalidateFsCaches();\n invalidateTsconfigCaches();\n await performCompilation();\n };\n}\n\n/**\n * Convert Analog/Angular CLI-style file replacements into the flat record\n * expected by `AngularHostOptions.fileReplacements`.\n *\n * Only browser replacements (`{ replace, with }`) are converted. SSR-only\n * replacements (`{ replace, ssr }`) are left for the Vite runtime plugin to\n * handle — they should not be baked into the Angular compilation host because\n * that would apply them to both browser and server builds.\n *\n * Relative paths are resolved against `workspaceRoot` so that the host\n * receives the same absolute paths it would get from the Angular CLI.\n */\nexport function toAngularCompilationFileReplacements(\n replacements: FileReplacement[],\n workspaceRoot: string,\n): Record<string, string> | undefined {\n const mappedReplacements = replacements.flatMap((replacement) => {\n // Skip SSR-only entries — they use `ssr` instead of `with`.\n if (!('with' in replacement)) {\n return [];\n }\n\n return [\n [\n isAbsolute(replacement.replace)\n ? replacement.replace\n : resolve(workspaceRoot, replacement.replace),\n isAbsolute(replacement.with)\n ? replacement.with\n : resolve(workspaceRoot, replacement.with),\n ] as const,\n ];\n });\n\n return mappedReplacements.length\n ? Object.fromEntries(mappedReplacements)\n : undefined;\n}\n\n/**\n * Map Angular's `templateUpdates` (keyed by `encodedFilePath@ClassName`)\n * back to absolute file paths with their associated HMR code and component\n * class name.\n *\n * Angular's private Compilation API emits template update keys in the form\n * `encodeURIComponent(relativePath + '@' + className)`. We decode and resolve\n * them so the caller can look up updates by the same normalized absolute path\n * used elsewhere in the plugin (`outputFiles`, `classNames`, etc.).\n */\nexport function mapTemplateUpdatesToFiles(\n templateUpdates: ReadonlyMap<string, string> | undefined,\n): Map<\n string,\n {\n className: string;\n code: string;\n }\n> {\n const updatesByFile = new Map<string, { className: string; code: string }>();\n\n templateUpdates?.forEach((code, encodedUpdateId) => {\n const [file, className = ''] =\n decodeURIComponent(encodedUpdateId).split('@');\n const resolvedFile = normalizePath(resolve(process.cwd(), file));\n\n updatesByFile.set(resolvedFile, {\n className,\n code,\n });\n });\n\n return updatesByFile;\n}\n\nfunction sendHMRComponentUpdate(server: ViteDevServer, id: string) {\n server.ws.send('angular:component-update', {\n id: encodeURIComponent(id),\n timestamp: Date.now(),\n });\n\n classNames.delete(id);\n}\n\nexport function getFileMetadata(\n program: ts.BuilderProgram,\n angularCompiler?: NgtscProgram['compiler'],\n liveReload?: boolean,\n disableTypeChecking?: boolean,\n) {\n const ts = require('typescript');\n return (\n file: string,\n ): {\n errors?: string[];\n warnings?: (string | ts.DiagnosticMessageChain)[];\n hmrUpdateCode?: string | null;\n hmrEligible?: boolean;\n } => {\n const sourceFile = program.getSourceFile(file);\n if (!sourceFile) {\n return {};\n }\n\n const diagnostics = getDiagnosticsForSourceFile(\n sourceFile,\n !!disableTypeChecking,\n program,\n angularCompiler,\n );\n\n const errors = diagnostics\n .filter((d) => d.category === ts.DiagnosticCategory?.Error)\n .map((d) =>\n typeof d.messageText === 'object'\n ? d.messageText.messageText\n : d.messageText,\n );\n\n const warnings = diagnostics\n .filter((d) => d.category === ts.DiagnosticCategory?.Warning)\n .map((d) => d.messageText);\n\n let hmrUpdateCode: string | null | undefined = undefined;\n\n let hmrEligible = false;\n if (liveReload) {\n for (const node of sourceFile.statements) {\n if (ts.isClassDeclaration(node) && (node as any).name != null) {\n hmrUpdateCode = angularCompiler?.emitHmrUpdateModule(node as any);\n if (hmrUpdateCode) {\n classNames.set(file, (node as any).name.getText());\n hmrEligible = true;\n }\n }\n }\n }\n\n return { errors, warnings, hmrUpdateCode, hmrEligible };\n };\n}\n\nfunction getDiagnosticsForSourceFile(\n sourceFile: ts.SourceFile,\n disableTypeChecking: boolean,\n program: ts.BuilderProgram,\n angularCompiler?: NgtscProgram['compiler'],\n) {\n const syntacticDiagnostics = program.getSyntacticDiagnostics(sourceFile);\n\n if (disableTypeChecking) {\n // Syntax errors are cheap to compute and the app will not run if there are any\n // So always show these types of errors regardless if type checking is disabled\n return syntacticDiagnostics;\n }\n\n const semanticDiagnostics = program.getSemanticDiagnostics(sourceFile);\n const angularDiagnostics = angularCompiler\n ? angularCompiler.getDiagnosticsForFile(sourceFile, 1)\n : [];\n return [\n ...syntacticDiagnostics,\n ...semanticDiagnostics,\n ...angularDiagnostics,\n ];\n}\n\nfunction markModuleSelfAccepting(mod: ModuleNode): ModuleNode {\n // support Vite 6\n if ('_clientModule' in mod) {\n (mod as any)['_clientModule'].isSelfAccepting = true;\n }\n\n return {\n ...mod,\n isSelfAccepting: true,\n } as ModuleNode;\n}\n\nfunction isComponentStyleSheet(id: string): boolean {\n return id.includes('ngcomp=');\n}\n\nfunction getComponentStyleSheetMeta(id: string): {\n componentId: string;\n encapsulation: 'emulated' | 'shadow' | 'none';\n} {\n const params = new URL(id, 'http://localhost').searchParams;\n const encapsulationMapping = {\n '0': 'emulated',\n '2': 'none',\n '3': 'shadow',\n };\n return {\n componentId: params.get('ngcomp')!,\n encapsulation: encapsulationMapping[\n params.get('e') as keyof typeof encapsulationMapping\n ] as 'emulated' | 'shadow' | 'none',\n };\n}\n\n/**\n * Removes leading / and query string from a url path\n * e.g. /foo.scss?direct&ngcomp=ng-c3153525609&e=0 returns foo.scss\n * @param id\n */\nfunction getFilenameFromPath(id: string): string {\n return new URL(id, 'http://localhost').pathname.replace(/^\\//, '');\n}\n\n/**\n * Checks for vitest run from the command line\n * @returns boolean\n */\nexport function isTestWatchMode(args: string[] = process.argv): boolean {\n // vitest --run\n const hasRun = args.find((arg) => arg.includes('--run'));\n if (hasRun) {\n return false;\n }\n\n // vitest --no-run\n const hasNoRun = args.find((arg) => arg.includes('--no-run'));\n if (hasNoRun) {\n return true;\n }\n\n // check for --watch=false or --no-watch\n const hasWatch = args.find((arg) => arg.includes('watch'));\n if (hasWatch && ['false', 'no'].some((neg) => hasWatch.includes(neg))) {\n return false;\n }\n\n // check for --watch false\n const watchIndex = args.findIndex((arg) => arg.includes('watch'));\n const watchArg = args[watchIndex + 1];\n if (watchArg && watchArg === 'false') {\n return false;\n }\n\n return true;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"angular-vite-plugin.js","names":[],"sources":["../../../src/lib/angular-vite-plugin.ts"],"sourcesContent":["import { NgtscProgram } from '@angular/compiler-cli';\nimport { union } from 'es-toolkit';\nimport { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport {\n basename,\n dirname,\n isAbsolute,\n join,\n relative,\n resolve,\n} from 'node:path';\nimport * as vite from 'vite';\n\nimport * as compilerCli from '@angular/compiler-cli';\nimport { createRequire } from 'node:module';\nimport * as ts from 'typescript';\nimport { type createAngularCompilation as createAngularCompilationType } from '@angular/build/private';\n\nimport * as ngCompiler from '@angular/compiler';\nimport { globSync } from 'tinyglobby';\nimport {\n defaultClientConditions,\n ModuleNode,\n normalizePath,\n Plugin,\n preprocessCSS,\n ResolvedConfig,\n ViteDevServer,\n} from 'vite';\nimport { buildOptimizerPlugin } from './angular-build-optimizer-plugin.js';\nimport { jitPlugin } from './angular-jit-plugin.js';\nimport {\n createCompilerPlugin,\n createRolldownCompilerPlugin,\n} from './compiler-plugin.js';\nimport {\n StyleUrlsResolver,\n TemplateUrlsResolver,\n} from './component-resolvers.js';\nimport {\n augmentHostWithCaching,\n augmentHostWithResources,\n augmentProgramWithVersioning,\n mergeTransformers,\n} from './host.js';\nimport type { StylePreprocessor } from './style-preprocessor.js';\n\nimport { angularVitestPlugins } from './angular-vitest-plugin.js';\nimport {\n createAngularCompilation,\n createJitResourceTransformer,\n SourceFileCache,\n angularFullVersion,\n} from './utils/devkit.js';\nimport {\n activateDeferredDebug,\n applyDebugOption,\n debugCompilationApi,\n debugCompiler,\n debugHmr,\n debugStyles,\n debugTailwind,\n type DebugOption,\n} from './utils/debug.js';\nimport { getJsTransformConfigKey, isRolldown } from './utils/rolldown.js';\nimport { type SourceFileCache as SourceFileCacheType } from './utils/source-file-cache.js';\n\nconst require = createRequire(import.meta.url);\n\nimport { pendingTasksPlugin } from './angular-pending-tasks.plugin.js';\nimport { liveReloadPlugin } from './live-reload-plugin.js';\nimport { EmitFileResult } from './models.js';\nimport { nxFolderPlugin } from './nx-folder-plugin.js';\nimport {\n FileReplacement,\n FileReplacementSSR,\n FileReplacementWith,\n replaceFiles,\n} from './plugins/file-replacements.plugin.js';\nimport { routerPlugin } from './router-plugin.js';\nimport { createHash } from 'node:crypto';\n\nexport enum DiagnosticModes {\n None = 0,\n Option = 1 << 0,\n Syntactic = 1 << 1,\n Semantic = 1 << 2,\n All = Option | Syntactic | Semantic,\n}\n\nexport interface PluginOptions {\n tsconfig?: string | (() => string);\n workspaceRoot?: string;\n inlineStylesExtension?: string;\n jit?: boolean;\n advanced?: {\n /**\n * Custom TypeScript transformers that are run before Angular compilation\n */\n tsTransformers?: ts.CustomTransformers;\n };\n supportedBrowsers?: string[];\n transformFilter?: (code: string, id: string) => boolean;\n /**\n * Additional files to include in compilation\n */\n include?: string[];\n additionalContentDirs?: string[];\n liveReload?: boolean;\n disableTypeChecking?: boolean;\n fileReplacements?: FileReplacement[];\n experimental?: {\n useAngularCompilationAPI?: boolean;\n };\n /**\n * Enable debug logging for specific scopes.\n *\n * - `true` → enables all `analog:angular:*` scopes\n * - `string[]` → enables listed namespaces (e.g. `['analog:angular:compiler']`)\n * - `{ scopes?, mode? }` → object form with optional `mode: 'build' | 'dev'`\n * to restrict output to a specific Vite command (omit for both)\n *\n * Also responds to the `DEBUG` env var (Node.js) or `localStorage.debug`\n * (browser), using the `obug` convention.\n */\n debug?: DebugOption;\n /**\n * Optional preprocessor that transforms component CSS before it enters Vite's\n * preprocessCSS pipeline. Runs on every component stylesheet (both external\n * `.component.css` files and inline `styles: [...]` blocks).\n *\n * @param code - Raw CSS content of the component stylesheet\n * @param filename - Resolved file path of the stylesheet (or containing .ts file for inline styles)\n * @returns Transformed CSS string, or the original code if no transformation is needed\n */\n stylePreprocessor?: StylePreprocessor;\n /**\n * First-class Tailwind CSS v4 integration for Angular component styles.\n *\n * Angular's compiler processes component CSS through Vite's `preprocessCSS()`,\n * which runs `@tailwindcss/vite` — but each component stylesheet is processed\n * in isolation without access to the root Tailwind configuration (prefix, @theme,\n * @custom-variant, @plugin definitions). This causes errors like:\n *\n * \"Cannot apply utility class `sa:grid` because the `sa` variant does not exist\"\n *\n * The `tailwindCss` option solves this by auto-injecting a `@reference` directive\n * into every component CSS file that uses Tailwind utilities, pointing it to the\n * root Tailwind stylesheet so `@tailwindcss/vite` can resolve the full configuration.\n *\n * @example Basic usage — reference a root Tailwind CSS file:\n * ```ts\n * import { resolve } from 'node:path';\n *\n * angular({\n * tailwindCss: {\n * rootStylesheet: resolve(__dirname, 'src/styles/tailwind.css'),\n * },\n * })\n * ```\n *\n * @example With prefix detection — only inject for files using specific prefixes:\n * ```ts\n * angular({\n * tailwindCss: {\n * rootStylesheet: resolve(__dirname, 'src/styles/tailwind.css'),\n * // Only inject @reference into files that use these prefixed classes\n * prefixes: ['sa:', 'tw:'],\n * },\n * })\n * ```\n *\n * @example AnalogJS platform — passed through the `vite` option:\n * ```ts\n * analog({\n * vite: {\n * tailwindCss: {\n * rootStylesheet: resolve(__dirname, '../../../libs/meritos/tailwind.config.css'),\n * },\n * },\n * })\n * ```\n */\n tailwindCss?: {\n /**\n * Absolute path to the root Tailwind CSS file that contains `@import \"tailwindcss\"`,\n * `@theme`, `@custom-variant`, and `@plugin` definitions.\n *\n * A `@reference` directive pointing to this file will be auto-injected into\n * component CSS files that use Tailwind utilities.\n */\n rootStylesheet: string;\n /**\n * Optional list of class prefixes to detect (e.g. `['sa:', 'tw:']`).\n * When provided, `@reference` is only injected into component CSS files that\n * contain at least one of these prefixes. When omitted, `@reference` is injected\n * into all component CSS files that contain `@apply` or `@` directives.\n *\n * @default undefined — inject into all component CSS files with `@apply`\n */\n prefixes?: string[];\n };\n}\n\n/**\n * TypeScript file extension regex\n * Match .(c or m)ts, .ts extensions with an optional ? for query params\n * Ignore .tsx extensions\n */\nconst TS_EXT_REGEX = /\\.[cm]?(ts)[^x]?\\??/;\nconst classNames = new Map();\n\ninterface DeclarationFile {\n declarationFileDir: string;\n declarationPath: string;\n data: string;\n}\n\n/**\n * Builds a resolved stylePreprocessor function from plugin options.\n * If `tailwindCss` is provided, creates an auto-reference injector.\n * If `stylePreprocessor` is also provided, chains them (tailwind first, then user).\n */\nfunction buildStylePreprocessor(\n options?: PluginOptions,\n): ((code: string, filename: string) => string) | undefined {\n const userPreprocessor = options?.stylePreprocessor;\n const tw = options?.tailwindCss;\n\n if (!tw && !userPreprocessor) {\n return undefined;\n }\n\n // Build the Tailwind @reference injector\n let tailwindPreprocessor:\n | ((code: string, filename: string) => string)\n | undefined;\n\n if (tw) {\n const rootStylesheet = tw.rootStylesheet;\n const prefixes = tw.prefixes;\n debugTailwind('configured', { rootStylesheet, prefixes });\n\n tailwindPreprocessor = (code: string, filename: string): string => {\n // Skip if already has @reference or is a root Tailwind file\n if (\n code.includes('@reference') ||\n code.includes('@import \"tailwindcss\"') ||\n code.includes(\"@import 'tailwindcss'\")\n ) {\n debugTailwind('skip (already has @reference or is root)', { filename });\n return code;\n }\n\n // Check if the file uses Tailwind utilities\n const needsReference = prefixes\n ? prefixes.some((prefix) => code.includes(prefix))\n : code.includes('@apply');\n\n if (!needsReference) {\n debugTailwind('skip (no Tailwind usage detected)', { filename });\n return code;\n }\n\n debugTailwind('injected @reference', { filename });\n const refPath = relative(dirname(filename), rootStylesheet);\n return `@reference \"${refPath}\";\\n${code}`;\n };\n }\n\n // Chain: tailwind preprocessor first, then user preprocessor\n if (tailwindPreprocessor && userPreprocessor) {\n debugTailwind('chained with user stylePreprocessor');\n return (code: string, filename: string) => {\n const intermediate = tailwindPreprocessor!(code, filename);\n return userPreprocessor(intermediate, filename);\n };\n }\n\n return tailwindPreprocessor ?? userPreprocessor;\n}\n\nexport function angular(options?: PluginOptions): Plugin[] {\n applyDebugOption(options?.debug, options?.workspaceRoot);\n\n /**\n * Normalize plugin options so defaults\n * are used for values not provided.\n */\n const pluginOptions = {\n tsconfigGetter: createTsConfigGetter(options?.tsconfig),\n workspaceRoot: options?.workspaceRoot ?? process.cwd(),\n inlineStylesExtension: options?.inlineStylesExtension ?? 'css',\n advanced: {\n tsTransformers: {\n before: options?.advanced?.tsTransformers?.before ?? [],\n after: options?.advanced?.tsTransformers?.after ?? [],\n afterDeclarations:\n options?.advanced?.tsTransformers?.afterDeclarations ?? [],\n },\n },\n supportedBrowsers: options?.supportedBrowsers ?? ['safari 15'],\n jit: options?.jit,\n include: options?.include ?? [],\n additionalContentDirs: options?.additionalContentDirs ?? [],\n liveReload: options?.liveReload ?? false,\n disableTypeChecking: options?.disableTypeChecking ?? true,\n fileReplacements: options?.fileReplacements ?? [],\n useAngularCompilationAPI:\n options?.experimental?.useAngularCompilationAPI ?? false,\n stylePreprocessor: buildStylePreprocessor(options),\n };\n\n let resolvedConfig: ResolvedConfig;\n // Store config context needed for getTsConfigPath resolution\n let tsConfigResolutionContext: {\n root: string;\n isProd: boolean;\n isLib: boolean;\n } | null = null;\n\n const ts = require('typescript');\n let builder: ts.BuilderProgram | ts.EmitAndSemanticDiagnosticsBuilderProgram;\n let nextProgram: NgtscProgram | undefined;\n // Caches (always rebuild Angular program per user request)\n const tsconfigOptionsCache = new Map<\n string,\n { options: ts.CompilerOptions; rootNames: string[] }\n >();\n let cachedHost: ts.CompilerHost | undefined;\n let cachedHostKey: string | undefined;\n let includeCache: string[] = [];\n function invalidateFsCaches() {\n includeCache = [];\n }\n function invalidateTsconfigCaches() {\n // `readConfiguration` caches the root file list, so hot-added pages can be\n // missing from Angular's compilation program until we clear this state.\n tsconfigOptionsCache.clear();\n cachedHost = undefined;\n cachedHostKey = undefined;\n }\n let watchMode = false;\n let testWatchMode = isTestWatchMode();\n let inlineComponentStyles: Map<string, string> | undefined;\n let externalComponentStyles: Map<string, string> | undefined;\n const sourceFileCache: SourceFileCacheType = new SourceFileCache();\n const isTest = process.env['NODE_ENV'] === 'test' || !!process.env['VITEST'];\n const isVitestVscode = !!process.env['VITEST_VSCODE'];\n const isStackBlitz = !!process.versions['webcontainer'];\n const isAstroIntegration = process.env['ANALOG_ASTRO'] === 'true';\n\n const jit =\n typeof pluginOptions?.jit !== 'undefined' ? pluginOptions.jit : isTest;\n let viteServer: ViteDevServer | undefined;\n\n const styleUrlsResolver = new StyleUrlsResolver();\n const templateUrlsResolver = new TemplateUrlsResolver();\n let outputFile: ((file: string) => void) | undefined;\n const outputFiles = new Map<string, EmitFileResult>();\n const fileEmitter = (file: string) => {\n outputFile?.(file);\n return outputFiles.get(normalizePath(file));\n };\n let initialCompilation = false;\n const declarationFiles: DeclarationFile[] = [];\n const fileTransformMap = new Map<string, string>();\n let styleTransform: (\n code: string,\n filename: string,\n ) => Promise<vite.PreprocessCSSResult>;\n let pendingCompilation: Promise<void> | null;\n let compilationLock = Promise.resolve();\n // Persistent Angular Compilation API instance. Kept alive across rebuilds so\n // Angular can diff previous state and emit `templateUpdates` for HMR.\n // Previously the compilation was recreated on every pass, which meant Angular\n // never had prior state and could never produce HMR payloads.\n let angularCompilation:\n | Awaited<ReturnType<typeof createAngularCompilationType>>\n | undefined;\n\n function angularPlugin(): Plugin {\n let isProd = false;\n\n if (angularFullVersion < 190000 || isTest) {\n pluginOptions.liveReload = false;\n debugHmr('liveReload disabled', {\n angularVersion: angularFullVersion,\n isTest,\n });\n }\n\n // liveReload and fileReplacements guards were previously here and forced\n // both options off when useAngularCompilationAPI was enabled. Those guards\n // have been removed because:\n // - liveReload: the persistent compilation instance (above) now gives\n // Angular the prior state it needs to emit `templateUpdates` for HMR\n // - fileReplacements: Angular's AngularHostOptions already accepts a\n // `fileReplacements` record — we now convert and pass it through in\n // `performAngularCompilation` via `toAngularCompilationFileReplacements`\n if (pluginOptions.useAngularCompilationAPI) {\n if (angularFullVersion < 200100) {\n pluginOptions.useAngularCompilationAPI = false;\n debugCompilationApi(\n 'disabled: Angular version %s < 20.1',\n angularFullVersion,\n );\n console.warn(\n '[@analogjs/vite-plugin-angular]: The Angular Compilation API is only available with Angular v20.1 and later',\n );\n } else {\n debugCompilationApi('enabled (Angular %s)', angularFullVersion);\n }\n }\n\n return {\n name: '@analogjs/vite-plugin-angular',\n async config(config, { command }) {\n activateDeferredDebug(command);\n watchMode = command === 'serve';\n isProd =\n config.mode === 'production' ||\n process.env['NODE_ENV'] === 'production';\n\n // Store the config context for later resolution in configResolved\n tsConfigResolutionContext = {\n root: config.root || '.',\n isProd,\n isLib: !!config?.build?.lib,\n };\n\n // Do a preliminary resolution for esbuild plugin (before configResolved)\n const preliminaryTsConfigPath = resolveTsConfigPath();\n\n const esbuild = pluginOptions.useAngularCompilationAPI\n ? undefined\n : (config.esbuild ?? false);\n const oxc = pluginOptions.useAngularCompilationAPI\n ? undefined\n : (config.oxc ?? false);\n if (pluginOptions.useAngularCompilationAPI) {\n debugCompilationApi(\n 'esbuild/oxc disabled, Angular handles transforms',\n );\n }\n\n const defineOptions = {\n ngJitMode: 'false',\n ngI18nClosureMode: 'false',\n ...(watchMode ? {} : { ngDevMode: 'false' }),\n };\n const useRolldown = isRolldown();\n const jsTransformConfigKey = getJsTransformConfigKey();\n const jsTransformConfigValue =\n jsTransformConfigKey === 'oxc' ? oxc : esbuild;\n\n const rolldownOptions: vite.DepOptimizationOptions['rolldownOptions'] =\n {\n plugins: [\n createRolldownCompilerPlugin(\n {\n tsconfig: preliminaryTsConfigPath,\n sourcemap: !isProd,\n advancedOptimizations: isProd,\n jit,\n incremental: watchMode,\n },\n // Astro manages the transformer lifecycle externally.\n !isAstroIntegration,\n ),\n ],\n };\n\n const esbuildOptions: vite.DepOptimizationOptions['esbuildOptions'] = {\n plugins: [\n createCompilerPlugin(\n {\n tsconfig: preliminaryTsConfigPath,\n sourcemap: !isProd,\n advancedOptimizations: isProd,\n jit,\n incremental: watchMode,\n },\n isTest,\n !isAstroIntegration,\n ),\n ],\n define: defineOptions,\n };\n\n return {\n [jsTransformConfigKey]: jsTransformConfigValue,\n optimizeDeps: {\n include: ['rxjs/operators', 'rxjs'],\n exclude: ['@angular/platform-server'],\n ...(useRolldown ? { rolldownOptions } : { esbuildOptions }),\n },\n resolve: {\n conditions: [\n 'style',\n ...(config.resolve?.conditions || defaultClientConditions),\n ],\n },\n };\n },\n configResolved(config) {\n resolvedConfig = config;\n\n if (pluginOptions.useAngularCompilationAPI) {\n externalComponentStyles = new Map();\n inlineComponentStyles = new Map();\n debugStyles('style maps initialized (Angular Compilation API)');\n }\n\n if (!jit) {\n styleTransform = (code: string, filename: string) =>\n preprocessCSS(code, filename, config);\n }\n\n if (isTest) {\n // set test watch mode\n // - vite override from vitest-angular\n // - @nx/vite executor set server.watch explicitly to undefined (watch)/null (watch=false)\n // - vite config for test.watch variable\n // - vitest watch mode detected from the command line\n testWatchMode =\n !(config.server.watch === null) ||\n (config as any).test?.watch === true ||\n testWatchMode;\n }\n },\n configureServer(server) {\n viteServer = server;\n // Add/unlink changes the TypeScript program shape, not just file\n // contents, so we need to invalidate both include discovery and the\n // cached tsconfig root names before recompiling.\n const invalidateCompilationOnFsChange = createFsWatcherCacheInvalidator(\n invalidateFsCaches,\n invalidateTsconfigCaches,\n () => performCompilation(resolvedConfig),\n );\n server.watcher.on('add', invalidateCompilationOnFsChange);\n server.watcher.on('unlink', invalidateCompilationOnFsChange);\n server.watcher.on('change', (file) => {\n if (file.includes('tsconfig')) {\n invalidateTsconfigCaches();\n }\n });\n },\n async buildStart() {\n // Defer the first compilation in test mode\n if (!isVitestVscode) {\n await performCompilation(resolvedConfig);\n pendingCompilation = null;\n\n initialCompilation = true;\n }\n },\n async handleHotUpdate(ctx) {\n if (TS_EXT_REGEX.test(ctx.file)) {\n const [fileId] = ctx.file.split('?');\n debugHmr('TS file changed', { file: ctx.file, fileId });\n\n pendingCompilation = performCompilation(resolvedConfig, [fileId]);\n\n let result;\n\n if (pluginOptions.liveReload) {\n await pendingCompilation;\n pendingCompilation = null;\n result = fileEmitter(fileId);\n debugHmr('TS file emitted', {\n fileId,\n hmrEligible: !!result?.hmrEligible,\n hasClassName: !!classNames.get(fileId),\n });\n }\n\n if (\n pluginOptions.liveReload &&\n result?.hmrEligible &&\n classNames.get(fileId)\n ) {\n const relativeFileId = `${normalizePath(\n relative(process.cwd(), fileId),\n )}@${classNames.get(fileId)}`;\n\n debugHmr('sending component update', { relativeFileId });\n sendHMRComponentUpdate(ctx.server, relativeFileId);\n\n return ctx.modules.map((mod) => {\n if (mod.id === ctx.file) {\n return markModuleSelfAccepting(mod);\n }\n\n return mod;\n });\n }\n }\n\n if (/\\.(html|htm|css|less|sass|scss)$/.test(ctx.file)) {\n debugHmr('resource file changed', { file: ctx.file });\n fileTransformMap.delete(ctx.file.split('?')[0]);\n /**\n * Check to see if this was a direct request\n * for an external resource (styles, html).\n */\n const isDirect = ctx.modules.find(\n (mod) => ctx.file === mod.file && mod.id?.includes('?direct'),\n );\n const isInline = ctx.modules.find(\n (mod) => ctx.file === mod.file && mod.id?.includes('?inline'),\n );\n\n if (isDirect || isInline) {\n if (pluginOptions.liveReload && isDirect?.id && isDirect.file) {\n const isComponentStyle =\n isDirect.type === 'css' && isComponentStyleSheet(isDirect.id);\n if (isComponentStyle) {\n const { encapsulation } = getComponentStyleSheetMeta(\n isDirect.id,\n );\n debugStyles('HMR: component stylesheet changed', {\n file: isDirect.file,\n encapsulation,\n });\n\n // Track if the component uses ShadowDOM encapsulation\n // Shadow DOM components currently require a full reload.\n // Vite's CSS hot replacement does not support shadow root searching.\n if (encapsulation !== 'shadow') {\n ctx.server.ws.send({\n type: 'update',\n updates: [\n {\n type: 'css-update',\n timestamp: Date.now(),\n path: isDirect.url,\n acceptedPath: isDirect.file,\n },\n ],\n });\n\n return ctx.modules\n .filter((mod) => {\n // Component stylesheets will have 2 modules (*.component.scss and *.component.scss?direct&ngcomp=xyz&e=x)\n // We remove the module with the query params to prevent vite double logging the stylesheet name \"hmr update *.component.scss, *.component.scss?direct&ngcomp=xyz&e=x\"\n return mod.file !== ctx.file || mod.id !== isDirect.id;\n })\n .map((mod) => {\n if (mod.file === ctx.file) {\n return markModuleSelfAccepting(mod);\n }\n return mod;\n }) as ModuleNode[];\n }\n }\n }\n return ctx.modules;\n }\n\n const mods: ModuleNode[] = [];\n const updates: string[] = [];\n ctx.modules.forEach((mod) => {\n mod.importers.forEach((imp) => {\n ctx.server.moduleGraph.invalidateModule(imp);\n\n if (pluginOptions.liveReload && classNames.get(imp.id)) {\n updates.push(imp.id as string);\n } else {\n mods.push(imp);\n }\n });\n });\n\n pendingCompilation = performCompilation(resolvedConfig, [\n ...mods.map((mod) => mod.id as string),\n ...updates,\n ]);\n\n if (updates.length > 0) {\n await pendingCompilation;\n pendingCompilation = null;\n\n debugHmr('resource importer component updates', {\n file: ctx.file,\n updateCount: updates.length,\n });\n updates.forEach((updateId) => {\n const impRelativeFileId = `${normalizePath(\n relative(process.cwd(), updateId),\n )}@${classNames.get(updateId)}`;\n\n sendHMRComponentUpdate(ctx.server, impRelativeFileId);\n });\n\n return ctx.modules.map((mod) => {\n if (mod.id === ctx.file) {\n return markModuleSelfAccepting(mod);\n }\n\n return mod;\n });\n }\n\n return mods;\n }\n\n // clear HMR updates with a full reload\n debugHmr('full reload — unrecognized file type', { file: ctx.file });\n classNames.clear();\n return ctx.modules;\n },\n resolveId(id, importer) {\n if (jit && id.startsWith('angular:jit:')) {\n const path = id.split(';')[1];\n return `${normalizePath(\n resolve(dirname(importer as string), path),\n )}?${id.includes(':style') ? 'inline' : 'raw'}`;\n }\n\n // Map angular external styleUrls to the source file\n if (isComponentStyleSheet(id)) {\n const filename = getFilenameFromPath(id);\n const componentStyles = externalComponentStyles?.get(filename);\n if (componentStyles) {\n debugStyles('resolveId: mapped external stylesheet', {\n filename,\n resolvedPath: componentStyles,\n });\n return componentStyles + new URL(id, 'http://localhost').search;\n }\n }\n\n return undefined;\n },\n async load(id) {\n // Map angular inline styles to the source text\n if (isComponentStyleSheet(id)) {\n const filename = getFilenameFromPath(id);\n const componentStyles = inlineComponentStyles?.get(filename);\n if (componentStyles) {\n debugStyles('load: served inline component stylesheet', {\n filename,\n length: componentStyles.length,\n });\n return componentStyles;\n }\n }\n\n return;\n },\n transform: {\n filter: {\n id: {\n include: [TS_EXT_REGEX],\n exclude: [/node_modules/, 'type=script', '@ng/component'],\n },\n },\n async handler(code, id) {\n /**\n * Check for options.transformFilter\n */\n if (\n options?.transformFilter &&\n !(options?.transformFilter(code, id) ?? true)\n ) {\n return;\n }\n\n if (pluginOptions.useAngularCompilationAPI) {\n const isAngular =\n /(Component|Directive|Pipe|Injectable|NgModule)\\(/.test(code);\n\n if (!isAngular) {\n debugCompilationApi('transform skip (non-Angular file)', { id });\n return;\n }\n }\n\n /**\n * Skip transforming content files\n */\n if (id.includes('?') && id.includes('analog-content-')) {\n return;\n }\n\n /**\n * Encapsulate component stylesheets that use emulated encapsulation\n */\n if (pluginOptions.liveReload && isComponentStyleSheet(id)) {\n const { encapsulation, componentId } =\n getComponentStyleSheetMeta(id);\n if (encapsulation === 'emulated' && componentId) {\n debugStyles('applying emulated view encapsulation', {\n stylesheet: id.split('?')[0],\n componentId,\n });\n const encapsulated = ngCompiler.encapsulateStyle(\n code,\n componentId,\n );\n return {\n code: encapsulated,\n map: null,\n };\n }\n }\n\n if (id.includes('.ts?')) {\n // Strip the query string off the ID\n // in case of a dynamically loaded file\n id = id.replace(/\\?(.*)/, '');\n }\n\n fileTransformMap.set(id, code);\n\n /**\n * Re-analyze on each transform\n * for test(Vitest)\n */\n if (isTest) {\n if (isVitestVscode && !initialCompilation) {\n // Do full initial compilation\n pendingCompilation = performCompilation(resolvedConfig);\n initialCompilation = true;\n }\n\n const tsMod = viteServer?.moduleGraph.getModuleById(id);\n if (tsMod) {\n const invalidated = tsMod.lastInvalidationTimestamp;\n\n if (testWatchMode && invalidated) {\n pendingCompilation = performCompilation(resolvedConfig, [id]);\n }\n }\n }\n\n const hasComponent = code.includes('@Component');\n debugCompiler('transform', {\n id,\n codeLength: code.length,\n hasComponent,\n });\n const templateUrls = hasComponent\n ? templateUrlsResolver.resolve(code, id)\n : [];\n const styleUrls = hasComponent\n ? styleUrlsResolver.resolve(code, id)\n : [];\n\n if (hasComponent && watchMode) {\n for (const urlSet of [...templateUrls, ...styleUrls]) {\n // `urlSet` is a string where a relative path is joined with an\n // absolute path using the `|` symbol.\n // For example: `./app.component.html|/home/projects/analog/src/app/app.component.html`.\n const [, absoluteFileUrl] = urlSet.split('|');\n this.addWatchFile(absoluteFileUrl);\n }\n }\n\n if (pendingCompilation) {\n await pendingCompilation;\n pendingCompilation = null;\n }\n\n const typescriptResult = fileEmitter(id);\n\n if (\n typescriptResult?.warnings &&\n typescriptResult?.warnings.length > 0\n ) {\n this.warn(`${typescriptResult.warnings.join('\\n')}`);\n }\n\n if (typescriptResult?.errors && typescriptResult?.errors.length > 0) {\n this.error(`${typescriptResult.errors.join('\\n')}`);\n }\n\n // return fileEmitter\n let data = typescriptResult?.content ?? '';\n\n if (jit && data.includes('angular:jit:')) {\n data = data.replace(\n /angular:jit:style:inline;/g,\n 'virtual:angular:jit:style:inline;',\n );\n\n templateUrls.forEach((templateUrlSet) => {\n const [templateFile, resolvedTemplateUrl] =\n templateUrlSet.split('|');\n data = data.replace(\n `angular:jit:template:file;${templateFile}`,\n `${resolvedTemplateUrl}?raw`,\n );\n });\n\n styleUrls.forEach((styleUrlSet) => {\n const [styleFile, resolvedStyleUrl] = styleUrlSet.split('|');\n data = data.replace(\n `angular:jit:style:file;${styleFile}`,\n `${resolvedStyleUrl}?inline`,\n );\n });\n }\n\n return {\n code: data,\n map: null,\n };\n },\n },\n closeBundle() {\n declarationFiles.forEach(\n ({ declarationFileDir, declarationPath, data }) => {\n mkdirSync(declarationFileDir, { recursive: true });\n writeFileSync(declarationPath, data, 'utf-8');\n },\n );\n // Tear down the persistent compilation instance at end of build so it\n // does not leak memory across unrelated Vite invocations.\n angularCompilation?.close?.();\n angularCompilation = undefined;\n },\n };\n }\n\n return [\n replaceFiles(pluginOptions.fileReplacements, pluginOptions.workspaceRoot),\n angularPlugin(),\n pluginOptions.liveReload && liveReloadPlugin({ classNames, fileEmitter }),\n ...(isTest && !isStackBlitz ? angularVitestPlugins() : []),\n (jit &&\n jitPlugin({\n inlineStylesExtension: pluginOptions.inlineStylesExtension,\n })) as Plugin,\n buildOptimizerPlugin({\n supportedBrowsers: pluginOptions.supportedBrowsers,\n jit,\n }),\n routerPlugin(),\n angularFullVersion < 190004 && pendingTasksPlugin(),\n nxFolderPlugin(),\n ].filter(Boolean) as Plugin[];\n\n function findIncludes() {\n const workspaceRoot = normalizePath(resolve(pluginOptions.workspaceRoot));\n\n // Map include patterns to absolute workspace paths\n const globs = [\n ...pluginOptions.include.map((glob) => `${workspaceRoot}${glob}`),\n ];\n\n // Discover TypeScript files using tinyglobby\n return globSync(globs, {\n dot: true,\n absolute: true,\n });\n }\n\n function createTsConfigGetter(tsconfigOrGetter?: string | (() => string)) {\n if (typeof tsconfigOrGetter === 'function') {\n return tsconfigOrGetter;\n }\n\n return () => tsconfigOrGetter || '';\n }\n\n function getTsConfigPath(\n root: string,\n tsconfig: string,\n isProd: boolean,\n isTest: boolean,\n isLib: boolean,\n ) {\n if (tsconfig && isAbsolute(tsconfig)) {\n if (!existsSync(tsconfig)) {\n console.error(\n `[@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.`,\n );\n }\n\n return tsconfig;\n }\n\n let tsconfigFilePath = './tsconfig.app.json';\n\n if (isLib) {\n tsconfigFilePath = isProd\n ? './tsconfig.lib.prod.json'\n : './tsconfig.lib.json';\n }\n\n if (isTest) {\n tsconfigFilePath = './tsconfig.spec.json';\n }\n\n if (tsconfig) {\n tsconfigFilePath = tsconfig;\n }\n\n const resolvedPath = resolve(root, tsconfigFilePath);\n\n if (!existsSync(resolvedPath)) {\n console.error(\n `[@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.`,\n );\n }\n\n return resolvedPath;\n }\n\n function resolveTsConfigPath() {\n const tsconfigValue = pluginOptions.tsconfigGetter();\n\n return getTsConfigPath(\n tsConfigResolutionContext!.root,\n tsconfigValue,\n tsConfigResolutionContext!.isProd,\n isTest,\n tsConfigResolutionContext!.isLib,\n );\n }\n\n /**\n * Perform compilation using Angular's private Compilation API.\n *\n * Key differences from the standard `performCompilation` path:\n * 1. The compilation instance is reused across rebuilds (nullish-coalescing\n * assignment below) so Angular retains prior state and can diff it to\n * produce `templateUpdates` for HMR.\n * 2. `ids` (modified files) are forwarded to both the source-file cache and\n * `angularCompilation.update()` so that incremental re-analysis is\n * scoped to what actually changed.\n * 3. `fileReplacements` are converted and passed into Angular's host via\n * `toAngularCompilationFileReplacements`.\n * 4. `templateUpdates` from the compilation result are mapped back to\n * file-level HMR metadata (`hmrUpdateCode`, `hmrEligible`, `classNames`).\n */\n async function performAngularCompilation(\n config: ResolvedConfig,\n ids?: string[],\n ) {\n // Reuse the existing instance so Angular can diff against prior state.\n angularCompilation ??= await (\n createAngularCompilation as typeof createAngularCompilationType\n )(!!pluginOptions.jit, false);\n const modifiedFiles = ids?.length\n ? new Set(ids.map((file) => normalizePath(file)))\n : undefined;\n if (modifiedFiles?.size) {\n sourceFileCache.invalidate(modifiedFiles);\n }\n // Notify Angular of modified files before re-initialization so it can\n // scope its incremental analysis.\n if (modifiedFiles?.size && angularCompilation.update) {\n debugCompilationApi('incremental update', {\n files: [...modifiedFiles],\n });\n await angularCompilation.update(modifiedFiles);\n }\n\n const resolvedTsConfigPath = resolveTsConfigPath();\n const compilationResult = await angularCompilation.initialize(\n resolvedTsConfigPath,\n {\n // Convert Analog's browser-style `{ replace, with }` entries into the\n // `Record<string, string>` shape that Angular's AngularHostOptions\n // expects. SSR-only replacements (`{ replace, ssr }`) are intentionally\n // excluded — they stay on the Vite runtime side.\n fileReplacements: toAngularCompilationFileReplacements(\n pluginOptions.fileReplacements,\n pluginOptions.workspaceRoot,\n ),\n modifiedFiles,\n async transformStylesheet(\n data,\n containingFile,\n resourceFile,\n order,\n className,\n ) {\n const filename =\n resourceFile ??\n containingFile.replace(\n '.ts',\n `.${pluginOptions.inlineStylesExtension}`,\n );\n\n // Apply any user-defined stylesheet preprocessing before Vite transforms it.\n const preprocessedData = pluginOptions.stylePreprocessor\n ? (pluginOptions.stylePreprocessor(data, filename) ?? data)\n : data;\n\n if (pluginOptions.liveReload && watchMode) {\n // Store the preprocessed (but not yet CSS-transformed) data so that\n // Vite's serve-time pipeline handles PostCSS / Tailwind processing\n // exactly once when the load hook returns this CSS. Running\n // preprocessCSS() here would strip directives like @reference before\n // the CSS re-enters the transform pipeline, causing plugins such as\n // @tailwindcss/vite to fail on the second pass.\n // Guard must match the externalRuntimeStyles condition (line ~927)\n // because the Angular compiler only emits external style references\n // when externalRuntimeStyles is enabled.\n const id = createHash('sha256')\n .update(containingFile)\n .update(className as string)\n .update(String(order))\n .update(preprocessedData)\n .digest('hex');\n const stylesheetId = id + '.' + pluginOptions.inlineStylesExtension;\n inlineComponentStyles!.set(stylesheetId, preprocessedData);\n\n debugStyles('stylesheet deferred to Vite pipeline (liveReload)', {\n stylesheetId,\n resourceFile: resourceFile ?? '(inline)',\n });\n\n return stylesheetId;\n }\n\n // Non-liveReload: the CSS is returned directly to the Angular\n // compiler and never re-enters Vite's pipeline, so we must run\n // preprocessCSS() eagerly here.\n debugStyles(\n 'stylesheet processed inline via preprocessCSS (no liveReload)',\n {\n filename,\n resourceFile: resourceFile ?? '(inline)',\n dataLength: preprocessedData.length,\n },\n );\n let stylesheetResult;\n\n try {\n stylesheetResult = await preprocessCSS(\n preprocessedData,\n `${filename}?direct`,\n resolvedConfig,\n );\n } catch (e) {\n console.error(`${e}`);\n }\n\n return stylesheetResult?.code || '';\n },\n processWebWorker(workerFile, containingFile) {\n return '';\n },\n },\n (tsCompilerOptions) => {\n if (pluginOptions.liveReload && watchMode) {\n tsCompilerOptions['_enableHmr'] = true;\n tsCompilerOptions['externalRuntimeStyles'] = true;\n // Workaround for https://github.com/angular/angular/issues/59310\n // Force extra instructions to be generated for HMR w/defer\n tsCompilerOptions['supportTestBed'] = true;\n }\n\n debugCompiler('tsCompilerOptions (compilation API)', {\n liveReload: pluginOptions.liveReload,\n watchMode,\n externalRuntimeStyles: !!tsCompilerOptions['externalRuntimeStyles'],\n hmr: !!tsCompilerOptions['_enableHmr'],\n });\n\n if (tsCompilerOptions.compilationMode === 'partial') {\n // These options can't be false in partial mode\n tsCompilerOptions['supportTestBed'] = true;\n tsCompilerOptions['supportJitMode'] = true;\n }\n\n if (!isTest && config.build?.lib) {\n tsCompilerOptions['declaration'] = true;\n tsCompilerOptions['declarationMap'] = watchMode;\n tsCompilerOptions['inlineSources'] = true;\n }\n\n if (isTest) {\n // Allow `TestBed.overrideXXX()` APIs.\n tsCompilerOptions['supportTestBed'] = true;\n }\n\n return tsCompilerOptions;\n },\n );\n\n // -------------------------------------------------------------------\n // Register external stylesheets and bridge the hash mismatch\n //\n // Two independent hash maps coexist for component CSS:\n //\n // inlineComponentStyles — keyed by Analog's hash (computed in\n // transformStylesheet from containingFile + className + order +\n // preprocessedData). The preprocessedData includes `@reference`\n // injected by buildStylePreprocessor. This map holds the CSS\n // that Vite should serve (with Tailwind context).\n //\n // externalComponentStyles — keyed by Angular's hash (computed by\n // the Angular compiler internally, returned in\n // compilationResult.externalStylesheets). Maps to the raw file\n // path. This is what Angular emits in the browser-side URLs.\n //\n // Problem: the browser requests CSS using Angular's hash, but the\n // preprocessed CSS lives in inlineComponentStyles under Analog's\n // hash. resolveId checks inlineComponentStyles first (line ~785),\n // misses (wrong key), falls through to externalComponentStyles,\n // and resolves to the RAW file — which has no @reference. Then\n // @tailwindcss/vite fails with:\n //\n // \"Cannot apply utility class 'sa:grid' because the 'sa'\n // variant does not exist\"\n //\n // Fix: after compilation, copy the preprocessed CSS into\n // inlineComponentStyles under Angular's hash. resolveId then finds\n // it on the first lookup, the load hook serves the @reference-\n // injected version, and @tailwindcss/vite compiles it correctly.\n //\n // The lookup uses basename(key) and key.replace(/^\\//, '') because\n // transformStylesheet stores under both of those keys (line ~1332).\n // -------------------------------------------------------------------\n // -------------------------------------------------------------------\n // Register external stylesheets and preprocess for Tailwind\n //\n // Angular's Compilation API with externalRuntimeStyles does NOT call\n // transformStylesheet for external styleUrls — it only reports them\n // in compilationResult.externalStylesheets. Only inline styles (from\n // `styles: [...]`) go through transformStylesheet.\n //\n // This means external component CSS files never get the @reference\n // directive injected by buildStylePreprocessor. The resolveId hook\n // maps Angular's hash to the raw file path, the load hook reads the\n // raw file from disk, and @tailwindcss/vite processes CSS without\n // @reference — causing \"sa: variant does not exist\" errors.\n //\n // Fix: for each external stylesheet, read the file, run the style\n // preprocessor (which injects @reference), and store the result in\n // inlineComponentStyles under Angular's hash. The resolveId hook\n // then finds it on the first lookup, the load hook serves the\n // preprocessed version, and @tailwindcss/vite compiles correctly.\n // -------------------------------------------------------------------\n compilationResult.externalStylesheets?.forEach((value, key) => {\n externalComponentStyles?.set(`${value}.css`, key);\n debugStyles('external stylesheet registered for resolveId mapping', {\n filename: `${value}.css`,\n resolvedPath: key,\n });\n });\n\n const diagnostics = await angularCompilation.diagnoseFiles(\n pluginOptions.disableTypeChecking\n ? DiagnosticModes.All & ~DiagnosticModes.Semantic\n : DiagnosticModes.All,\n );\n\n const errors = diagnostics.errors?.length ? diagnostics.errors : [];\n const warnings = diagnostics.warnings?.length ? diagnostics.warnings : [];\n // Angular encodes template updates as `encodedFilePath@ClassName` keys.\n // `mapTemplateUpdatesToFiles` decodes them back to absolute file paths so\n // we can attach HMR metadata to the correct `EmitFileResult` below.\n const templateUpdates = mapTemplateUpdatesToFiles(\n compilationResult.templateUpdates,\n );\n if (templateUpdates.size > 0) {\n debugHmr('compilation API template updates', {\n count: templateUpdates.size,\n files: [...templateUpdates.keys()],\n });\n }\n\n for (const file of await angularCompilation.emitAffectedFiles()) {\n const normalizedFilename = normalizePath(file.filename);\n const templateUpdate = templateUpdates.get(normalizedFilename);\n\n if (templateUpdate) {\n classNames.set(normalizedFilename, templateUpdate.className);\n }\n\n // Surface Angular's HMR payloads into Analog's existing live-reload\n // flow via the `hmrUpdateCode` / `hmrEligible` fields.\n outputFiles.set(normalizedFilename, {\n content: file.contents,\n dependencies: [],\n errors: errors.map((error: { text?: string }) => error.text || ''),\n warnings: warnings.map(\n (warning: { text?: string }) => warning.text || '',\n ),\n hmrUpdateCode: templateUpdate?.code,\n hmrEligible: !!templateUpdate?.code,\n });\n }\n }\n\n async function performCompilation(config: ResolvedConfig, ids?: string[]) {\n let resolve: (() => unknown) | undefined;\n const previousLock = compilationLock;\n compilationLock = new Promise<void>((r) => {\n resolve = r;\n });\n try {\n await previousLock;\n await _doPerformCompilation(config, ids);\n } finally {\n resolve!();\n }\n }\n\n /**\n * This method share mutable state and performs the actual compilation work.\n * It should not be called concurrently. Use `performCompilation` which wraps this method in a lock to ensure only one compilation runs at a time.\n */\n async function _doPerformCompilation(config: ResolvedConfig, ids?: string[]) {\n // Forward `ids` (modified files) so the Compilation API path can do\n // incremental re-analysis instead of a full recompile on every change.\n if (pluginOptions.useAngularCompilationAPI) {\n debugCompilationApi('using compilation API path', {\n modifiedFiles: ids?.length ?? 0,\n });\n await performAngularCompilation(config, ids);\n return;\n }\n\n const isProd = config.mode === 'production';\n const modifiedFiles = new Set<string>(ids ?? []);\n sourceFileCache.invalidate(modifiedFiles);\n\n if (ids?.length) {\n for (const id of ids || []) {\n fileTransformMap.delete(id);\n }\n }\n\n // Cached include discovery (invalidated only on FS events)\n if (pluginOptions.include.length > 0 && includeCache.length === 0) {\n includeCache = findIncludes();\n }\n\n const resolvedTsConfigPath = resolveTsConfigPath();\n const tsconfigKey = [\n resolvedTsConfigPath,\n isProd ? 'prod' : 'dev',\n isTest ? 'test' : 'app',\n config.build?.lib ? 'lib' : 'nolib',\n ].join('|');\n let cached = tsconfigOptionsCache.get(tsconfigKey);\n\n if (!cached) {\n const read = compilerCli.readConfiguration(resolvedTsConfigPath, {\n suppressOutputPathCheck: true,\n outDir: undefined,\n sourceMap: false,\n inlineSourceMap: !isProd,\n inlineSources: !isProd,\n declaration: false,\n declarationMap: false,\n allowEmptyCodegenFiles: false,\n annotationsAs: 'decorators',\n enableResourceInlining: false,\n noEmitOnError: false,\n mapRoot: undefined,\n sourceRoot: undefined,\n supportTestBed: false,\n supportJitMode: false,\n });\n cached = { options: read.options, rootNames: read.rootNames };\n tsconfigOptionsCache.set(tsconfigKey, cached);\n }\n\n // Clone options before mutation (preserve cache purity)\n const tsCompilerOptions = { ...cached.options };\n let rootNames = [...cached.rootNames];\n\n if (pluginOptions.liveReload && watchMode) {\n tsCompilerOptions['_enableHmr'] = true;\n tsCompilerOptions['externalRuntimeStyles'] = true;\n // Workaround for https://github.com/angular/angular/issues/59310\n // Force extra instructions to be generated for HMR w/defer\n tsCompilerOptions['supportTestBed'] = true;\n }\n\n debugCompiler('tsCompilerOptions (NgtscProgram path)', {\n externalRuntimeStyles: !!tsCompilerOptions['externalRuntimeStyles'],\n hmr: !!tsCompilerOptions['_enableHmr'],\n });\n\n if (tsCompilerOptions['compilationMode'] === 'partial') {\n // These options can't be false in partial mode\n tsCompilerOptions['supportTestBed'] = true;\n tsCompilerOptions['supportJitMode'] = true;\n }\n\n if (!isTest && config.build?.lib) {\n tsCompilerOptions['declaration'] = true;\n tsCompilerOptions['declarationMap'] = watchMode;\n tsCompilerOptions['inlineSources'] = true;\n }\n\n if (isTest) {\n // Allow `TestBed.overrideXXX()` APIs.\n tsCompilerOptions['supportTestBed'] = true;\n }\n\n const replacements = pluginOptions.fileReplacements.map((rp) =>\n join(\n pluginOptions.workspaceRoot,\n (rp as FileReplacementSSR).ssr || (rp as FileReplacementWith).with,\n ),\n );\n // Merge + dedupe root names\n rootNames = union(rootNames, includeCache, replacements);\n const hostKey = JSON.stringify(tsCompilerOptions);\n let host: ts.CompilerHost;\n\n if (cachedHost && cachedHostKey === hostKey) {\n host = cachedHost;\n } else {\n host = ts.createIncrementalCompilerHost(tsCompilerOptions, {\n ...ts.sys,\n readFile(path: string, encoding: string) {\n if (fileTransformMap.has(path)) {\n return fileTransformMap.get(path);\n }\n\n const file = ts.sys.readFile.call(null, path, encoding);\n\n if (file) {\n fileTransformMap.set(path, file);\n }\n\n return file;\n },\n });\n cachedHost = host;\n cachedHostKey = hostKey;\n\n // Only store cache if in watch mode\n if (watchMode) {\n augmentHostWithCaching(host, sourceFileCache);\n }\n }\n\n if (!jit) {\n const externalizeStyles = !!tsCompilerOptions['externalRuntimeStyles'];\n inlineComponentStyles = externalizeStyles ? new Map() : undefined;\n externalComponentStyles = externalizeStyles ? new Map() : undefined;\n debugStyles('style maps initialized (NgtscProgram path)', {\n externalizeStyles,\n });\n augmentHostWithResources(host, styleTransform, {\n inlineStylesExtension: pluginOptions.inlineStylesExtension,\n isProd,\n inlineComponentStyles,\n externalComponentStyles,\n sourceFileCache,\n stylePreprocessor: pluginOptions.stylePreprocessor,\n });\n }\n\n /**\n * Creates a new NgtscProgram to analyze/re-analyze\n * the source files and create a file emitter.\n * This is shared between an initial build and a hot update.\n */\n let typeScriptProgram: ts.Program;\n let angularCompiler: NgtscProgram['compiler'];\n const oldBuilder =\n builder ?? ts.readBuilderProgram(tsCompilerOptions, host);\n\n if (!jit) {\n // Create the Angular specific program that contains the Angular compiler\n const angularProgram: NgtscProgram = new compilerCli.NgtscProgram(\n rootNames,\n tsCompilerOptions,\n host,\n nextProgram,\n );\n angularCompiler = angularProgram.compiler;\n typeScriptProgram = angularProgram.compiler.getCurrentProgram();\n augmentProgramWithVersioning(typeScriptProgram);\n\n builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(\n typeScriptProgram,\n host,\n oldBuilder as ts.EmitAndSemanticDiagnosticsBuilderProgram,\n );\n\n nextProgram = angularProgram;\n } else {\n builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(\n rootNames,\n tsCompilerOptions,\n host,\n oldBuilder as ts.EmitAndSemanticDiagnosticsBuilderProgram,\n );\n\n typeScriptProgram = builder.getProgram();\n }\n\n if (!watchMode) {\n // When not in watch mode, the startup cost of the incremental analysis can be avoided by\n // using an abstract builder that only wraps a TypeScript program.\n builder = ts.createAbstractBuilder(typeScriptProgram, host, oldBuilder);\n }\n\n if (angularCompiler!) {\n await angularCompiler.analyzeAsync();\n }\n\n const beforeTransformers = jit\n ? [\n compilerCli.constructorParametersDownlevelTransform(\n builder.getProgram(),\n ),\n createJitResourceTransformer(() =>\n builder.getProgram().getTypeChecker(),\n ),\n ]\n : [];\n\n const transformers = mergeTransformers(\n { before: beforeTransformers },\n jit ? {} : angularCompiler!.prepareEmit().transformers,\n );\n\n const fileMetadata = getFileMetadata(\n builder,\n angularCompiler!,\n pluginOptions.liveReload,\n pluginOptions.disableTypeChecking,\n );\n\n const writeFileCallback: ts.WriteFileCallback = (\n _filename,\n content,\n _a,\n _b,\n sourceFiles,\n ) => {\n if (!sourceFiles?.length) {\n return;\n }\n\n const filename = normalizePath(sourceFiles[0].fileName);\n\n if (filename.includes('ngtypecheck.ts') || filename.includes('.d.')) {\n return;\n }\n\n const metadata = watchMode ? fileMetadata(filename) : {};\n\n outputFiles.set(filename, {\n content,\n dependencies: [],\n errors: metadata.errors,\n warnings: metadata.warnings,\n hmrUpdateCode: metadata.hmrUpdateCode,\n hmrEligible: metadata.hmrEligible,\n });\n };\n\n const writeOutputFile = (id: string) => {\n const sourceFile = builder.getSourceFile(id);\n if (!sourceFile) {\n return;\n }\n\n let content = '';\n builder.emit(\n sourceFile,\n (filename, data) => {\n if (/\\.[cm]?js$/.test(filename)) {\n content = data;\n }\n\n if (\n !watchMode &&\n !isTest &&\n /\\.d\\.ts/.test(filename) &&\n !filename.includes('.ngtypecheck.')\n ) {\n // output to library root instead /src\n const declarationPath = resolve(\n config.root,\n config.build.outDir,\n relative(config.root, filename),\n ).replace('/src/', '/');\n\n const declarationFileDir = declarationPath\n .replace(basename(filename), '')\n .replace('/src/', '/');\n\n declarationFiles.push({\n declarationFileDir,\n declarationPath,\n data,\n });\n }\n },\n undefined /* cancellationToken */,\n undefined /* emitOnlyDtsFiles */,\n transformers,\n );\n\n writeFileCallback(id, content, false, undefined, [sourceFile]);\n\n if (angularCompiler) {\n angularCompiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);\n }\n };\n\n if (watchMode) {\n if (ids && ids.length > 0) {\n ids.forEach((id) => writeOutputFile(id));\n } else {\n /**\n * Only block the server from starting up\n * during testing.\n */\n if (isTest) {\n // TypeScript will loop until there are no more affected files in the program\n while (\n (\n builder as ts.EmitAndSemanticDiagnosticsBuilderProgram\n ).emitNextAffectedFile(\n writeFileCallback,\n undefined,\n undefined,\n transformers,\n )\n ) {\n /* empty */\n }\n }\n }\n }\n\n if (!isTest) {\n /**\n * Perf: Output files on demand so the dev server\n * isn't blocked when emitting files.\n */\n outputFile = writeOutputFile;\n }\n }\n}\n\nexport function createFsWatcherCacheInvalidator(\n invalidateFsCaches: () => void,\n invalidateTsconfigCaches: () => void,\n performCompilation: () => Promise<void>,\n): () => Promise<void> {\n return async (): Promise<void> => {\n invalidateFsCaches();\n invalidateTsconfigCaches();\n await performCompilation();\n };\n}\n\n/**\n * Convert Analog/Angular CLI-style file replacements into the flat record\n * expected by `AngularHostOptions.fileReplacements`.\n *\n * Only browser replacements (`{ replace, with }`) are converted. SSR-only\n * replacements (`{ replace, ssr }`) are left for the Vite runtime plugin to\n * handle — they should not be baked into the Angular compilation host because\n * that would apply them to both browser and server builds.\n *\n * Relative paths are resolved against `workspaceRoot` so that the host\n * receives the same absolute paths it would get from the Angular CLI.\n */\nexport function toAngularCompilationFileReplacements(\n replacements: FileReplacement[],\n workspaceRoot: string,\n): Record<string, string> | undefined {\n const mappedReplacements = replacements.flatMap((replacement) => {\n // Skip SSR-only entries — they use `ssr` instead of `with`.\n if (!('with' in replacement)) {\n return [];\n }\n\n return [\n [\n isAbsolute(replacement.replace)\n ? replacement.replace\n : resolve(workspaceRoot, replacement.replace),\n isAbsolute(replacement.with)\n ? replacement.with\n : resolve(workspaceRoot, replacement.with),\n ] as const,\n ];\n });\n\n return mappedReplacements.length\n ? Object.fromEntries(mappedReplacements)\n : undefined;\n}\n\n/**\n * Map Angular's `templateUpdates` (keyed by `encodedFilePath@ClassName`)\n * back to absolute file paths with their associated HMR code and component\n * class name.\n *\n * Angular's private Compilation API emits template update keys in the form\n * `encodeURIComponent(relativePath + '@' + className)`. We decode and resolve\n * them so the caller can look up updates by the same normalized absolute path\n * used elsewhere in the plugin (`outputFiles`, `classNames`, etc.).\n */\nexport function mapTemplateUpdatesToFiles(\n templateUpdates: ReadonlyMap<string, string> | undefined,\n): Map<\n string,\n {\n className: string;\n code: string;\n }\n> {\n const updatesByFile = new Map<string, { className: string; code: string }>();\n\n templateUpdates?.forEach((code, encodedUpdateId) => {\n const [file, className = ''] =\n decodeURIComponent(encodedUpdateId).split('@');\n const resolvedFile = normalizePath(resolve(process.cwd(), file));\n\n updatesByFile.set(resolvedFile, {\n className,\n code,\n });\n });\n\n return updatesByFile;\n}\n\nfunction sendHMRComponentUpdate(server: ViteDevServer, id: string) {\n server.ws.send('angular:component-update', {\n id: encodeURIComponent(id),\n timestamp: Date.now(),\n });\n\n classNames.delete(id);\n}\n\nexport function getFileMetadata(\n program: ts.BuilderProgram,\n angularCompiler?: NgtscProgram['compiler'],\n liveReload?: boolean,\n disableTypeChecking?: boolean,\n) {\n const ts = require('typescript');\n return (\n file: string,\n ): {\n errors?: string[];\n warnings?: (string | ts.DiagnosticMessageChain)[];\n hmrUpdateCode?: string | null;\n hmrEligible?: boolean;\n } => {\n const sourceFile = program.getSourceFile(file);\n if (!sourceFile) {\n return {};\n }\n\n const diagnostics = getDiagnosticsForSourceFile(\n sourceFile,\n !!disableTypeChecking,\n program,\n angularCompiler,\n );\n\n const errors = diagnostics\n .filter((d) => d.category === ts.DiagnosticCategory?.Error)\n .map((d) =>\n typeof d.messageText === 'object'\n ? d.messageText.messageText\n : d.messageText,\n );\n\n const warnings = diagnostics\n .filter((d) => d.category === ts.DiagnosticCategory?.Warning)\n .map((d) => d.messageText);\n\n let hmrUpdateCode: string | null | undefined = undefined;\n\n let hmrEligible = false;\n if (liveReload) {\n for (const node of sourceFile.statements) {\n if (ts.isClassDeclaration(node) && (node as any).name != null) {\n hmrUpdateCode = angularCompiler?.emitHmrUpdateModule(node as any);\n if (hmrUpdateCode) {\n const className = (node as any).name.getText();\n classNames.set(file, className);\n hmrEligible = true;\n debugHmr('NgtscProgram emitHmrUpdateModule', { file, className });\n }\n }\n }\n }\n\n return { errors, warnings, hmrUpdateCode, hmrEligible };\n };\n}\n\nfunction getDiagnosticsForSourceFile(\n sourceFile: ts.SourceFile,\n disableTypeChecking: boolean,\n program: ts.BuilderProgram,\n angularCompiler?: NgtscProgram['compiler'],\n) {\n const syntacticDiagnostics = program.getSyntacticDiagnostics(sourceFile);\n\n if (disableTypeChecking) {\n // Syntax errors are cheap to compute and the app will not run if there are any\n // So always show these types of errors regardless if type checking is disabled\n return syntacticDiagnostics;\n }\n\n const semanticDiagnostics = program.getSemanticDiagnostics(sourceFile);\n const angularDiagnostics = angularCompiler\n ? angularCompiler.getDiagnosticsForFile(sourceFile, 1)\n : [];\n return [\n ...syntacticDiagnostics,\n ...semanticDiagnostics,\n ...angularDiagnostics,\n ];\n}\n\nfunction markModuleSelfAccepting(mod: ModuleNode): ModuleNode {\n // support Vite 6\n if ('_clientModule' in mod) {\n (mod as any)['_clientModule'].isSelfAccepting = true;\n }\n\n return {\n ...mod,\n isSelfAccepting: true,\n } as ModuleNode;\n}\n\nfunction isComponentStyleSheet(id: string): boolean {\n return id.includes('ngcomp=');\n}\n\nfunction getComponentStyleSheetMeta(id: string): {\n componentId: string;\n encapsulation: 'emulated' | 'shadow' | 'none';\n} {\n const params = new URL(id, 'http://localhost').searchParams;\n const encapsulationMapping = {\n '0': 'emulated',\n '2': 'none',\n '3': 'shadow',\n };\n return {\n componentId: params.get('ngcomp')!,\n encapsulation: encapsulationMapping[\n params.get('e') as keyof typeof encapsulationMapping\n ] as 'emulated' | 'shadow' | 'none',\n };\n}\n\n/**\n * Removes leading / and query string from a url path\n * e.g. /foo.scss?direct&ngcomp=ng-c3153525609&e=0 returns foo.scss\n * @param id\n */\nfunction getFilenameFromPath(id: string): string {\n return new URL(id, 'http://localhost').pathname.replace(/^\\//, '');\n}\n\n/**\n * Checks for vitest run from the command line\n * @returns boolean\n */\nexport function isTestWatchMode(args: string[] = process.argv): boolean {\n // vitest --run\n const hasRun = args.find((arg) => arg.includes('--run'));\n if (hasRun) {\n return false;\n }\n\n // vitest --no-run\n const hasNoRun = args.find((arg) => arg.includes('--no-run'));\n if (hasNoRun) {\n return true;\n }\n\n // check for --watch=false or --no-watch\n const hasWatch = args.find((arg) => arg.includes('watch'));\n if (hasWatch && ['false', 'no'].some((neg) => hasWatch.includes(neg))) {\n return false;\n }\n\n // check for --watch false\n const watchIndex = args.findIndex((arg) => arg.includes('watch'));\n const watchArg = args[watchIndex + 1];\n if (watchArg && watchArg === 'false') {\n return false;\n }\n\n return true;\n}\n"],"mappings":"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"}
|
package/src/lib/host.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { debugStyles } from "./utils/debug.js";
|
|
1
2
|
import path from "node:path";
|
|
2
3
|
import { normalizePath } from "vite";
|
|
3
4
|
import { createHash } from "node:crypto";
|
|
@@ -20,8 +21,17 @@ function augmentHostWithResources(host, transform, options) {
|
|
|
20
21
|
if (options.inlineComponentStyles) {
|
|
21
22
|
const stylesheetId = createHash("sha256").update(context.containingFile).update(context.className).update(String(context.order)).update(preprocessedData).digest("hex") + "." + options.inlineStylesExtension;
|
|
22
23
|
options.inlineComponentStyles.set(stylesheetId, preprocessedData);
|
|
24
|
+
debugStyles("NgtscProgram: stylesheet deferred to Vite pipeline (liveReload)", {
|
|
25
|
+
stylesheetId,
|
|
26
|
+
resourceFile: context.resourceFile ?? "(inline)"
|
|
27
|
+
});
|
|
23
28
|
return { content: stylesheetId };
|
|
24
29
|
}
|
|
30
|
+
debugStyles("NgtscProgram: stylesheet processed inline via transform (no liveReload)", {
|
|
31
|
+
filename,
|
|
32
|
+
resourceFile: context.resourceFile ?? "(inline)",
|
|
33
|
+
dataLength: preprocessedData.length
|
|
34
|
+
});
|
|
25
35
|
let stylesheetResult;
|
|
26
36
|
try {
|
|
27
37
|
stylesheetResult = await transform(preprocessedData, `${filename}?direct`);
|
|
@@ -37,6 +47,11 @@ function augmentHostWithResources(host, transform, options) {
|
|
|
37
47
|
externalId ??= createHash("sha256").update(resolvedPath).digest("hex");
|
|
38
48
|
const filename = externalId + path.extname(resolvedPath);
|
|
39
49
|
options.externalComponentStyles.set(filename, resolvedPath);
|
|
50
|
+
debugStyles("NgtscProgram: external stylesheet ID mapped for resolveId", {
|
|
51
|
+
resourceName,
|
|
52
|
+
resolvedPath,
|
|
53
|
+
filename
|
|
54
|
+
});
|
|
40
55
|
return filename;
|
|
41
56
|
};
|
|
42
57
|
}
|
package/src/lib/host.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.js","names":[],"sources":["../../../src/lib/host.ts"],"sourcesContent":["import type { CompilerHost } from '@angular/compiler-cli';\nimport { normalizePath } from 'vite';\n\nimport * as ts from 'typescript';\n\nimport { createHash } from 'node:crypto';\nimport path from 'node:path';\nimport type { StylePreprocessor } from './style-preprocessor.js';\nimport type { SourceFileCache } from './utils/source-file-cache.js';\n\nexport function augmentHostWithResources(\n host: ts.CompilerHost,\n transform: (\n code: string,\n id: string,\n options?: { ssr?: boolean },\n ) => ReturnType<any> | null,\n options: {\n inlineStylesExtension: string;\n isProd?: boolean;\n inlineComponentStyles?: Map<string, string>;\n externalComponentStyles?: Map<string, string>;\n sourceFileCache?: SourceFileCache;\n stylePreprocessor?: StylePreprocessor;\n },\n): void {\n const resourceHost = host as CompilerHost;\n\n resourceHost.readResource = async function (fileName: string) {\n const filePath = normalizePath(fileName);\n\n const content = (this as any).readFile(filePath);\n\n if (content === undefined) {\n throw new Error('Unable to locate component resource: ' + fileName);\n }\n\n return content;\n };\n\n resourceHost.getModifiedResourceFiles = function () {\n return options?.sourceFileCache?.modifiedFiles;\n };\n\n resourceHost.transformResource = async function (data, context) {\n // Only style resources are supported currently\n if (context.type !== 'style') {\n return null;\n }\n\n const filename =\n context.resourceFile ??\n context.containingFile.replace(\n '.ts',\n `.${options?.inlineStylesExtension}`,\n );\n const preprocessedData = options.stylePreprocessor\n ? (options.stylePreprocessor(data, filename) ?? data)\n : data;\n\n // liveReload path: store preprocessed CSS for Vite's serve-time pipeline.\n // CSS must NOT be transformed here — the load hook returns it into\n // Vite's transform pipeline where PostCSS / Tailwind process it once.\n if (options.inlineComponentStyles) {\n const id = createHash('sha256')\n .update(context.containingFile)\n .update(context.className)\n .update(String(context.order))\n .update(preprocessedData)\n .digest('hex');\n const stylesheetId = id + '.' + options.inlineStylesExtension;\n options.inlineComponentStyles.set(stylesheetId, preprocessedData);\n return { content: stylesheetId };\n }\n\n // Non-liveReload: CSS is returned directly to the Angular compiler\n // and never re-enters Vite's pipeline, so transform eagerly.\n let stylesheetResult;\n\n try {\n stylesheetResult = await transform(\n preprocessedData,\n `${filename}?direct`,\n );\n } catch (e) {\n console.error(`${e}`);\n }\n\n return { content: stylesheetResult?.code || '' };\n };\n\n resourceHost.resourceNameToFileName = function (\n resourceName,\n containingFile,\n ) {\n const resolvedPath = path.join(path.dirname(containingFile), resourceName);\n\n // All resource names that have template file extensions are assumed to be templates\n if (!options.externalComponentStyles || !hasStyleExtension(resolvedPath)) {\n return resolvedPath;\n }\n\n // For external stylesheets, create a unique identifier and store the mapping\n let externalId = options.externalComponentStyles.get(resolvedPath);\n externalId ??= createHash('sha256').update(resolvedPath).digest('hex');\n\n const filename = externalId + path.extname(resolvedPath);\n\n options.externalComponentStyles.set(filename, resolvedPath);\n\n return filename;\n };\n}\n\nexport function augmentProgramWithVersioning(program: ts.Program): void {\n const baseGetSourceFiles = program.getSourceFiles;\n program.getSourceFiles = function (...parameters) {\n const files: readonly (ts.SourceFile & { version?: string })[] =\n baseGetSourceFiles(...parameters);\n\n for (const file of files) {\n file.version ??= createHash('sha256').update(file.text).digest('hex');\n }\n\n return files;\n };\n}\n\nexport function augmentHostWithCaching(\n host: ts.CompilerHost,\n cache: Map<string, ts.SourceFile>,\n): void {\n const baseGetSourceFile = host.getSourceFile;\n host.getSourceFile = function (\n fileName,\n languageVersion,\n onError,\n shouldCreateNewSourceFile,\n ...parameters\n ) {\n if (!shouldCreateNewSourceFile && cache.has(fileName)) {\n return cache.get(fileName);\n }\n\n const file = baseGetSourceFile.call(\n host,\n fileName,\n languageVersion,\n onError,\n true,\n ...parameters,\n );\n\n if (file) {\n cache.set(fileName, file);\n }\n\n return file;\n };\n}\n\nexport function mergeTransformers(\n first: ts.CustomTransformers,\n second: ts.CustomTransformers,\n): ts.CustomTransformers {\n const result: ts.CustomTransformers = {};\n\n if (first.before || second.before) {\n result.before = [...(first.before || []), ...(second.before || [])];\n }\n\n if (first.after || second.after) {\n result.after = [...(first.after || []), ...(second.after || [])];\n }\n\n if (first.afterDeclarations || second.afterDeclarations) {\n result.afterDeclarations = [\n ...(first.afterDeclarations || []),\n ...(second.afterDeclarations || []),\n ];\n }\n\n return result;\n}\n\nfunction hasStyleExtension(file: string): boolean {\n const extension = path.extname(file).toLowerCase();\n\n switch (extension) {\n case '.css':\n case '.scss':\n return true;\n default:\n return false;\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"host.js","names":[],"sources":["../../../src/lib/host.ts"],"sourcesContent":["import type { CompilerHost } from '@angular/compiler-cli';\nimport { normalizePath } from 'vite';\n\nimport * as ts from 'typescript';\n\nimport { createHash } from 'node:crypto';\nimport path from 'node:path';\nimport type { StylePreprocessor } from './style-preprocessor.js';\nimport { debugStyles } from './utils/debug.js';\nimport type { SourceFileCache } from './utils/source-file-cache.js';\n\nexport function augmentHostWithResources(\n host: ts.CompilerHost,\n transform: (\n code: string,\n id: string,\n options?: { ssr?: boolean },\n ) => ReturnType<any> | null,\n options: {\n inlineStylesExtension: string;\n isProd?: boolean;\n inlineComponentStyles?: Map<string, string>;\n externalComponentStyles?: Map<string, string>;\n sourceFileCache?: SourceFileCache;\n stylePreprocessor?: StylePreprocessor;\n },\n): void {\n const resourceHost = host as CompilerHost;\n\n resourceHost.readResource = async function (fileName: string) {\n const filePath = normalizePath(fileName);\n\n const content = (this as any).readFile(filePath);\n\n if (content === undefined) {\n throw new Error('Unable to locate component resource: ' + fileName);\n }\n\n return content;\n };\n\n resourceHost.getModifiedResourceFiles = function () {\n return options?.sourceFileCache?.modifiedFiles;\n };\n\n resourceHost.transformResource = async function (data, context) {\n // Only style resources are supported currently\n if (context.type !== 'style') {\n return null;\n }\n\n const filename =\n context.resourceFile ??\n context.containingFile.replace(\n '.ts',\n `.${options?.inlineStylesExtension}`,\n );\n const preprocessedData = options.stylePreprocessor\n ? (options.stylePreprocessor(data, filename) ?? data)\n : data;\n\n // liveReload path: store preprocessed CSS for Vite's serve-time pipeline.\n // CSS must NOT be transformed here — the load hook returns it into\n // Vite's transform pipeline where PostCSS / Tailwind process it once.\n if (options.inlineComponentStyles) {\n const id = createHash('sha256')\n .update(context.containingFile)\n .update(context.className)\n .update(String(context.order))\n .update(preprocessedData)\n .digest('hex');\n const stylesheetId = id + '.' + options.inlineStylesExtension;\n options.inlineComponentStyles.set(stylesheetId, preprocessedData);\n debugStyles(\n 'NgtscProgram: stylesheet deferred to Vite pipeline (liveReload)',\n {\n stylesheetId,\n resourceFile: context.resourceFile ?? '(inline)',\n },\n );\n return { content: stylesheetId };\n }\n\n // Non-liveReload: CSS is returned directly to the Angular compiler\n // and never re-enters Vite's pipeline, so transform eagerly.\n debugStyles(\n 'NgtscProgram: stylesheet processed inline via transform (no liveReload)',\n {\n filename,\n resourceFile: context.resourceFile ?? '(inline)',\n dataLength: preprocessedData.length,\n },\n );\n let stylesheetResult;\n\n try {\n stylesheetResult = await transform(\n preprocessedData,\n `${filename}?direct`,\n );\n } catch (e) {\n console.error(`${e}`);\n }\n\n return { content: stylesheetResult?.code || '' };\n };\n\n resourceHost.resourceNameToFileName = function (\n resourceName,\n containingFile,\n ) {\n const resolvedPath = path.join(path.dirname(containingFile), resourceName);\n\n // All resource names that have template file extensions are assumed to be templates\n if (!options.externalComponentStyles || !hasStyleExtension(resolvedPath)) {\n return resolvedPath;\n }\n\n // For external stylesheets, create a unique identifier and store the mapping\n let externalId = options.externalComponentStyles.get(resolvedPath);\n externalId ??= createHash('sha256').update(resolvedPath).digest('hex');\n\n const filename = externalId + path.extname(resolvedPath);\n\n options.externalComponentStyles.set(filename, resolvedPath);\n debugStyles('NgtscProgram: external stylesheet ID mapped for resolveId', {\n resourceName,\n resolvedPath,\n filename,\n });\n\n return filename;\n };\n}\n\nexport function augmentProgramWithVersioning(program: ts.Program): void {\n const baseGetSourceFiles = program.getSourceFiles;\n program.getSourceFiles = function (...parameters) {\n const files: readonly (ts.SourceFile & { version?: string })[] =\n baseGetSourceFiles(...parameters);\n\n for (const file of files) {\n file.version ??= createHash('sha256').update(file.text).digest('hex');\n }\n\n return files;\n };\n}\n\nexport function augmentHostWithCaching(\n host: ts.CompilerHost,\n cache: Map<string, ts.SourceFile>,\n): void {\n const baseGetSourceFile = host.getSourceFile;\n host.getSourceFile = function (\n fileName,\n languageVersion,\n onError,\n shouldCreateNewSourceFile,\n ...parameters\n ) {\n if (!shouldCreateNewSourceFile && cache.has(fileName)) {\n return cache.get(fileName);\n }\n\n const file = baseGetSourceFile.call(\n host,\n fileName,\n languageVersion,\n onError,\n true,\n ...parameters,\n );\n\n if (file) {\n cache.set(fileName, file);\n }\n\n return file;\n };\n}\n\nexport function mergeTransformers(\n first: ts.CustomTransformers,\n second: ts.CustomTransformers,\n): ts.CustomTransformers {\n const result: ts.CustomTransformers = {};\n\n if (first.before || second.before) {\n result.before = [...(first.before || []), ...(second.before || [])];\n }\n\n if (first.after || second.after) {\n result.after = [...(first.after || []), ...(second.after || [])];\n }\n\n if (first.afterDeclarations || second.afterDeclarations) {\n result.afterDeclarations = [\n ...(first.afterDeclarations || []),\n ...(second.afterDeclarations || []),\n ];\n }\n\n return result;\n}\n\nfunction hasStyleExtension(file: string): boolean {\n const extension = path.extname(file).toLowerCase();\n\n switch (extension) {\n case '.css':\n case '.scss':\n return true;\n default:\n return false;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { debugHmr } from "./utils/debug.js";
|
|
1
2
|
import { resolve } from "node:path";
|
|
2
3
|
import { normalizePath } from "vite";
|
|
3
4
|
//#region packages/vite-plugin-angular/src/lib/live-reload-plugin.ts
|
|
@@ -23,12 +24,17 @@ function liveReloadPlugin({ classNames, fileEmitter }) {
|
|
|
23
24
|
const [fileId] = decodeURIComponent(componentId).split("@");
|
|
24
25
|
const resolvedId = normalizePath(resolve(process.cwd(), fileId));
|
|
25
26
|
if (!(!!server.moduleGraph.getModuleById(resolvedId)?.lastInvalidationTimestamp && classNames.get(resolvedId))) {
|
|
27
|
+
debugHmr("middleware: skipped (not invalidated)", { resolvedId });
|
|
26
28
|
res.setHeader("Content-Type", "text/javascript");
|
|
27
29
|
res.setHeader("Cache-Control", "no-cache");
|
|
28
30
|
res.end("");
|
|
29
31
|
return;
|
|
30
32
|
}
|
|
31
33
|
const result = fileEmitter(resolvedId);
|
|
34
|
+
debugHmr("middleware: served component update", {
|
|
35
|
+
resolvedId,
|
|
36
|
+
hasCode: !!result?.hmrUpdateCode
|
|
37
|
+
});
|
|
32
38
|
res.setHeader("Content-Type", "text/javascript");
|
|
33
39
|
res.setHeader("Cache-Control", "no-cache");
|
|
34
40
|
res.end(`${result?.hmrUpdateCode || ""}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-reload-plugin.js","names":[],"sources":["../../../src/lib/live-reload-plugin.ts"],"sourcesContent":["import { resolve } from 'node:path';\nimport { ServerResponse } from 'node:http';\nimport { Connect, normalizePath, Plugin, ViteDevServer } from 'vite';\n\nimport { EmitFileResult } from './models.js';\n\nconst ANGULAR_COMPONENT_PREFIX = '/@ng/component';\nconst FILE_PREFIX = 'file:';\n\nexport function liveReloadPlugin({\n classNames,\n fileEmitter,\n}: {\n classNames: Map<string, string>;\n fileEmitter: (file: string) => EmitFileResult | undefined;\n}): Plugin {\n return {\n name: 'analogjs-live-reload-plugin',\n apply: 'serve',\n configureServer(server: ViteDevServer) {\n const angularComponentMiddleware: Connect.HandleFunction = async (\n req: Connect.IncomingMessage,\n res: ServerResponse<Connect.IncomingMessage>,\n next: Connect.NextFunction,\n ) => {\n if (req.url === undefined || res.writableEnded) {\n return;\n }\n\n if (!req.url.includes(ANGULAR_COMPONENT_PREFIX)) {\n next();\n\n return;\n }\n\n const requestUrl = new URL(req.url, 'http://localhost');\n const componentId = requestUrl.searchParams.get('c');\n\n if (!componentId) {\n res.statusCode = 400;\n res.end();\n\n return;\n }\n\n const [fileId] = decodeURIComponent(componentId).split('@');\n const resolvedId = normalizePath(resolve(process.cwd(), fileId));\n const invalidated =\n !!server.moduleGraph.getModuleById(resolvedId)\n ?.lastInvalidationTimestamp && classNames.get(resolvedId);\n\n // don't send an HMR update until the file has been invalidated\n if (!invalidated) {\n res.setHeader('Content-Type', 'text/javascript');\n res.setHeader('Cache-Control', 'no-cache');\n res.end('');\n return;\n }\n\n const result = fileEmitter(resolvedId);\n res.setHeader('Content-Type', 'text/javascript');\n res.setHeader('Cache-Control', 'no-cache');\n res.end(`${result?.hmrUpdateCode || ''}`);\n };\n\n server.middlewares.use(angularComponentMiddleware);\n },\n resolveId(id, _importer, options) {\n if (\n options?.ssr &&\n id.startsWith(FILE_PREFIX) &&\n id.includes(ANGULAR_COMPONENT_PREFIX)\n ) {\n return `\\0${id}`;\n }\n\n return undefined;\n },\n load(id, options) {\n if (options?.ssr && id.includes(ANGULAR_COMPONENT_PREFIX)) {\n const requestUrl = new URL(id.slice(1), 'http://localhost');\n const componentId = requestUrl.searchParams.get('c');\n\n if (!componentId) {\n return;\n }\n\n const result = fileEmitter(\n normalizePath(\n resolve(\n process.cwd(),\n decodeURIComponent(componentId).split('@')[0],\n ),\n ),\n );\n\n return result?.hmrUpdateCode || '';\n }\n\n return;\n },\n };\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"live-reload-plugin.js","names":[],"sources":["../../../src/lib/live-reload-plugin.ts"],"sourcesContent":["import { resolve } from 'node:path';\nimport { ServerResponse } from 'node:http';\nimport { Connect, normalizePath, Plugin, ViteDevServer } from 'vite';\n\nimport { EmitFileResult } from './models.js';\nimport { debugHmr } from './utils/debug.js';\n\nconst ANGULAR_COMPONENT_PREFIX = '/@ng/component';\nconst FILE_PREFIX = 'file:';\n\nexport function liveReloadPlugin({\n classNames,\n fileEmitter,\n}: {\n classNames: Map<string, string>;\n fileEmitter: (file: string) => EmitFileResult | undefined;\n}): Plugin {\n return {\n name: 'analogjs-live-reload-plugin',\n apply: 'serve',\n configureServer(server: ViteDevServer) {\n const angularComponentMiddleware: Connect.HandleFunction = async (\n req: Connect.IncomingMessage,\n res: ServerResponse<Connect.IncomingMessage>,\n next: Connect.NextFunction,\n ) => {\n if (req.url === undefined || res.writableEnded) {\n return;\n }\n\n if (!req.url.includes(ANGULAR_COMPONENT_PREFIX)) {\n next();\n\n return;\n }\n\n const requestUrl = new URL(req.url, 'http://localhost');\n const componentId = requestUrl.searchParams.get('c');\n\n if (!componentId) {\n res.statusCode = 400;\n res.end();\n\n return;\n }\n\n const [fileId] = decodeURIComponent(componentId).split('@');\n const resolvedId = normalizePath(resolve(process.cwd(), fileId));\n const invalidated =\n !!server.moduleGraph.getModuleById(resolvedId)\n ?.lastInvalidationTimestamp && classNames.get(resolvedId);\n\n // don't send an HMR update until the file has been invalidated\n if (!invalidated) {\n debugHmr('middleware: skipped (not invalidated)', { resolvedId });\n res.setHeader('Content-Type', 'text/javascript');\n res.setHeader('Cache-Control', 'no-cache');\n res.end('');\n return;\n }\n\n const result = fileEmitter(resolvedId);\n debugHmr('middleware: served component update', {\n resolvedId,\n hasCode: !!result?.hmrUpdateCode,\n });\n res.setHeader('Content-Type', 'text/javascript');\n res.setHeader('Cache-Control', 'no-cache');\n res.end(`${result?.hmrUpdateCode || ''}`);\n };\n\n server.middlewares.use(angularComponentMiddleware);\n },\n resolveId(id, _importer, options) {\n if (\n options?.ssr &&\n id.startsWith(FILE_PREFIX) &&\n id.includes(ANGULAR_COMPONENT_PREFIX)\n ) {\n return `\\0${id}`;\n }\n\n return undefined;\n },\n load(id, options) {\n if (options?.ssr && id.includes(ANGULAR_COMPONENT_PREFIX)) {\n const requestUrl = new URL(id.slice(1), 'http://localhost');\n const componentId = requestUrl.searchParams.get('c');\n\n if (!componentId) {\n return;\n }\n\n const result = fileEmitter(\n normalizePath(\n resolve(\n process.cwd(),\n decodeURIComponent(componentId).split('@')[0],\n ),\n ),\n );\n\n return result?.hmrUpdateCode || '';\n }\n\n return;\n },\n };\n}\n"],"mappings":";;;;AAOA,IAAM,2BAA2B;AACjC,IAAM,cAAc;AAEpB,SAAgB,iBAAiB,EAC/B,YACA,eAIS;AACT,QAAO;EACL,MAAM;EACN,OAAO;EACP,gBAAgB,QAAuB;GACrC,MAAM,6BAAqD,OACzD,KACA,KACA,SACG;AACH,QAAI,IAAI,QAAQ,KAAA,KAAa,IAAI,cAC/B;AAGF,QAAI,CAAC,IAAI,IAAI,SAAS,yBAAyB,EAAE;AAC/C,WAAM;AAEN;;IAIF,MAAM,cADa,IAAI,IAAI,IAAI,KAAK,mBAAmB,CACxB,aAAa,IAAI,IAAI;AAEpD,QAAI,CAAC,aAAa;AAChB,SAAI,aAAa;AACjB,SAAI,KAAK;AAET;;IAGF,MAAM,CAAC,UAAU,mBAAmB,YAAY,CAAC,MAAM,IAAI;IAC3D,MAAM,aAAa,cAAc,QAAQ,QAAQ,KAAK,EAAE,OAAO,CAAC;AAMhE,QAAI,EAJF,CAAC,CAAC,OAAO,YAAY,cAAc,WAAW,EAC1C,6BAA6B,WAAW,IAAI,WAAW,GAG3C;AAChB,cAAS,yCAAyC,EAAE,YAAY,CAAC;AACjE,SAAI,UAAU,gBAAgB,kBAAkB;AAChD,SAAI,UAAU,iBAAiB,WAAW;AAC1C,SAAI,IAAI,GAAG;AACX;;IAGF,MAAM,SAAS,YAAY,WAAW;AACtC,aAAS,uCAAuC;KAC9C;KACA,SAAS,CAAC,CAAC,QAAQ;KACpB,CAAC;AACF,QAAI,UAAU,gBAAgB,kBAAkB;AAChD,QAAI,UAAU,iBAAiB,WAAW;AAC1C,QAAI,IAAI,GAAG,QAAQ,iBAAiB,KAAK;;AAG3C,UAAO,YAAY,IAAI,2BAA2B;;EAEpD,UAAU,IAAI,WAAW,SAAS;AAChC,OACE,SAAS,OACT,GAAG,WAAW,YAAY,IAC1B,GAAG,SAAS,yBAAyB,CAErC,QAAO,KAAK;;EAKhB,KAAK,IAAI,SAAS;AAChB,OAAI,SAAS,OAAO,GAAG,SAAS,yBAAyB,EAAE;IAEzD,MAAM,cADa,IAAI,IAAI,GAAG,MAAM,EAAE,EAAE,mBAAmB,CAC5B,aAAa,IAAI,IAAI;AAEpD,QAAI,CAAC,YACH;AAYF,WATe,YACb,cACE,QACE,QAAQ,KAAK,EACb,mBAAmB,YAAY,CAAC,MAAM,IAAI,CAAC,GAC5C,CACF,CACF,EAEc,iBAAiB;;;EAKrC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Debugger } from "obug";
|
|
2
|
+
export type DebugMode = "build" | "dev";
|
|
3
|
+
export interface DebugModeOptions<S extends string = string> {
|
|
4
|
+
scopes?: boolean | S[];
|
|
5
|
+
mode?: DebugMode;
|
|
6
|
+
/**
|
|
7
|
+
* Write debug output to log files under `tmp/debug/` in the workspace root.
|
|
8
|
+
* - `true` or `'single'` — all output to `tmp/debug/analog.log`
|
|
9
|
+
* - `'scoped'` — one file per scope, e.g. `tmp/debug/analog.angular.hmr.log`
|
|
10
|
+
*/
|
|
11
|
+
logFile?: boolean | "single" | "scoped";
|
|
12
|
+
}
|
|
13
|
+
export type DebugOption<S extends string = string> = boolean | S[] | DebugModeOptions<S> | DebugModeOptions<S>[];
|
|
14
|
+
export interface DebugHarness<S extends string = string> {
|
|
15
|
+
applyDebugOption(debug: DebugOption<S> | undefined, workspaceRoot?: string): void;
|
|
16
|
+
activateDeferredDebug(command: "build" | "serve"): void;
|
|
17
|
+
/** @internal test-only reset */
|
|
18
|
+
_resetDeferredDebug(): void;
|
|
19
|
+
}
|
|
20
|
+
export declare function createDebugHarness<S extends string = string>(config: {
|
|
21
|
+
fallbackNamespace: string;
|
|
22
|
+
instanceGroups: Debugger[][];
|
|
23
|
+
}): DebugHarness<S>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { DEBUG_LOG_DIR, DEBUG_LOG_FILENAME, wrapInstancesForFileLog, wrapInstancesForScopedFileLog } from "./debug-log-file.js";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { enable } from "obug";
|
|
4
|
+
//#region packages/vite-plugin-angular/src/lib/utils/debug-harness.ts
|
|
5
|
+
/**
|
|
6
|
+
* Duplicates of this file (keep in sync):
|
|
7
|
+
* packages/platform/src/lib/utils/debug-harness.ts
|
|
8
|
+
* packages/vite-plugin-angular/src/lib/utils/debug-harness.ts
|
|
9
|
+
*/
|
|
10
|
+
function resolveNamespaces(scopes, fallback) {
|
|
11
|
+
if (scopes === true || scopes === void 0) return fallback;
|
|
12
|
+
if (Array.isArray(scopes) && scopes.length) return scopes.join(",");
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
function extractLogFile(debug) {
|
|
16
|
+
if (typeof debug === "boolean") return false;
|
|
17
|
+
if (Array.isArray(debug)) {
|
|
18
|
+
if (debug.length === 0 || typeof debug[0] === "string") return false;
|
|
19
|
+
return debug.find((e) => !!e.logFile)?.logFile ?? false;
|
|
20
|
+
}
|
|
21
|
+
return debug.logFile ?? false;
|
|
22
|
+
}
|
|
23
|
+
function createDebugHarness(config) {
|
|
24
|
+
let pendingDebug = [];
|
|
25
|
+
function installFileWrappers(logFile, root) {
|
|
26
|
+
if (logFile === "scoped") {
|
|
27
|
+
const dirPath = join(root, DEBUG_LOG_DIR);
|
|
28
|
+
for (const group of config.instanceGroups) wrapInstancesForScopedFileLog(group, dirPath);
|
|
29
|
+
} else {
|
|
30
|
+
const filePath = join(root, DEBUG_LOG_DIR, DEBUG_LOG_FILENAME);
|
|
31
|
+
for (const group of config.instanceGroups) wrapInstancesForFileLog(group, filePath);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function applyEntry(entry, fallback, logFile, root) {
|
|
35
|
+
if (!entry.mode) {
|
|
36
|
+
const ns = resolveNamespaces(entry.scopes ?? true, fallback);
|
|
37
|
+
if (ns) enable(ns);
|
|
38
|
+
if (logFile) installFileWrappers(logFile, root);
|
|
39
|
+
} else pendingDebug.push({
|
|
40
|
+
entry,
|
|
41
|
+
logFile,
|
|
42
|
+
root
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
applyDebugOption(debug, workspaceRoot) {
|
|
47
|
+
if (debug == null || debug === false) return;
|
|
48
|
+
const logFile = extractLogFile(debug);
|
|
49
|
+
const root = workspaceRoot ?? process.env["NX_WORKSPACE_ROOT"] ?? process.cwd();
|
|
50
|
+
if (typeof debug === "boolean") {
|
|
51
|
+
const ns = resolveNamespaces(debug, config.fallbackNamespace);
|
|
52
|
+
if (ns) enable(ns);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (Array.isArray(debug)) {
|
|
56
|
+
if (debug.length === 0) return;
|
|
57
|
+
if (typeof debug[0] === "string") {
|
|
58
|
+
const ns = debug.join(",");
|
|
59
|
+
if (ns) enable(ns);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
for (const entry of debug) {
|
|
63
|
+
const entryLogFile = entry.logFile ?? false;
|
|
64
|
+
applyEntry(entry, config.fallbackNamespace, entryLogFile || logFile, root);
|
|
65
|
+
}
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
applyEntry(debug, config.fallbackNamespace, logFile, root);
|
|
69
|
+
},
|
|
70
|
+
activateDeferredDebug(command) {
|
|
71
|
+
if (pendingDebug.length === 0) return;
|
|
72
|
+
const currentMode = command === "serve" ? "dev" : "build";
|
|
73
|
+
for (const { entry, logFile, root } of pendingDebug) if (entry.mode === currentMode) {
|
|
74
|
+
const ns = resolveNamespaces(entry.scopes ?? true, config.fallbackNamespace);
|
|
75
|
+
if (ns) enable(ns);
|
|
76
|
+
if (logFile) installFileWrappers(logFile, root);
|
|
77
|
+
}
|
|
78
|
+
pendingDebug = [];
|
|
79
|
+
},
|
|
80
|
+
_resetDeferredDebug() {
|
|
81
|
+
pendingDebug = [];
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
//#endregion
|
|
86
|
+
export { createDebugHarness };
|
|
87
|
+
|
|
88
|
+
//# sourceMappingURL=debug-harness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-harness.js","names":[],"sources":["../../../../src/lib/utils/debug-harness.ts"],"sourcesContent":["/**\n * Duplicates of this file (keep in sync):\n * packages/platform/src/lib/utils/debug-harness.ts\n * packages/vite-plugin-angular/src/lib/utils/debug-harness.ts\n */\nimport { join } from 'node:path';\nimport { enable } from 'obug';\nimport type { Debugger } from 'obug';\n\nimport {\n DEBUG_LOG_DIR,\n DEBUG_LOG_FILENAME,\n wrapInstancesForFileLog,\n wrapInstancesForScopedFileLog,\n} from './debug-log-file.js';\n\nexport type DebugMode = 'build' | 'dev';\n\nexport interface DebugModeOptions<S extends string = string> {\n scopes?: boolean | S[];\n mode?: DebugMode;\n /**\n * Write debug output to log files under `tmp/debug/` in the workspace root.\n * - `true` or `'single'` — all output to `tmp/debug/analog.log`\n * - `'scoped'` — one file per scope, e.g. `tmp/debug/analog.angular.hmr.log`\n */\n logFile?: boolean | 'single' | 'scoped';\n}\n\nexport type DebugOption<S extends string = string> =\n | boolean\n | S[]\n | DebugModeOptions<S>\n | DebugModeOptions<S>[];\n\nexport interface DebugHarness<S extends string = string> {\n applyDebugOption(\n debug: DebugOption<S> | undefined,\n workspaceRoot?: string,\n ): void;\n activateDeferredDebug(command: 'build' | 'serve'): void;\n /** @internal test-only reset */\n _resetDeferredDebug(): void;\n}\n\nfunction resolveNamespaces(\n scopes: boolean | string[] | undefined,\n fallback: string,\n): string | null {\n if (scopes === true || scopes === undefined) return fallback;\n if (Array.isArray(scopes) && scopes.length) return scopes.join(',');\n return null;\n}\n\nfunction extractLogFile(\n debug: DebugOption,\n): true | 'single' | 'scoped' | false {\n if (typeof debug === 'boolean') return false;\n if (Array.isArray(debug)) {\n if (debug.length === 0 || typeof debug[0] === 'string') return false;\n const entry = (debug as DebugModeOptions[]).find((e) => !!e.logFile);\n return entry?.logFile ?? false;\n }\n return (debug as DebugModeOptions).logFile ?? false;\n}\n\nexport function createDebugHarness<S extends string = string>(config: {\n fallbackNamespace: string;\n instanceGroups: Debugger[][];\n}): DebugHarness<S> {\n interface PendingEntry {\n entry: DebugModeOptions<S>;\n logFile: true | 'single' | 'scoped' | false;\n root: string;\n }\n\n let pendingDebug: PendingEntry[] = [];\n\n function installFileWrappers(\n logFile: true | 'single' | 'scoped',\n root: string,\n ): void {\n if (logFile === 'scoped') {\n const dirPath = join(root, DEBUG_LOG_DIR);\n for (const group of config.instanceGroups) {\n wrapInstancesForScopedFileLog(group, dirPath);\n }\n } else {\n const filePath = join(root, DEBUG_LOG_DIR, DEBUG_LOG_FILENAME);\n for (const group of config.instanceGroups) {\n wrapInstancesForFileLog(group, filePath);\n }\n }\n }\n\n function applyEntry(\n entry: DebugModeOptions<S>,\n fallback: string,\n logFile: true | 'single' | 'scoped' | false,\n root: string,\n ): void {\n if (!entry.mode) {\n const ns = resolveNamespaces(entry.scopes ?? true, fallback);\n if (ns) enable(ns);\n if (logFile) installFileWrappers(logFile, root);\n } else {\n pendingDebug.push({ entry, logFile, root });\n }\n }\n\n return {\n applyDebugOption(\n debug: DebugOption<S> | undefined,\n workspaceRoot?: string,\n ): void {\n if (debug == null || debug === false) return;\n\n const logFile = extractLogFile(debug);\n const root =\n workspaceRoot ?? process.env['NX_WORKSPACE_ROOT'] ?? process.cwd();\n\n if (typeof debug === 'boolean') {\n const ns = resolveNamespaces(debug, config.fallbackNamespace);\n if (ns) enable(ns);\n return;\n }\n\n if (Array.isArray(debug)) {\n if (debug.length === 0) return;\n\n if (typeof debug[0] === 'string') {\n const ns = (debug as string[]).join(',');\n if (ns) enable(ns);\n return;\n }\n\n for (const entry of debug as DebugModeOptions<S>[]) {\n const entryLogFile = entry.logFile ?? false;\n applyEntry(\n entry,\n config.fallbackNamespace,\n entryLogFile || logFile,\n root,\n );\n }\n return;\n }\n\n applyEntry(debug, config.fallbackNamespace, logFile, root);\n },\n\n activateDeferredDebug(command: 'build' | 'serve'): void {\n if (pendingDebug.length === 0) return;\n\n const currentMode = command === 'serve' ? 'dev' : 'build';\n\n for (const { entry, logFile, root } of pendingDebug) {\n if (entry.mode === currentMode) {\n const ns = resolveNamespaces(\n entry.scopes ?? true,\n config.fallbackNamespace,\n );\n if (ns) enable(ns);\n if (logFile) installFileWrappers(logFile, root);\n }\n }\n\n pendingDebug = [];\n },\n\n _resetDeferredDebug(): void {\n pendingDebug = [];\n },\n };\n}\n"],"mappings":";;;;;;;;;AA6CA,SAAS,kBACP,QACA,UACe;AACf,KAAI,WAAW,QAAQ,WAAW,KAAA,EAAW,QAAO;AACpD,KAAI,MAAM,QAAQ,OAAO,IAAI,OAAO,OAAQ,QAAO,OAAO,KAAK,IAAI;AACnE,QAAO;;AAGT,SAAS,eACP,OACoC;AACpC,KAAI,OAAO,UAAU,UAAW,QAAO;AACvC,KAAI,MAAM,QAAQ,MAAM,EAAE;AACxB,MAAI,MAAM,WAAW,KAAK,OAAO,MAAM,OAAO,SAAU,QAAO;AAE/D,SADe,MAA6B,MAAM,MAAM,CAAC,CAAC,EAAE,QAAQ,EACtD,WAAW;;AAE3B,QAAQ,MAA2B,WAAW;;AAGhD,SAAgB,mBAA8C,QAG1C;CAOlB,IAAI,eAA+B,EAAE;CAErC,SAAS,oBACP,SACA,MACM;AACN,MAAI,YAAY,UAAU;GACxB,MAAM,UAAU,KAAK,MAAM,cAAc;AACzC,QAAK,MAAM,SAAS,OAAO,eACzB,+BAA8B,OAAO,QAAQ;SAE1C;GACL,MAAM,WAAW,KAAK,MAAM,eAAe,mBAAmB;AAC9D,QAAK,MAAM,SAAS,OAAO,eACzB,yBAAwB,OAAO,SAAS;;;CAK9C,SAAS,WACP,OACA,UACA,SACA,MACM;AACN,MAAI,CAAC,MAAM,MAAM;GACf,MAAM,KAAK,kBAAkB,MAAM,UAAU,MAAM,SAAS;AAC5D,OAAI,GAAI,QAAO,GAAG;AAClB,OAAI,QAAS,qBAAoB,SAAS,KAAK;QAE/C,cAAa,KAAK;GAAE;GAAO;GAAS;GAAM,CAAC;;AAI/C,QAAO;EACL,iBACE,OACA,eACM;AACN,OAAI,SAAS,QAAQ,UAAU,MAAO;GAEtC,MAAM,UAAU,eAAe,MAAM;GACrC,MAAM,OACJ,iBAAiB,QAAQ,IAAI,wBAAwB,QAAQ,KAAK;AAEpE,OAAI,OAAO,UAAU,WAAW;IAC9B,MAAM,KAAK,kBAAkB,OAAO,OAAO,kBAAkB;AAC7D,QAAI,GAAI,QAAO,GAAG;AAClB;;AAGF,OAAI,MAAM,QAAQ,MAAM,EAAE;AACxB,QAAI,MAAM,WAAW,EAAG;AAExB,QAAI,OAAO,MAAM,OAAO,UAAU;KAChC,MAAM,KAAM,MAAmB,KAAK,IAAI;AACxC,SAAI,GAAI,QAAO,GAAG;AAClB;;AAGF,SAAK,MAAM,SAAS,OAAgC;KAClD,MAAM,eAAe,MAAM,WAAW;AACtC,gBACE,OACA,OAAO,mBACP,gBAAgB,SAChB,KACD;;AAEH;;AAGF,cAAW,OAAO,OAAO,mBAAmB,SAAS,KAAK;;EAG5D,sBAAsB,SAAkC;AACtD,OAAI,aAAa,WAAW,EAAG;GAE/B,MAAM,cAAc,YAAY,UAAU,QAAQ;AAElD,QAAK,MAAM,EAAE,OAAO,SAAS,UAAU,aACrC,KAAI,MAAM,SAAS,aAAa;IAC9B,MAAM,KAAK,kBACT,MAAM,UAAU,MAChB,OAAO,kBACR;AACD,QAAI,GAAI,QAAO,GAAG;AAClB,QAAI,QAAS,qBAAoB,SAAS,KAAK;;AAInD,kBAAe,EAAE;;EAGnB,sBAA4B;AAC1B,kBAAe,EAAE;;EAEpB"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Debugger } from "obug";
|
|
2
|
+
export declare const DEBUG_LOG_DIR = "tmp/debug";
|
|
3
|
+
export declare const DEBUG_LOG_FILENAME = "analog.log";
|
|
4
|
+
export declare function wrapInstancesForFileLog(instances: Debugger[], filePath: string): void;
|
|
5
|
+
export declare function wrapInstancesForScopedFileLog(instances: Debugger[], dirPath: string): void;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { appendFileSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { format } from "node:util";
|
|
4
|
+
//#region packages/vite-plugin-angular/src/lib/utils/debug-log-file.ts
|
|
5
|
+
/**
|
|
6
|
+
* Duplicates of this file (keep in sync):
|
|
7
|
+
* packages/platform/src/lib/utils/debug-log-file.ts
|
|
8
|
+
* packages/vite-plugin-angular/src/lib/utils/debug-log-file.ts
|
|
9
|
+
*/
|
|
10
|
+
var TRUNCATED_KEY = "__analogDebugLogTruncated";
|
|
11
|
+
var WRAPPED_KEY = "__analogFileLogWrapped";
|
|
12
|
+
var ANSI_RE = /\x1B\[[0-9;]*[A-Za-z]|\x1B\].*?\x07/g;
|
|
13
|
+
var DEBUG_LOG_DIR = "tmp/debug";
|
|
14
|
+
var DEBUG_LOG_FILENAME = "analog.log";
|
|
15
|
+
function ensureTruncated(filePath) {
|
|
16
|
+
const g = globalThis;
|
|
17
|
+
const truncated = g[TRUNCATED_KEY] ?? /* @__PURE__ */ new Set();
|
|
18
|
+
g[TRUNCATED_KEY] = truncated;
|
|
19
|
+
if (truncated.has(filePath)) return;
|
|
20
|
+
try {
|
|
21
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
22
|
+
writeFileSync(filePath, "", "utf-8");
|
|
23
|
+
} catch {}
|
|
24
|
+
truncated.add(filePath);
|
|
25
|
+
}
|
|
26
|
+
function wrapLog(dbg, filePath) {
|
|
27
|
+
const rec = dbg;
|
|
28
|
+
if (rec[WRAPPED_KEY] === filePath) return;
|
|
29
|
+
const originalLog = rec[WRAPPED_KEY] && rec["__analogOriginalLog"] ? rec["__analogOriginalLog"] : dbg.log;
|
|
30
|
+
rec["__analogOriginalLog"] = originalLog;
|
|
31
|
+
dbg.log = function(...args) {
|
|
32
|
+
originalLog.apply(this, args);
|
|
33
|
+
try {
|
|
34
|
+
appendFileSync(filePath, format(...args).replace(ANSI_RE, "") + "\n", "utf-8");
|
|
35
|
+
} catch {}
|
|
36
|
+
};
|
|
37
|
+
rec[WRAPPED_KEY] = filePath;
|
|
38
|
+
}
|
|
39
|
+
function wrapInstancesForFileLog(instances, filePath) {
|
|
40
|
+
ensureTruncated(filePath);
|
|
41
|
+
for (const dbg of instances) wrapLog(dbg, filePath);
|
|
42
|
+
}
|
|
43
|
+
function scopeToFilename(namespace) {
|
|
44
|
+
return namespace.replace(/:/g, ".") + ".log";
|
|
45
|
+
}
|
|
46
|
+
function wrapInstancesForScopedFileLog(instances, dirPath) {
|
|
47
|
+
for (const dbg of instances) {
|
|
48
|
+
const scopedPath = join(dirPath, scopeToFilename(dbg.namespace));
|
|
49
|
+
ensureTruncated(scopedPath);
|
|
50
|
+
wrapLog(dbg, scopedPath);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { DEBUG_LOG_DIR, DEBUG_LOG_FILENAME, wrapInstancesForFileLog, wrapInstancesForScopedFileLog };
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=debug-log-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-log-file.js","names":[],"sources":["../../../../src/lib/utils/debug-log-file.ts"],"sourcesContent":["/**\n * Duplicates of this file (keep in sync):\n * packages/platform/src/lib/utils/debug-log-file.ts\n * packages/vite-plugin-angular/src/lib/utils/debug-log-file.ts\n */\nimport { mkdirSync, writeFileSync, appendFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { format } from 'node:util';\nimport type { Debugger } from 'obug';\n\nconst TRUNCATED_KEY = '__analogDebugLogTruncated';\nconst WRAPPED_KEY = '__analogFileLogWrapped';\n// eslint-disable-next-line no-control-regex\nconst ANSI_RE = /\\x1B\\[[0-9;]*[A-Za-z]|\\x1B\\].*?\\x07/g;\n\nexport const DEBUG_LOG_DIR = 'tmp/debug';\nexport const DEBUG_LOG_FILENAME = 'analog.log';\n\nfunction ensureTruncated(filePath: string): void {\n const g = globalThis as Record<string, unknown>;\n const truncated = (g[TRUNCATED_KEY] as Set<string>) ?? new Set<string>();\n g[TRUNCATED_KEY] = truncated;\n if (truncated.has(filePath)) return;\n try {\n mkdirSync(dirname(filePath), { recursive: true });\n writeFileSync(filePath, '', 'utf-8');\n } catch {\n // best-effort: fall through to append mode if truncation fails\n }\n truncated.add(filePath);\n}\n\nfunction wrapLog(dbg: Debugger, filePath: string): void {\n const rec = dbg as Record<string, unknown>;\n if (rec[WRAPPED_KEY] === filePath) return;\n\n const originalLog =\n rec[WRAPPED_KEY] && rec['__analogOriginalLog']\n ? (rec['__analogOriginalLog'] as Debugger['log'])\n : dbg.log;\n\n rec['__analogOriginalLog'] = originalLog;\n dbg.log = function (this: Debugger, ...args: unknown[]) {\n originalLog.apply(this, args);\n try {\n const line = format(...args).replace(ANSI_RE, '') + '\\n';\n appendFileSync(filePath, line, 'utf-8');\n } catch {\n // debug logging must never crash the build\n }\n };\n rec[WRAPPED_KEY] = filePath;\n}\n\nexport function wrapInstancesForFileLog(\n instances: Debugger[],\n filePath: string,\n): void {\n ensureTruncated(filePath);\n for (const dbg of instances) {\n wrapLog(dbg, filePath);\n }\n}\n\nfunction scopeToFilename(namespace: string): string {\n return namespace.replace(/:/g, '.') + '.log';\n}\n\nexport function wrapInstancesForScopedFileLog(\n instances: Debugger[],\n dirPath: string,\n): void {\n for (const dbg of instances) {\n const scopedPath = join(dirPath, scopeToFilename(dbg.namespace));\n ensureTruncated(scopedPath);\n wrapLog(dbg, scopedPath);\n }\n}\n"],"mappings":";;;;;;;;;AAUA,IAAM,gBAAgB;AACtB,IAAM,cAAc;AAEpB,IAAM,UAAU;AAEhB,IAAa,gBAAgB;AAC7B,IAAa,qBAAqB;AAElC,SAAS,gBAAgB,UAAwB;CAC/C,MAAM,IAAI;CACV,MAAM,YAAa,EAAE,kCAAkC,IAAI,KAAa;AACxE,GAAE,iBAAiB;AACnB,KAAI,UAAU,IAAI,SAAS,CAAE;AAC7B,KAAI;AACF,YAAU,QAAQ,SAAS,EAAE,EAAE,WAAW,MAAM,CAAC;AACjD,gBAAc,UAAU,IAAI,QAAQ;SAC9B;AAGR,WAAU,IAAI,SAAS;;AAGzB,SAAS,QAAQ,KAAe,UAAwB;CACtD,MAAM,MAAM;AACZ,KAAI,IAAI,iBAAiB,SAAU;CAEnC,MAAM,cACJ,IAAI,gBAAgB,IAAI,yBACnB,IAAI,yBACL,IAAI;AAEV,KAAI,yBAAyB;AAC7B,KAAI,MAAM,SAA0B,GAAG,MAAiB;AACtD,cAAY,MAAM,MAAM,KAAK;AAC7B,MAAI;AAEF,kBAAe,UADF,OAAO,GAAG,KAAK,CAAC,QAAQ,SAAS,GAAG,GAAG,MACrB,QAAQ;UACjC;;AAIV,KAAI,eAAe;;AAGrB,SAAgB,wBACd,WACA,UACM;AACN,iBAAgB,SAAS;AACzB,MAAK,MAAM,OAAO,UAChB,SAAQ,KAAK,SAAS;;AAI1B,SAAS,gBAAgB,WAA2B;AAClD,QAAO,UAAU,QAAQ,MAAM,IAAI,GAAG;;AAGxC,SAAgB,8BACd,WACA,SACM;AACN,MAAK,MAAM,OAAO,WAAW;EAC3B,MAAM,aAAa,KAAK,SAAS,gBAAgB,IAAI,UAAU,CAAC;AAChE,kBAAgB,WAAW;AAC3B,UAAQ,KAAK,WAAW"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const debugHmr: unknown;
|
|
2
|
+
export declare const debugStyles: unknown;
|
|
3
|
+
export declare const debugCompiler: unknown;
|
|
4
|
+
export declare const debugCompilationApi: unknown;
|
|
5
|
+
export declare const debugTailwind: unknown;
|
|
6
|
+
export type DebugScope = "analog:angular:*" | "analog:angular:hmr" | "analog:angular:styles" | "analog:angular:compiler" | "analog:angular:compilation-api" | "analog:angular:tailwind" | (string & {});
|
|
7
|
+
export type DebugMode = "build" | "dev";
|
|
8
|
+
export interface DebugModeOptions {
|
|
9
|
+
scopes?: boolean | DebugScope[];
|
|
10
|
+
mode?: DebugMode;
|
|
11
|
+
/**
|
|
12
|
+
* Write debug output to log files under `tmp/debug/` in the workspace root.
|
|
13
|
+
* - `true` or `'single'` — all output to `tmp/debug/analog.log`
|
|
14
|
+
* - `'scoped'` — one file per scope, e.g. `tmp/debug/analog.angular.hmr.log`
|
|
15
|
+
*/
|
|
16
|
+
logFile?: boolean | "single" | "scoped";
|
|
17
|
+
}
|
|
18
|
+
export type DebugOption = boolean | DebugScope[] | DebugModeOptions | DebugModeOptions[];
|
|
19
|
+
export declare const applyDebugOption: (debug: DebugOption | undefined, workspaceRoot?: string) => void;
|
|
20
|
+
export declare const activateDeferredDebug: (command: "build" | "serve") => void;
|
|
21
|
+
export declare const _resetDeferredDebug: () => void;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createDebugHarness } from "./debug-harness.js";
|
|
2
|
+
import { createDebug } from "obug";
|
|
3
|
+
//#region packages/vite-plugin-angular/src/lib/utils/debug.ts
|
|
4
|
+
var debugHmr = createDebug("analog:angular:hmr");
|
|
5
|
+
var debugStyles = createDebug("analog:angular:styles");
|
|
6
|
+
var debugCompiler = createDebug("analog:angular:compiler");
|
|
7
|
+
var debugCompilationApi = createDebug("analog:angular:compilation-api");
|
|
8
|
+
var debugTailwind = createDebug("analog:angular:tailwind");
|
|
9
|
+
var harness = createDebugHarness({
|
|
10
|
+
fallbackNamespace: "analog:angular:*",
|
|
11
|
+
instanceGroups: [[
|
|
12
|
+
debugHmr,
|
|
13
|
+
debugStyles,
|
|
14
|
+
debugCompiler,
|
|
15
|
+
debugCompilationApi,
|
|
16
|
+
debugTailwind
|
|
17
|
+
]]
|
|
18
|
+
});
|
|
19
|
+
var applyDebugOption = harness.applyDebugOption;
|
|
20
|
+
var activateDeferredDebug = harness.activateDeferredDebug;
|
|
21
|
+
harness._resetDeferredDebug;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { activateDeferredDebug, applyDebugOption, debugCompilationApi, debugCompiler, debugHmr, debugStyles, debugTailwind };
|
|
24
|
+
|
|
25
|
+
//# sourceMappingURL=debug.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug.js","names":[],"sources":["../../../../src/lib/utils/debug.ts"],"sourcesContent":["import { createDebug } from 'obug';\nimport { createDebugHarness } from './debug-harness.js';\n\nexport const debugHmr = createDebug('analog:angular:hmr');\nexport const debugStyles = createDebug('analog:angular:styles');\nexport const debugCompiler = createDebug('analog:angular:compiler');\nexport const debugCompilationApi = createDebug(\n 'analog:angular:compilation-api',\n);\nexport const debugTailwind = createDebug('analog:angular:tailwind');\n\nconst angularDebugInstances = [\n debugHmr,\n debugStyles,\n debugCompiler,\n debugCompilationApi,\n debugTailwind,\n];\n\nexport type DebugScope =\n | 'analog:angular:*'\n | 'analog:angular:hmr'\n | 'analog:angular:styles'\n | 'analog:angular:compiler'\n | 'analog:angular:compilation-api'\n | 'analog:angular:tailwind'\n | (string & {});\n\nexport type DebugMode = 'build' | 'dev';\n\nexport interface DebugModeOptions {\n scopes?: boolean | DebugScope[];\n mode?: DebugMode;\n /**\n * Write debug output to log files under `tmp/debug/` in the workspace root.\n * - `true` or `'single'` — all output to `tmp/debug/analog.log`\n * - `'scoped'` — one file per scope, e.g. `tmp/debug/analog.angular.hmr.log`\n */\n logFile?: boolean | 'single' | 'scoped';\n}\n\nexport type DebugOption =\n | boolean\n | DebugScope[]\n | DebugModeOptions\n | DebugModeOptions[];\n\nconst harness = createDebugHarness({\n fallbackNamespace: 'analog:angular:*',\n instanceGroups: [angularDebugInstances],\n});\n\nexport const applyDebugOption: (\n debug: DebugOption | undefined,\n workspaceRoot?: string,\n) => void = harness.applyDebugOption;\nexport const activateDeferredDebug: (command: 'build' | 'serve') => void =\n harness.activateDeferredDebug;\nexport const _resetDeferredDebug: () => void = harness._resetDeferredDebug;\n"],"mappings":";;;AAGA,IAAa,WAAW,YAAY,qBAAqB;AACzD,IAAa,cAAc,YAAY,wBAAwB;AAC/D,IAAa,gBAAgB,YAAY,0BAA0B;AACnE,IAAa,sBAAsB,YACjC,iCACD;AACD,IAAa,gBAAgB,YAAY,0BAA0B;AAsCnE,IAAM,UAAU,mBAAmB;CACjC,mBAAmB;CACnB,gBAAgB,CAtCY;EAC5B;EACA;EACA;EACA;EACA;EACD,CAgCwC;CACxC,CAAC;AAEF,IAAa,mBAGD,QAAQ;AACpB,IAAa,wBACX,QAAQ;AACqC,QAAQ"}
|