@analogjs/vite-plugin-angular 3.0.0-alpha.35 → 3.0.0-alpha.37

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.
Files changed (72) hide show
  1. package/README.md +22 -0
  2. package/package.json +3 -4
  3. package/src/lib/angular-jit-plugin.js +3 -0
  4. package/src/lib/angular-jit-plugin.js.map +1 -1
  5. package/src/lib/angular-vite-plugin.d.ts +12 -7
  6. package/src/lib/angular-vite-plugin.js +229 -43
  7. package/src/lib/angular-vite-plugin.js.map +1 -1
  8. package/src/lib/compiler/angular-version.d.ts +19 -0
  9. package/src/lib/compiler/angular-version.js +16 -0
  10. package/src/lib/compiler/angular-version.js.map +1 -0
  11. package/src/lib/compiler/class-field-lowering.d.ts +23 -0
  12. package/src/lib/compiler/class-field-lowering.js +131 -0
  13. package/src/lib/compiler/class-field-lowering.js.map +1 -0
  14. package/src/lib/compiler/compile.d.ts +44 -0
  15. package/src/lib/compiler/compile.js +731 -0
  16. package/src/lib/compiler/compile.js.map +1 -0
  17. package/src/lib/compiler/constants.d.ts +18 -0
  18. package/src/lib/compiler/constants.js +52 -0
  19. package/src/lib/compiler/constants.js.map +1 -0
  20. package/src/lib/compiler/debug.d.ts +22 -0
  21. package/src/lib/compiler/debug.js +20 -0
  22. package/src/lib/compiler/debug.js.map +1 -0
  23. package/src/lib/compiler/defer.d.ts +47 -0
  24. package/src/lib/compiler/defer.js +138 -0
  25. package/src/lib/compiler/defer.js.map +1 -0
  26. package/src/lib/compiler/dts-reader.d.ts +35 -0
  27. package/src/lib/compiler/dts-reader.js +365 -0
  28. package/src/lib/compiler/dts-reader.js.map +1 -0
  29. package/src/lib/compiler/hmr.d.ts +16 -0
  30. package/src/lib/compiler/hmr.js +69 -0
  31. package/src/lib/compiler/hmr.js.map +1 -0
  32. package/src/lib/compiler/index.d.ts +7 -0
  33. package/src/lib/compiler/index.js +7 -0
  34. package/src/lib/compiler/jit-metadata.d.ts +14 -0
  35. package/src/lib/compiler/jit-metadata.js +146 -0
  36. package/src/lib/compiler/jit-metadata.js.map +1 -0
  37. package/src/lib/compiler/jit-transform.d.ts +24 -0
  38. package/src/lib/compiler/jit-transform.js +200 -0
  39. package/src/lib/compiler/jit-transform.js.map +1 -0
  40. package/src/lib/compiler/js-emitter.d.ts +10 -0
  41. package/src/lib/compiler/js-emitter.js +420 -0
  42. package/src/lib/compiler/js-emitter.js.map +1 -0
  43. package/src/lib/compiler/metadata.d.ts +45 -0
  44. package/src/lib/compiler/metadata.js +633 -0
  45. package/src/lib/compiler/metadata.js.map +1 -0
  46. package/src/lib/compiler/registry.d.ts +49 -0
  47. package/src/lib/compiler/registry.js +164 -0
  48. package/src/lib/compiler/registry.js.map +1 -0
  49. package/src/lib/compiler/resource-inliner.d.ts +21 -0
  50. package/src/lib/compiler/resource-inliner.js +152 -0
  51. package/src/lib/compiler/resource-inliner.js.map +1 -0
  52. package/src/lib/compiler/style-ast.d.ts +8 -0
  53. package/src/lib/compiler/style-ast.js +54 -0
  54. package/src/lib/compiler/style-ast.js.map +1 -0
  55. package/src/lib/compiler/styles.d.ts +13 -0
  56. package/src/lib/compiler/test-helpers.d.ts +7 -0
  57. package/src/lib/compiler/type-elision.d.ts +26 -0
  58. package/src/lib/compiler/type-elision.js +211 -0
  59. package/src/lib/compiler/type-elision.js.map +1 -0
  60. package/src/lib/compiler/utils.d.ts +10 -0
  61. package/src/lib/compiler/utils.js +35 -0
  62. package/src/lib/compiler/utils.js.map +1 -0
  63. package/src/lib/{analog-compiler-plugin.d.ts → fast-compile-plugin.d.ts} +3 -3
  64. package/src/lib/{analog-compiler-plugin.js → fast-compile-plugin.js} +46 -33
  65. package/src/lib/fast-compile-plugin.js.map +1 -0
  66. package/src/lib/utils/debug.d.ts +3 -1
  67. package/src/lib/utils/debug.js +6 -2
  68. package/src/lib/utils/debug.js.map +1 -1
  69. package/src/lib/utils/virtual-resources.d.ts +16 -0
  70. package/src/lib/utils/virtual-resources.js +31 -2
  71. package/src/lib/utils/virtual-resources.js.map +1 -1
  72. package/src/lib/analog-compiler-plugin.js.map +0 -1
package/README.md CHANGED
@@ -48,6 +48,28 @@ export default defineConfig({
48
48
 
49
49
  > The `angular` plugin should be listed **first** in the plugins array.
50
50
 
51
+ ## Fast Compile Mode
52
+
53
+ `fastCompile` opts the plugin into a single-pass compilation path that emits Ivy instructions directly and skips Angular's template type-checking. It's intended for content-focused apps and faster dev iteration where build throughput matters more than inline type-safety feedback.
54
+
55
+ ```ts
56
+ export default defineConfig({
57
+ plugins: [angular({ fastCompile: true })],
58
+ });
59
+ ```
60
+
61
+ When `fastCompile` is enabled, template and input type errors will not surface during compilation — run `ngc -p tsconfig.app.json --noEmit` as a separate step in your build script to keep full type safety:
62
+
63
+ ```json
64
+ {
65
+ "scripts": {
66
+ "build": "ngc -p tsconfig.app.json --noEmit && vite build"
67
+ }
68
+ }
69
+ ```
70
+
71
+ The fast compile path currently passes ~91% of Angular's conformance suite. Behavior and output may change between minor releases.
72
+
51
73
  ## Setting up the TypeScript config
52
74
 
53
75
  The integration needs a `tsconfig.app.json` at the root of the project for compilation.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@analogjs/vite-plugin-angular",
3
- "version": "3.0.0-alpha.35",
3
+ "version": "3.0.0-alpha.37",
4
4
  "description": "Vite Plugin for Angular",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -36,8 +36,8 @@
36
36
  }
37
37
  },
38
38
  "dependencies": {
39
- "@analogjs/angular-compiler": "3.0.0-alpha.35",
40
39
  "es-toolkit": "^1.45.1",
40
+ "magic-string": "^0.30.21",
41
41
  "obug": "^2.1.1",
42
42
  "oxc-parser": "^0.124.0",
43
43
  "oxc-resolver": "^11.19.1",
@@ -65,8 +65,7 @@
65
65
  "@analogjs/storybook-angular",
66
66
  "@analogjs/vite-plugin-angular",
67
67
  "@analogjs/vite-plugin-nitro",
68
- "@analogjs/vitest-angular",
69
- "@analogjs/angular-compiler"
68
+ "@analogjs/vitest-angular"
70
69
  ],
71
70
  "migrations": "./migrations/migration.json"
72
71
  },
@@ -1,5 +1,6 @@
1
1
  import { debugStyles } from "./utils/debug.js";
2
2
  import { isTailwindReferenceError } from "./utils/tailwind-reference.js";
3
+ import { shouldPreprocessTestCss } from "./utils/virtual-resources.js";
3
4
  import { createHash } from "node:crypto";
4
5
  import { preprocessCSS } from "vite";
5
6
  //#region packages/vite-plugin-angular/src/lib/angular-jit-plugin.ts
@@ -19,6 +20,8 @@ function jitPlugin({ inlineStylesExtension }) {
19
20
  const styleIdHash = createHash("sha256").update(styleId).digest("hex").slice(0, 16);
20
21
  const decodedStyles = Buffer.from(decodeURIComponent(styleId), "base64").toString();
21
22
  let styles = "";
23
+ const inlineStyleId = `${styleIdHash}.${inlineStylesExtension}`;
24
+ if (!shouldPreprocessTestCss(config, inlineStyleId)) return `export default \`\``;
22
25
  try {
23
26
  styles = (await preprocessCSS(decodedStyles, `${styleIdHash}.${inlineStylesExtension}?direct`, config))?.code;
24
27
  } catch (e) {
@@ -1 +1 @@
1
- {"version":3,"file":"angular-jit-plugin.js","names":[],"sources":["../../../src/lib/angular-jit-plugin.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { Plugin, ResolvedConfig, preprocessCSS } from 'vite';\nimport { debugStyles } from './utils/debug.js';\nimport { isTailwindReferenceError } from './utils/tailwind-reference.js';\n\nexport function jitPlugin({\n inlineStylesExtension,\n}: {\n inlineStylesExtension: string;\n}): Plugin {\n let config: ResolvedConfig;\n\n return {\n name: '@analogjs/vite-plugin-angular-jit',\n configResolved(_config) {\n config = _config;\n },\n resolveId(id: string) {\n if (id.startsWith('virtual:angular')) {\n return `\\0${id}`;\n }\n\n return;\n },\n async load(id: string) {\n if (id.includes('virtual:angular:jit:style:inline;')) {\n const styleId = id.split('style:inline;')[1];\n // styleId may exceed 255 bytes of base64-encoded content, limit to 16\n const styleIdHash = createHash('sha256')\n .update(styleId)\n .digest('hex')\n .slice(0, 16);\n\n const decodedStyles = Buffer.from(\n decodeURIComponent(styleId),\n 'base64',\n ).toString();\n\n let styles: string | undefined = '';\n\n try {\n const compiled = await preprocessCSS(\n decodedStyles,\n `${styleIdHash}.${inlineStylesExtension}?direct`,\n config,\n );\n styles = compiled?.code;\n } catch (e) {\n if (isTailwindReferenceError(e)) {\n throw e;\n }\n const errorMessage = e instanceof Error ? e.message : String(e);\n debugStyles('jit css compilation error', {\n styleIdHash,\n error: errorMessage,\n });\n console.warn(\n '[@analogjs/vite-plugin-angular]: Failed to preprocess inline JIT stylesheet %s. Returning an empty stylesheet instead. %s',\n styleIdHash,\n errorMessage,\n );\n }\n\n return `export default \\`${styles}\\``;\n }\n\n return;\n },\n };\n}\n"],"mappings":";;;;;AAKA,SAAgB,UAAU,EACxB,yBAGS;CACT,IAAI;AAEJ,QAAO;EACL,MAAM;EACN,eAAe,SAAS;AACtB,YAAS;;EAEX,UAAU,IAAY;AACpB,OAAI,GAAG,WAAW,kBAAkB,CAClC,QAAO,KAAK;;EAKhB,MAAM,KAAK,IAAY;AACrB,OAAI,GAAG,SAAS,oCAAoC,EAAE;IACpD,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC;IAE1C,MAAM,cAAc,WAAW,SAAS,CACrC,OAAO,QAAQ,CACf,OAAO,MAAM,CACb,MAAM,GAAG,GAAG;IAEf,MAAM,gBAAgB,OAAO,KAC3B,mBAAmB,QAAQ,EAC3B,SACD,CAAC,UAAU;IAEZ,IAAI,SAA6B;AAEjC,QAAI;AAMF,eALiB,MAAM,cACrB,eACA,GAAG,YAAY,GAAG,sBAAsB,UACxC,OACD,GACkB;aACZ,GAAG;AACV,SAAI,yBAAyB,EAAE,CAC7B,OAAM;KAER,MAAM,eAAe,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;AAC/D,iBAAY,6BAA6B;MACvC;MACA,OAAO;MACR,CAAC;AACF,aAAQ,KACN,6HACA,aACA,aACD;;AAGH,WAAO,oBAAoB,OAAO;;;EAKvC"}
1
+ {"version":3,"file":"angular-jit-plugin.js","names":[],"sources":["../../../src/lib/angular-jit-plugin.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { Plugin, ResolvedConfig, preprocessCSS } from 'vite';\nimport { debugStyles } from './utils/debug.js';\nimport { isTailwindReferenceError } from './utils/tailwind-reference.js';\n\nimport { shouldPreprocessTestCss } from './utils/virtual-resources.js';\n\nexport function jitPlugin({\n inlineStylesExtension,\n}: {\n inlineStylesExtension: string;\n}): Plugin {\n let config: ResolvedConfig;\n\n return {\n name: '@analogjs/vite-plugin-angular-jit',\n configResolved(_config) {\n config = _config;\n },\n resolveId(id: string) {\n if (id.startsWith('virtual:angular')) {\n return `\\0${id}`;\n }\n\n return;\n },\n async load(id: string) {\n if (id.includes('virtual:angular:jit:style:inline;')) {\n const styleId = id.split('style:inline;')[1];\n // styleId may exceed 255 bytes of base64-encoded content, limit to 16\n const styleIdHash = createHash('sha256')\n .update(styleId)\n .digest('hex')\n .slice(0, 16);\n\n const decodedStyles = Buffer.from(\n decodeURIComponent(styleId),\n 'base64',\n ).toString();\n\n let styles: string | undefined = '';\n\n // In tests, mirror Vitest's `test.css` rules — defaults to no\n // preprocessing (matches Vite's CSS pipeline behavior). Inline\n // component styles have no real file path to match include/exclude\n // patterns against, so only `test.css: true` opts them in. (#2297)\n const inlineStyleId = `${styleIdHash}.${inlineStylesExtension}`;\n if (!shouldPreprocessTestCss(config, inlineStyleId)) {\n return `export default \\`\\``;\n }\n\n try {\n const compiled = await preprocessCSS(\n decodedStyles,\n `${styleIdHash}.${inlineStylesExtension}?direct`,\n config,\n );\n styles = compiled?.code;\n } catch (e) {\n if (isTailwindReferenceError(e)) {\n throw e;\n }\n const errorMessage = e instanceof Error ? e.message : String(e);\n debugStyles('jit css compilation error', {\n styleIdHash,\n error: errorMessage,\n });\n console.warn(\n '[@analogjs/vite-plugin-angular]: Failed to preprocess inline JIT stylesheet %s. Returning an empty stylesheet instead. %s',\n styleIdHash,\n errorMessage,\n );\n }\n\n return `export default \\`${styles}\\``;\n }\n\n return;\n },\n };\n}\n"],"mappings":";;;;;;AAOA,SAAgB,UAAU,EACxB,yBAGS;CACT,IAAI;AAEJ,QAAO;EACL,MAAM;EACN,eAAe,SAAS;AACtB,YAAS;;EAEX,UAAU,IAAY;AACpB,OAAI,GAAG,WAAW,kBAAkB,CAClC,QAAO,KAAK;;EAKhB,MAAM,KAAK,IAAY;AACrB,OAAI,GAAG,SAAS,oCAAoC,EAAE;IACpD,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC;IAE1C,MAAM,cAAc,WAAW,SAAS,CACrC,OAAO,QAAQ,CACf,OAAO,MAAM,CACb,MAAM,GAAG,GAAG;IAEf,MAAM,gBAAgB,OAAO,KAC3B,mBAAmB,QAAQ,EAC3B,SACD,CAAC,UAAU;IAEZ,IAAI,SAA6B;IAMjC,MAAM,gBAAgB,GAAG,YAAY,GAAG;AACxC,QAAI,CAAC,wBAAwB,QAAQ,cAAc,CACjD,QAAO;AAGT,QAAI;AAMF,eALiB,MAAM,cACrB,eACA,GAAG,YAAY,GAAG,sBAAsB,UACxC,OACD,GACkB;aACZ,GAAG;AACV,SAAI,yBAAyB,EAAE,CAC7B,OAAM;KAER,MAAM,eAAe,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;AAC/D,iBAAY,6BAA6B;MACvC;MACA,OAAO;MACR,CAAC;AACF,aAAQ,KACN,6HACA,aACA,aACD;;AAGH,WAAO,oBAAoB,OAAO;;;EAKvC"}
@@ -44,15 +44,20 @@ export interface PluginOptions {
44
44
  liveReload?: boolean;
45
45
  disableTypeChecking?: boolean;
46
46
  fileReplacements?: FileReplacement[];
47
+ /**
48
+ * Opt into the fast compile path. Skips Angular's template type-checking
49
+ * and routes compilation through an internal single-pass transform.
50
+ * Defaults to `false`.
51
+ */
52
+ fastCompile?: boolean;
53
+ /**
54
+ * Compilation output mode used when `fastCompile` is enabled.
55
+ * - `'full'` (default): Emit final Ivy definitions for application builds.
56
+ * - `'partial'`: Emit partial declarations for library publishing.
57
+ */
58
+ fastCompileMode?: "full" | "partial";
47
59
  experimental?: {
48
60
  useAngularCompilationAPI?: boolean;
49
- useAnalogCompiler?: boolean;
50
- /**
51
- * Compilation output mode for the Analog compiler.
52
- * - `'full'` (default): Emit final Ivy definitions for application builds.
53
- * - `'partial'`: Emit partial declarations for library publishing.
54
- */
55
- analogCompilationMode?: "full" | "partial";
56
61
  };
57
62
  /**
58
63
  * Enable debug logging for specific scopes.
@@ -1,8 +1,10 @@
1
1
  import { angularFullVersion, cjt, createAngularCompilation, sourceFileCache } from "./utils/devkit.js";
2
2
  import { getJsTransformConfigKey, isRolldown } from "./utils/rolldown.js";
3
3
  import { buildOptimizerPlugin } from "./angular-build-optimizer-plugin.js";
4
- import { activateDeferredDebug, applyDebugOption, debugCompilationApi, debugCompiler, debugCompilerV, debugHmr, debugHmrV, debugStyles, debugStylesV, debugTailwind, debugTailwindV } from "./utils/debug.js";
4
+ import { activateDeferredDebug, applyDebugOption, debugCompilationApi, debugCompiler, debugCompilerV, debugEmit, debugEmitV, debugHmr, debugHmrV, debugStyles, debugStylesV, debugTailwind, debugTailwindV } from "./utils/debug.js";
5
5
  import { inspectCssTailwindDirectives, isTailwindReferenceError, throwTailwindReferenceTextError } from "./utils/tailwind-reference.js";
6
+ import { toVirtualRawId, toVirtualStyleId } from "./utils/virtual-ids.js";
7
+ import { loadVirtualRawModule, loadVirtualStyleModule } from "./utils/virtual-resources.js";
6
8
  import { jitPlugin } from "./angular-jit-plugin.js";
7
9
  import { createCompilerPlugin, createRolldownCompilerPlugin } from "./compiler-plugin.js";
8
10
  import { StyleUrlsResolver, TemplateUrlsResolver, getAngularComponentMetadata } from "./component-resolvers.js";
@@ -10,9 +12,7 @@ import { composeStylePreprocessors, normalizeStylesheetDependencies } from "./st
10
12
  import { AnalogStylesheetRegistry, preprocessStylesheet, preprocessStylesheetResult, registerStylesheetContent, rewriteRelativeCssImports } from "./stylesheet-registry.js";
11
13
  import { augmentHostWithCaching, augmentHostWithResources, augmentProgramWithVersioning, mergeTransformers } from "./host.js";
12
14
  import { TS_EXT_REGEX, createTsConfigGetter, getTsConfigPath } from "./utils/plugin-config.js";
13
- import { toVirtualRawId, toVirtualStyleId } from "./utils/virtual-ids.js";
14
- import { loadVirtualRawModule, loadVirtualStyleModule } from "./utils/virtual-resources.js";
15
- import { analogCompilerPlugin } from "./analog-compiler-plugin.js";
15
+ import { fastCompilePlugin } from "./fast-compile-plugin.js";
16
16
  import { angularVitestPlugins } from "./angular-vitest-plugin.js";
17
17
  import { pendingTasksPlugin } from "./angular-pending-tasks.plugin.js";
18
18
  import { liveReloadPlugin } from "./live-reload-plugin.js";
@@ -135,6 +135,8 @@ function angular(options) {
135
135
  disableTypeChecking: options?.disableTypeChecking ?? true,
136
136
  fileReplacements: options?.fileReplacements ?? [],
137
137
  useAngularCompilationAPI: options?.experimental?.useAngularCompilationAPI ?? false,
138
+ fastCompile: options?.fastCompile ?? false,
139
+ fastCompileMode: options?.fastCompileMode ?? "full",
138
140
  hasTailwindCss: !!options?.tailwindCss,
139
141
  tailwindCss: options?.tailwindCss,
140
142
  stylePreprocessor: buildStylePreprocessor(options)
@@ -145,6 +147,7 @@ function angular(options) {
145
147
  let builder;
146
148
  let nextProgram;
147
149
  const tsconfigOptionsCache = /* @__PURE__ */ new Map();
150
+ const tsconfigGraphRootCache = /* @__PURE__ */ new Map();
148
151
  let cachedHost;
149
152
  let cachedHostKey;
150
153
  let includeCache = [];
@@ -153,6 +156,7 @@ function angular(options) {
153
156
  }
154
157
  function invalidateTsconfigCaches() {
155
158
  tsconfigOptionsCache.clear();
159
+ tsconfigGraphRootCache.clear();
156
160
  cachedHost = void 0;
157
161
  cachedHostKey = void 0;
158
162
  }
@@ -325,9 +329,36 @@ function angular(options) {
325
329
  const templateUrlsResolver = new TemplateUrlsResolver();
326
330
  let outputFile;
327
331
  const outputFiles = /* @__PURE__ */ new Map();
332
+ const normalizeEmitterLookupId = (file) => {
333
+ const normalizedFile = normalizePath(file);
334
+ if (!normalizedFile.startsWith("/@fs/")) return normalizedFile;
335
+ return normalizePath(normalizedFile.slice(4).replace(/^\/([A-Za-z]:\/)/, "$1"));
336
+ };
337
+ const describeEmitMarkers = (content) => ({
338
+ contentLength: content.length,
339
+ hasCmp: content.includes("ɵcmp"),
340
+ hasFac: content.includes("ɵfac"),
341
+ hasProv: content.includes("ɵprov"),
342
+ hasDecorate: content.includes("__decorate"),
343
+ hasMetadata: content.includes("__metadata")
344
+ });
328
345
  const fileEmitter = (file) => {
329
- outputFile?.(file);
330
- return outputFiles.get(normalizePath(file));
346
+ const normalizedFile = normalizeEmitterLookupId(file);
347
+ const hadCachedEmit = outputFiles.has(normalizedFile);
348
+ outputFile?.(normalizedFile);
349
+ const emittedResult = outputFiles.get(normalizedFile);
350
+ debugEmitV("fileEmitter lookup", {
351
+ requestFile: file,
352
+ normalizedFile,
353
+ hadCachedEmit,
354
+ hasOutputFileHook: !!outputFile,
355
+ emitted: !!emittedResult,
356
+ knownOutputCount: outputFiles.size,
357
+ contentLength: emittedResult?.content?.length ?? 0,
358
+ errorCount: emittedResult?.errors?.length ?? 0,
359
+ warningCount: emittedResult?.warnings?.length ?? 0
360
+ });
361
+ return emittedResult;
331
362
  };
332
363
  let initialCompilation = false;
333
364
  const declarationFiles = [];
@@ -890,12 +921,27 @@ function angular(options) {
890
921
  const typescriptResult = fileEmitter(id);
891
922
  if (!typescriptResult) {
892
923
  debugCompilerV("transform skip (file not emitted by Angular)", { id });
893
- if (!id.includes("@ng/component") && /(Component|Directive|Pipe|Injectable|NgModule)\(/.test(code)) this.warn(`[@analogjs/vite-plugin-angular]: "${id}" contains Angular decorators but is not in the TypeScript program. Ensure it is included in your tsconfig.`);
924
+ const isAngular = !id.includes("@ng/component") && /(Component|Directive|Pipe|Injectable|NgModule)\(/.test(code);
925
+ debugEmit("transform emit miss", {
926
+ id,
927
+ normalizedId: normalizeEmitterLookupId(id),
928
+ knownOutputCount: outputFiles.size,
929
+ hasOutputFileHook: !!outputFile,
930
+ isAngular
931
+ });
932
+ if (isAngular) this.warn(`[@analogjs/vite-plugin-angular]: "${id}" contains Angular decorators but is not in the TypeScript program. Ensure it is included in your tsconfig.`);
894
933
  return;
895
934
  }
896
935
  if (typescriptResult.warnings && typescriptResult.warnings.length > 0) this.warn(`${typescriptResult.warnings.join("\n")}`);
897
936
  if (typescriptResult.errors && typescriptResult.errors.length > 0) this.error(`${typescriptResult.errors.join("\n")}`);
898
937
  let data = typescriptResult.content ?? "";
938
+ debugEmitV("transform emit hit", {
939
+ id,
940
+ normalizedId: normalizeEmitterLookupId(id),
941
+ ...describeEmitMarkers(data),
942
+ errorCount: typescriptResult.errors?.length ?? 0,
943
+ warningCount: typescriptResult.warnings?.length ?? 0
944
+ });
899
945
  if (jit && data.includes("angular:jit:")) {
900
946
  data = data.replace(/angular:jit:style:inline;/g, "virtual:angular:jit:style:inline;");
901
947
  templateUrls.forEach((templateUrlSet) => {
@@ -936,7 +982,7 @@ function angular(options) {
936
982
  }
937
983
  };
938
984
  }
939
- pluginOptions.useAnalogCompiler ? analogCompilerPlugin({
985
+ pluginOptions.fastCompile ? fastCompilePlugin({
940
986
  tsconfigGetter: pluginOptions.tsconfigGetter,
941
987
  workspaceRoot: pluginOptions.workspaceRoot,
942
988
  inlineStylesExtension: pluginOptions.inlineStylesExtension,
@@ -946,7 +992,7 @@ function angular(options) {
946
992
  transformFilter: options?.transformFilter,
947
993
  isTest,
948
994
  isAstroIntegration,
949
- analogCompilationMode: pluginOptions.analogCompilationMode
995
+ fastCompileMode: pluginOptions.fastCompileMode
950
996
  }) : angularPlugin();
951
997
  return [
952
998
  replaceFiles(pluginOptions.fileReplacements, pluginOptions.workspaceRoot),
@@ -1064,13 +1110,26 @@ function angular(options) {
1064
1110
  nxFolderPlugin()
1065
1111
  ].filter(Boolean);
1066
1112
  function findIncludes() {
1067
- return globSync(pluginOptions.include.map((glob) => normalizeIncludeGlob(pluginOptions.workspaceRoot, glob)), {
1113
+ const globs = pluginOptions.include.map((glob) => normalizeIncludeGlob(pluginOptions.workspaceRoot, glob));
1114
+ const files = globSync(globs, {
1068
1115
  dot: true,
1069
1116
  absolute: true
1070
1117
  });
1118
+ debugEmit("include discovery", {
1119
+ patternCount: globs.length,
1120
+ fileCount: files.length
1121
+ });
1122
+ debugEmitV("include discovery files", {
1123
+ globs,
1124
+ files: files.map((file) => normalizePath(file))
1125
+ });
1126
+ return files;
1071
1127
  }
1072
1128
  function ensureIncludeCache() {
1073
- if (pluginOptions.include.length > 0 && includeCache.length === 0) includeCache = findIncludes();
1129
+ if (pluginOptions.include.length > 0 && includeCache.length === 0) {
1130
+ includeCache = findIncludes();
1131
+ debugEmit("include cache populated", { fileCount: includeCache.length });
1132
+ }
1074
1133
  return includeCache;
1075
1134
  }
1076
1135
  function getTsconfigCacheKey(resolvedTsConfigPath, config) {
@@ -1079,45 +1138,128 @@ function angular(options) {
1079
1138
  config.mode === "production" ? "prod" : "dev",
1080
1139
  isTest ? "test" : "app",
1081
1140
  config.build?.lib ? "lib" : "nolib",
1082
- pluginOptions.hmr ? "hmr" : "nohmr",
1141
+ pluginOptions.liveReload ? "live-reload" : "no-live-reload",
1083
1142
  pluginOptions.hasTailwindCss ? "tw" : "notw"
1084
1143
  ].join("|");
1085
1144
  }
1086
- function getCachedTsconfigOptions(resolvedTsConfigPath, config) {
1145
+ function readAngularTsconfigConfiguration(resolvedTsConfigPath, config) {
1087
1146
  const isProd = config.mode === "production";
1147
+ return compilerCli.readConfiguration(resolvedTsConfigPath, {
1148
+ suppressOutputPathCheck: true,
1149
+ outDir: void 0,
1150
+ sourceMap: false,
1151
+ inlineSourceMap: !isProd,
1152
+ inlineSources: !isProd,
1153
+ declaration: false,
1154
+ declarationMap: false,
1155
+ allowEmptyCodegenFiles: false,
1156
+ annotationsAs: "decorators",
1157
+ enableResourceInlining: false,
1158
+ noEmitOnError: false,
1159
+ mapRoot: void 0,
1160
+ sourceRoot: void 0,
1161
+ supportTestBed: false,
1162
+ supportJitMode: false
1163
+ });
1164
+ }
1165
+ function getCachedTsconfigOptions(resolvedTsConfigPath, config) {
1088
1166
  const tsconfigKey = getTsconfigCacheKey(resolvedTsConfigPath, config);
1089
1167
  let cached = tsconfigOptionsCache.get(tsconfigKey);
1090
1168
  if (!cached) {
1091
- const read = compilerCli.readConfiguration(resolvedTsConfigPath, {
1092
- suppressOutputPathCheck: true,
1093
- outDir: void 0,
1094
- sourceMap: false,
1095
- inlineSourceMap: !isProd,
1096
- inlineSources: !isProd,
1097
- declaration: false,
1098
- declarationMap: false,
1099
- allowEmptyCodegenFiles: false,
1100
- annotationsAs: "decorators",
1101
- enableResourceInlining: false,
1102
- noEmitOnError: false,
1103
- mapRoot: void 0,
1104
- sourceRoot: void 0,
1105
- supportTestBed: false,
1106
- supportJitMode: false
1107
- });
1169
+ const read = readAngularTsconfigConfiguration(resolvedTsConfigPath, config);
1108
1170
  cached = {
1109
1171
  options: read.options,
1110
1172
  rootNames: read.rootNames
1111
1173
  };
1112
1174
  tsconfigOptionsCache.set(tsconfigKey, cached);
1175
+ debugEmit("tsconfig root names loaded", {
1176
+ resolvedTsConfigPath,
1177
+ rootNameCount: read.rootNames.length
1178
+ });
1179
+ debugEmitV("tsconfig root names", {
1180
+ resolvedTsConfigPath,
1181
+ rootNames: read.rootNames.map((file) => normalizePath(file))
1182
+ });
1113
1183
  }
1114
1184
  return cached;
1115
1185
  }
1186
+ function resolveReferenceTsconfigPath(referencePath, ownerTsconfigPath) {
1187
+ const ownerDir = dirname(ownerTsconfigPath);
1188
+ const resolvedReference = normalizePath(isAbsolute(referencePath) ? referencePath : resolve(ownerDir, referencePath));
1189
+ if (existsSync(resolvedReference)) {
1190
+ try {
1191
+ if (statSync(resolvedReference).isDirectory()) {
1192
+ const nestedTsconfig = join(resolvedReference, "tsconfig.json");
1193
+ return existsSync(nestedTsconfig) ? normalizePath(nestedTsconfig) : void 0;
1194
+ }
1195
+ } catch {
1196
+ return;
1197
+ }
1198
+ return resolvedReference;
1199
+ }
1200
+ if (!resolvedReference.endsWith(".json")) {
1201
+ const asJson = `${resolvedReference}.json`;
1202
+ if (existsSync(asJson)) return normalizePath(asJson);
1203
+ const nestedTsconfig = join(resolvedReference, "tsconfig.json");
1204
+ if (existsSync(nestedTsconfig)) return normalizePath(nestedTsconfig);
1205
+ }
1206
+ }
1207
+ function collectTsconfigPathRoots(resolvedTsConfigPath, options, rawTsconfig) {
1208
+ const tsPaths = rawTsconfig.compilerOptions?.paths ?? options.paths;
1209
+ if (!tsPaths) return [];
1210
+ const tsconfigDir = dirname(resolvedTsConfigPath);
1211
+ const configuredBaseUrl = typeof options.baseUrl === "string" ? options.baseUrl : typeof rawTsconfig.compilerOptions?.baseUrl === "string" ? rawTsconfig.compilerOptions.baseUrl : void 0;
1212
+ const resolvedBaseUrl = configuredBaseUrl ? isAbsolute(configuredBaseUrl) ? configuredBaseUrl : resolve(tsconfigDir, configuredBaseUrl) : tsconfigDir;
1213
+ const discoveredRoots = /* @__PURE__ */ new Set();
1214
+ for (const targets of Object.values(tsPaths)) for (const target of targets) {
1215
+ const resolvedTarget = normalizePath(isAbsolute(target) ? target : resolve(resolvedBaseUrl, target));
1216
+ if (target.includes("*")) {
1217
+ for (const match of globSync(resolvedTarget, {
1218
+ dot: true,
1219
+ absolute: true
1220
+ })) discoveredRoots.add(normalizePath(match));
1221
+ continue;
1222
+ }
1223
+ if (existsSync(resolvedTarget)) discoveredRoots.add(resolvedTarget);
1224
+ }
1225
+ return [...discoveredRoots];
1226
+ }
1227
+ function collectExpandedTsconfigRoots(resolvedTsConfigPath, config, visited = /* @__PURE__ */ new Set()) {
1228
+ const normalizedTsConfigPath = normalizePath(resolvedTsConfigPath);
1229
+ if (visited.has(normalizedTsConfigPath)) return [];
1230
+ const tsconfigKey = `${getTsconfigCacheKey(normalizedTsConfigPath, config)}|graph`;
1231
+ const cached = tsconfigGraphRootCache.get(tsconfigKey);
1232
+ if (cached) return cached;
1233
+ visited.add(normalizedTsConfigPath);
1234
+ const read = readAngularTsconfigConfiguration(normalizedTsConfigPath, config);
1235
+ const rawTsconfig = ts.readConfigFile(normalizedTsConfigPath, ts.sys.readFile).config ?? {};
1236
+ const expandedRoots = new Set(read.rootNames.map((file) => normalizePath(file)));
1237
+ const pathRoots = collectTsconfigPathRoots(normalizedTsConfigPath, read.options, rawTsconfig);
1238
+ for (const pathRoot of pathRoots) expandedRoots.add(pathRoot);
1239
+ const referenceConfigs = (rawTsconfig.references ?? []).flatMap((reference) => typeof reference.path === "string" ? [resolveReferenceTsconfigPath(reference.path, normalizedTsConfigPath)] : []).filter((reference) => !!reference);
1240
+ for (const referenceConfig of referenceConfigs) for (const referenceRoot of collectExpandedTsconfigRoots(referenceConfig, config, visited)) expandedRoots.add(referenceRoot);
1241
+ const expandedRootList = [...expandedRoots];
1242
+ tsconfigGraphRootCache.set(tsconfigKey, expandedRootList);
1243
+ debugEmit("expanded tsconfig graph roots", {
1244
+ resolvedTsConfigPath: normalizedTsConfigPath,
1245
+ directRootNameCount: read.rootNames.length,
1246
+ pathRootCount: pathRoots.length,
1247
+ referenceConfigCount: referenceConfigs.length,
1248
+ expandedRootCount: expandedRootList.length
1249
+ });
1250
+ debugEmitV("expanded tsconfig graph root files", {
1251
+ resolvedTsConfigPath: normalizedTsConfigPath,
1252
+ pathRoots,
1253
+ referenceConfigs,
1254
+ rootNames: expandedRootList
1255
+ });
1256
+ return expandedRootList;
1257
+ }
1116
1258
  function resolveCompilationApiTsConfigPath(resolvedTsConfigPath, config) {
1117
1259
  const includedFiles = ensureIncludeCache();
1118
- if (includedFiles.length === 0) return resolvedTsConfigPath;
1119
1260
  const cached = getCachedTsconfigOptions(resolvedTsConfigPath, config);
1120
- const mergedRootNames = union(cached.rootNames, includedFiles).map((file) => normalizePath(file));
1261
+ const expandedGraphRoots = collectExpandedTsconfigRoots(resolvedTsConfigPath, config);
1262
+ const mergedRootNames = union(cached.rootNames, expandedGraphRoots, includedFiles).map((file) => normalizePath(file));
1121
1263
  if (mergedRootNames.length === cached.rootNames.length) return resolvedTsConfigPath;
1122
1264
  const wrapperDir = join(isAbsolute(config.cacheDir) ? config.cacheDir : resolve(config.root, config.cacheDir), "analog-angular", "compilation-api");
1123
1265
  const rawTsconfig = ts.readConfigFile(resolvedTsConfigPath, ts.sys.readFile).config ?? {};
@@ -1135,6 +1277,19 @@ function angular(options) {
1135
1277
  includeCount: includedFiles.length,
1136
1278
  rootNameCount: mergedRootNames.length
1137
1279
  });
1280
+ debugEmit("wrapper tsconfig root merge", {
1281
+ originalTsconfig: resolvedTsConfigPath,
1282
+ wrapperTsconfig: wrapperPath,
1283
+ baseRootNameCount: cached.rootNames.length,
1284
+ expandedGraphRootCount: expandedGraphRoots.length,
1285
+ includeCount: includedFiles.length,
1286
+ mergedRootNameCount: mergedRootNames.length,
1287
+ referenceCount: rawTsconfig.references?.length ?? 0
1288
+ });
1289
+ debugEmitV("wrapper tsconfig root names", {
1290
+ wrapperTsconfig: wrapperPath,
1291
+ rootNames: mergedRootNames
1292
+ });
1138
1293
  return wrapperPath;
1139
1294
  }
1140
1295
  function resolveTsConfigPath() {
@@ -1157,15 +1312,21 @@ function angular(options) {
1157
1312
  * file-level HMR metadata (`hmrUpdateCode`, `hmrEligible`, `classNames`).
1158
1313
  */
1159
1314
  async function performAngularCompilation(config, ids) {
1160
- angularCompilation ??= await createAngularCompilation(!!pluginOptions.jit, false);
1315
+ const compilation = angularCompilation ??= await createAngularCompilation(!!pluginOptions.jit, false);
1161
1316
  const modifiedFiles = ids?.length ? new Set(ids.map((file) => normalizePath(file))) : void 0;
1162
1317
  if (modifiedFiles?.size) sourceFileCache$1.invalidate(modifiedFiles);
1163
- if (modifiedFiles?.size && angularCompilation.update) {
1318
+ if (modifiedFiles?.size && compilation.update) {
1164
1319
  debugCompilationApi("incremental update", { files: [...modifiedFiles] });
1165
- await angularCompilation.update(modifiedFiles);
1320
+ await compilation.update(modifiedFiles);
1166
1321
  }
1167
- const compilationApiTsConfigPath = resolveCompilationApiTsConfigPath(resolveTsConfigPath(), config);
1168
- const compilationResult = await angularCompilation.initialize(compilationApiTsConfigPath, {
1322
+ const resolvedTsConfigPath = resolveTsConfigPath();
1323
+ const compilationApiTsConfigPath = resolveCompilationApiTsConfigPath(resolvedTsConfigPath, config);
1324
+ debugEmit("compilation initialize", {
1325
+ resolvedTsConfigPath,
1326
+ compilationApiTsConfigPath,
1327
+ modifiedFileCount: modifiedFiles?.size ?? 0
1328
+ });
1329
+ const compilationResult = await compilation.initialize(compilationApiTsConfigPath, {
1169
1330
  fileReplacements: toAngularCompilationFileReplacements(pluginOptions.fileReplacements, pluginOptions.workspaceRoot),
1170
1331
  modifiedFiles,
1171
1332
  async transformStylesheet(data, containingFile, resourceFile, order, className) {
@@ -1246,7 +1407,6 @@ function angular(options) {
1246
1407
  tsCompilerOptions["supportTestBed"] = true;
1247
1408
  tsCompilerOptions["supportJitMode"] = true;
1248
1409
  }
1249
- if (angularFullVersion >= 2e5) tsCompilerOptions["_enableSelectorless"] = true;
1250
1410
  if (!isTest && config.build?.lib) {
1251
1411
  tsCompilerOptions["declaration"] = true;
1252
1412
  tsCompilerOptions["declarationMap"] = watchMode;
@@ -1266,7 +1426,7 @@ function angular(options) {
1266
1426
  skipped: 0,
1267
1427
  errors: 0
1268
1428
  };
1269
- compilationResult.externalStylesheets?.forEach((value, key) => {
1429
+ for (const [key, value] of compilationResult.externalStylesheets ?? []) {
1270
1430
  preprocessStats.total++;
1271
1431
  const angularHash = `${value}.css`;
1272
1432
  stylesheetRegistry?.registerExternalRequest(angularHash, key);
@@ -1336,17 +1496,28 @@ function angular(options) {
1336
1496
  filename: angularHash,
1337
1497
  resolvedPath: key
1338
1498
  });
1339
- });
1499
+ }
1340
1500
  debugStyles("external stylesheet preprocessing complete", preprocessStats);
1341
- const diagnostics = await angularCompilation.diagnoseFiles(pluginOptions.disableTypeChecking ? DiagnosticModes.All & ~DiagnosticModes.Semantic : DiagnosticModes.All);
1501
+ const diagnostics = await compilation.diagnoseFiles(pluginOptions.disableTypeChecking ? DiagnosticModes.All & ~DiagnosticModes.Semantic : DiagnosticModes.All);
1342
1502
  const errors = diagnostics.errors?.length ? diagnostics.errors : [];
1343
1503
  const warnings = diagnostics.warnings?.length ? diagnostics.warnings : [];
1504
+ debugEmit("compilation diagnostics", {
1505
+ errorCount: errors.length,
1506
+ warningCount: warnings.length
1507
+ });
1344
1508
  const templateUpdates = mapTemplateUpdatesToFiles(compilationResult.templateUpdates);
1345
1509
  if (templateUpdates.size > 0) debugHmr("compilation API template updates", {
1346
1510
  count: templateUpdates.size,
1347
1511
  files: [...templateUpdates.keys()]
1348
1512
  });
1349
- for (const file of await angularCompilation.emitAffectedFiles()) {
1513
+ const affectedFiles = await compilation.emitAffectedFiles();
1514
+ debugEmit("emitAffectedFiles summary", {
1515
+ count: affectedFiles.length,
1516
+ templateUpdateCount: templateUpdates.size,
1517
+ knownOutputCountBefore: outputFiles.size
1518
+ });
1519
+ debugEmitV("emitAffectedFiles files", { files: affectedFiles.map((file) => normalizePath(file.filename)) });
1520
+ for (const file of affectedFiles) {
1350
1521
  const normalizedFilename = normalizePath(file.filename);
1351
1522
  const templateUpdate = templateUpdates.get(normalizedFilename);
1352
1523
  if (templateUpdate) classNames.set(normalizedFilename, templateUpdate.className);
@@ -1358,6 +1529,14 @@ function angular(options) {
1358
1529
  hmrUpdateCode: templateUpdate?.code,
1359
1530
  hmrEligible: !!templateUpdate?.code
1360
1531
  });
1532
+ debugEmitV("registered compilation API output", {
1533
+ filename: normalizedFilename,
1534
+ ...describeEmitMarkers(file.contents),
1535
+ hasTemplateUpdate: !!templateUpdate,
1536
+ errorCount: errors.length,
1537
+ warningCount: warnings.length,
1538
+ knownOutputCount: outputFiles.size
1539
+ });
1361
1540
  }
1362
1541
  }
1363
1542
  async function performCompilation(config, ids) {
@@ -1406,7 +1585,6 @@ function angular(options) {
1406
1585
  tsCompilerOptions["supportTestBed"] = true;
1407
1586
  tsCompilerOptions["supportJitMode"] = true;
1408
1587
  }
1409
- if (angularFullVersion >= 2e5) tsCompilerOptions["_enableSelectorless"] = true;
1410
1588
  if (!isTest && config.build?.lib) {
1411
1589
  tsCompilerOptions["declaration"] = true;
1412
1590
  tsCompilerOptions["declarationMap"] = watchMode;
@@ -1481,6 +1659,14 @@ function angular(options) {
1481
1659
  hmrUpdateCode: metadata.hmrUpdateCode,
1482
1660
  hmrEligible: metadata.hmrEligible
1483
1661
  });
1662
+ debugEmitV("registered ngtsc output", {
1663
+ filename,
1664
+ ...describeEmitMarkers(content),
1665
+ errorCount: metadata.errors?.length ?? 0,
1666
+ warningCount: metadata.warnings?.length ?? 0,
1667
+ hmrEligible: !!metadata.hmrEligible,
1668
+ knownOutputCount: outputFiles.size
1669
+ });
1484
1670
  };
1485
1671
  const writeOutputFile = (id) => {
1486
1672
  const sourceFile = builder.getSourceFile(id);