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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -89,3 +89,9 @@ Create a `tsconfig.app.json` in the root of the project.
89
89
  "include": ["src/**/*.ts"]
90
90
  }
91
91
  ```
92
+
93
+ ## Tailwind CSS v4
94
+
95
+ For Angular component styles that use Tailwind utilities like `@apply`, configure `tailwindCss.rootStylesheet` and follow the Tailwind guide for Analog:
96
+
97
+ - https://analogjs.org/docs/integrations/tailwind
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@analogjs/vite-plugin-angular",
3
- "version": "3.0.0-alpha.33",
3
+ "version": "3.0.0-alpha.35",
4
4
  "description": "Vite Plugin for Angular",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -36,7 +36,7 @@
36
36
  }
37
37
  },
38
38
  "dependencies": {
39
- "@analogjs/angular-compiler": "3.0.0-alpha.33",
39
+ "@analogjs/angular-compiler": "3.0.0-alpha.35",
40
40
  "es-toolkit": "^1.45.1",
41
41
  "obug": "^2.1.1",
42
42
  "oxc-parser": "^0.124.0",
@@ -1,4 +1,5 @@
1
1
  import { debugStyles } from "./utils/debug.js";
2
+ import { isTailwindReferenceError } from "./utils/tailwind-reference.js";
2
3
  import { createHash } from "node:crypto";
3
4
  import { preprocessCSS } from "vite";
4
5
  //#region packages/vite-plugin-angular/src/lib/angular-jit-plugin.ts
@@ -21,6 +22,7 @@ function jitPlugin({ inlineStylesExtension }) {
21
22
  try {
22
23
  styles = (await preprocessCSS(decodedStyles, `${styleIdHash}.${inlineStylesExtension}?direct`, config))?.code;
23
24
  } catch (e) {
25
+ if (isTailwindReferenceError(e)) throw e;
24
26
  const errorMessage = e instanceof Error ? e.message : String(e);
25
27
  debugStyles("jit css compilation error", {
26
28
  styleIdHash,
@@ -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';\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 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":";;;;AAIA,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;KACV,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\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"}
@@ -32,14 +32,14 @@ export interface PluginOptions {
32
32
  include?: string[];
33
33
  additionalContentDirs?: string[];
34
34
  /**
35
- * Enables Angular's HMR during development/watch mode.
35
+ * Enables Analog's Angular live-reload/HMR pipeline during development/watch mode.
36
36
  *
37
- * Defaults to `true` for watch mode. Set to `false` to disable HMR while
38
- * keeping other stylesheet externalization behavior available when needed.
39
- */
40
- hmr?: boolean;
41
- /**
42
- * @deprecated Use `hmr` instead. Kept as a compatibility alias.
37
+ * This is separate from Vite's `server.hmr` option, which configures the
38
+ * HMR client transport.
39
+ *
40
+ * Defaults to `true` for watch mode. Set to `false` to disable Angular
41
+ * reload updates while keeping other stylesheet externalization behavior
42
+ * available when needed.
43
43
  */
44
44
  liveReload?: boolean;
45
45
  disableTypeChecking?: boolean;
@@ -160,6 +160,20 @@ export declare function evictDeletedFileMetadata(file: string, { removeActiveGra
160
160
  }): void;
161
161
  export declare function injectViteIgnoreForHmrMetadata(code: string): string;
162
162
  export declare function isIgnoredHmrFile(file: string): boolean;
163
+ /**
164
+ * Builds a resolved stylePreprocessor function from plugin options.
165
+ *
166
+ * When `tailwindCss` is configured, creates an injector that prepends
167
+ * `@reference "<rootStylesheet>"` into component CSS that uses Tailwind
168
+ * utilities. Uses absolute paths because Angular's externalRuntimeStyles
169
+ * serves component CSS as virtual modules (hash-based IDs) with no
170
+ * meaningful directory — relative paths can't resolve from a hash.
171
+ *
172
+ * If both `tailwindCss` and `stylePreprocessor` are provided, they are
173
+ * chained: Tailwind reference injection runs first, then the user's
174
+ * custom preprocessor.
175
+ */
176
+ export declare function buildStylePreprocessor(options?: PluginOptions): StylePreprocessor | undefined;
163
177
  export declare function angular(options?: PluginOptions): Plugin[];
164
178
  export declare function createFsWatcherCacheInvalidator(invalidateFsCaches: () => void, invalidateTsconfigCaches: () => void, performCompilation: () => Promise<void>): () => Promise<void>;
165
179
  /**
@@ -2,6 +2,7 @@ import { angularFullVersion, cjt, createAngularCompilation, sourceFileCache } fr
2
2
  import { getJsTransformConfigKey, isRolldown } from "./utils/rolldown.js";
3
3
  import { buildOptimizerPlugin } from "./angular-build-optimizer-plugin.js";
4
4
  import { activateDeferredDebug, applyDebugOption, debugCompilationApi, debugCompiler, debugCompilerV, debugHmr, debugHmrV, debugStyles, debugStylesV, debugTailwind, debugTailwindV } from "./utils/debug.js";
5
+ import { inspectCssTailwindDirectives, isTailwindReferenceError, throwTailwindReferenceTextError } from "./utils/tailwind-reference.js";
5
6
  import { jitPlugin } from "./angular-jit-plugin.js";
6
7
  import { createCompilerPlugin, createRolldownCompilerPlugin } from "./compiler-plugin.js";
7
8
  import { StyleUrlsResolver, TemplateUrlsResolver, getAngularComponentMetadata } from "./component-resolvers.js";
@@ -89,14 +90,16 @@ function buildStylePreprocessor(options) {
89
90
  });
90
91
  if (!existsSync(rootStylesheet)) console.warn(`[@analogjs/vite-plugin-angular] tailwindCss.rootStylesheet not found at "${rootStylesheet}". @reference directives will point to a non-existent file, which will cause Tailwind CSS errors. Ensure the path is absolute and the file exists.`);
91
92
  tailwindPreprocessor = (code, filename) => {
92
- if (code.includes("@reference") || code.includes("@import \"tailwindcss\"") || code.includes("@import 'tailwindcss'")) {
93
+ const directiveState = inspectCssTailwindDirectives(code);
94
+ if (directiveState.hasReferenceDirective || directiveState.hasTailwindImportDirective) {
93
95
  debugTailwindV("skip (already has @reference or is root)", { filename });
94
96
  return code;
95
97
  }
96
- if (!(prefixes ? prefixes.some((prefix) => code.includes(prefix)) : code.includes("@apply"))) {
98
+ if (!(prefixes ? prefixes.some((prefix) => directiveState.commentlessCode.includes(prefix)) : directiveState.commentlessCode.includes("@apply"))) {
97
99
  debugTailwindV("skip (no Tailwind usage detected)", { filename });
98
100
  return code;
99
101
  }
102
+ if (directiveState.hasReferenceText) throwTailwindReferenceTextError(filename, rootStylesheet);
100
103
  debugTailwind("injected @reference via preprocessor", { filename });
101
104
  return `@reference "${rootStylesheet}";\n${code}`;
102
105
  };
@@ -110,6 +113,7 @@ function buildStylePreprocessor(options) {
110
113
  }
111
114
  function angular(options) {
112
115
  applyDebugOption(options?.debug, options?.workspaceRoot);
116
+ const liveReload = options?.liveReload ?? true;
113
117
  /**
114
118
  * Normalize plugin options so defaults
115
119
  * are used for values not provided.
@@ -127,7 +131,7 @@ function angular(options) {
127
131
  jit: options?.jit,
128
132
  include: options?.include ?? [],
129
133
  additionalContentDirs: options?.additionalContentDirs ?? [],
130
- hmr: options?.hmr ?? options?.liveReload ?? true,
134
+ liveReload,
131
135
  disableTypeChecking: options?.disableTypeChecking ?? true,
132
136
  fileReplacements: options?.fileReplacements ?? [],
133
137
  useAngularCompilationAPI: options?.experimental?.useAngularCompilationAPI ?? false,
@@ -159,8 +163,11 @@ function angular(options) {
159
163
  const classNameOwners = /* @__PURE__ */ new Map();
160
164
  const transformedStyleOwnerMetadata = /* @__PURE__ */ new Map();
161
165
  const styleSourceOwners = /* @__PURE__ */ new Map();
162
- function shouldEnableHmr() {
163
- return !!((isTest ? testWatchMode : watchMode) && pluginOptions.hmr);
166
+ function hasViteHmrTransport() {
167
+ return resolvedConfig ? resolvedConfig.server.hmr !== false : true;
168
+ }
169
+ function shouldEnableLiveReload() {
170
+ return !!((isTest ? testWatchMode : watchMode) && pluginOptions.liveReload && hasViteHmrTransport());
164
171
  }
165
172
  /**
166
173
  * Determines whether Angular should externalize component styles.
@@ -180,7 +187,7 @@ function angular(options) {
180
187
  */
181
188
  function shouldExternalizeStyles() {
182
189
  if (!(isTest ? testWatchMode : watchMode)) return false;
183
- return !!(shouldEnableHmr() || pluginOptions.hasTailwindCss);
190
+ return !!(shouldEnableLiveReload() || pluginOptions.hasTailwindCss);
184
191
  }
185
192
  /**
186
193
  * Validates the Tailwind CSS integration configuration and emits actionable
@@ -203,8 +210,33 @@ function angular(options) {
203
210
  }
204
211
  }
205
212
  if (tw.prefixes !== void 0 && tw.prefixes.length === 0) console.warn(`${PREFIX} tailwindCss.prefixes is an empty array. No component stylesheets will receive @reference injection. Either remove the prefixes option (to use @apply detection) or specify your prefixes: ['tw:']\n`);
213
+ /**
214
+ * Duplicate analog() registrations are a real bug for the non-SSR/client
215
+ * build because each plugin instance creates its own component-style state.
216
+ *
217
+ * That state includes the style maps/registries used to:
218
+ * - track transformed component styles
219
+ * - map owner components back to stylesheet requests
220
+ * - coordinate Tailwind/@reference processing and style reload behavior
221
+ *
222
+ * If two plugin instances are active for the same client build, one
223
+ * instance can record stylesheet metadata while the other services the
224
+ * request. The result is "missing" component CSS even though compilation
225
+ * appeared to succeed.
226
+ *
227
+ * SSR is different. Analog's Nitro/SSR build path reuses the already
228
+ * resolved plugin graph and then runs an additional `build.ssr === true`
229
+ * pass for the server bundle. In that flow Vite can expose multiple
230
+ * `@analogjs/vite-plugin-angular` entries in `config.plugins`, but that is
231
+ * not the same failure mode as a duplicated client build. The server build
232
+ * does not rely on the client-side style maps that this guard is protecting.
233
+ *
234
+ * Because of that, we only throw for duplicate registrations on non-SSR
235
+ * builds. Throwing during SSR would be a false positive that breaks valid
236
+ * Analog SSR/Nitro builds.
237
+ */
206
238
  const analogInstances = resolvedPlugins.filter((p) => p.name === "@analogjs/vite-plugin-angular");
207
- if (analogInstances.length > 1) throw new Error(`${PREFIX} analog() is registered ${analogInstances.length} times. Each instance creates separate style maps, causing component styles to be lost. Remove duplicate registrations.`);
239
+ if (analogInstances.length > 1 && !config.build?.ssr) throw new Error(`${PREFIX} analog() is registered ${analogInstances.length} times. Each instance creates separate style maps, causing component styles to be lost. Remove duplicate registrations.`);
208
240
  if (existsSync(tw.rootStylesheet)) try {
209
241
  const rootContent = readFileSync(tw.rootStylesheet, "utf-8");
210
242
  if (!rootContent.includes("@import \"tailwindcss\"") && !rootContent.includes("@import 'tailwindcss'")) console.warn(`${PREFIX} tailwindCss.rootStylesheet does not contain @import "tailwindcss". The @reference directive will point to a file without Tailwind configuration.\n\n File: ${tw.rootStylesheet}\n`);
@@ -306,16 +338,16 @@ function angular(options) {
306
338
  let angularCompilation;
307
339
  function angularPlugin() {
308
340
  let isProd = false;
309
- if (angularFullVersion < 19e4 && pluginOptions.hmr) {
341
+ if (angularFullVersion < 19e4 && pluginOptions.liveReload) {
310
342
  debugHmr("hmr disabled: Angular version does not support HMR APIs", {
311
343
  angularVersion: angularFullVersion,
312
344
  isTest
313
345
  });
314
346
  console.warn("[@analogjs/vite-plugin-angular]: HMR was disabled because Angular v19+ is required for externalRuntimeStyles/_enableHmr support. Detected Angular version: %s.", angularFullVersion);
315
- pluginOptions.hmr = false;
347
+ pluginOptions.liveReload = false;
316
348
  }
317
349
  if (isTest) {
318
- pluginOptions.hmr = false;
350
+ pluginOptions.liveReload = false;
319
351
  debugHmr("hmr disabled", {
320
352
  angularVersion: angularFullVersion,
321
353
  isTest
@@ -428,7 +460,7 @@ function angular(options) {
428
460
  });
429
461
  pendingCompilation = performCompilation(resolvedConfig, [fileId]);
430
462
  let result;
431
- if (shouldEnableHmr()) {
463
+ if (shouldEnableLiveReload()) {
432
464
  await pendingCompilation;
433
465
  pendingCompilation = null;
434
466
  result = fileEmitter(fileId);
@@ -450,7 +482,7 @@ function angular(options) {
450
482
  hint: result?.hmrEligible ? "A TS-side component change, including inline template edits, produced an Angular HMR payload." : "No Angular HMR payload was emitted for this TS change; the change may not affect component template state."
451
483
  });
452
484
  }
453
- if (shouldEnableHmr() && result?.hmrEligible && classNames.get(fileId)) {
485
+ if (shouldEnableLiveReload() && result?.hmrEligible && classNames.get(fileId)) {
454
486
  const relativeFileId = `${normalizePath(relative(process.cwd(), fileId))}@${classNames.get(fileId)}`;
455
487
  debugHmr("sending component update", { relativeFileId });
456
488
  debugHmrV("ts hmr component update payload", {
@@ -631,7 +663,7 @@ function angular(options) {
631
663
  }
632
664
  return fileModules;
633
665
  }
634
- if (shouldEnableHmr() && /\.(html|htm)$/.test(ctx.file) && fileModules.length === 0) {
666
+ if (shouldEnableLiveReload() && /\.(html|htm)$/.test(ctx.file) && fileModules.length === 0) {
635
667
  const ownerModules = findTemplateOwnerModules(ctx.server, ctx.file);
636
668
  debugHmrV("template owner lookup", {
637
669
  file: ctx.file,
@@ -857,6 +889,7 @@ function angular(options) {
857
889
  }
858
890
  const typescriptResult = fileEmitter(id);
859
891
  if (!typescriptResult) {
892
+ debugCompilerV("transform skip (file not emitted by Angular)", { id });
860
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.`);
861
894
  return;
862
895
  }
@@ -1002,18 +1035,21 @@ function angular(options) {
1002
1035
  const tw = pluginOptions.tailwindCss;
1003
1036
  if (!tw || !id.includes(".css")) return;
1004
1037
  if (id.split("?")[0] === tw.rootStylesheet) return;
1005
- if (code.includes("@reference") || code.includes("@import \"tailwindcss\"") || code.includes("@import 'tailwindcss'")) return;
1038
+ const directiveState = inspectCssTailwindDirectives(code);
1039
+ if (directiveState.hasReferenceDirective || directiveState.hasTailwindImportDirective) return;
1006
1040
  const rootBasename = basename(tw.rootStylesheet);
1007
- if (code.includes(rootBasename)) return;
1041
+ if (directiveState.commentlessCode.includes(rootBasename)) return;
1008
1042
  const prefixes = tw.prefixes;
1009
- if (prefixes ? prefixes.some((p) => code.includes(p)) : code.includes("@apply")) {
1043
+ const needsRef = prefixes ? prefixes.some((p) => directiveState.commentlessCode.includes(p)) : directiveState.commentlessCode.includes("@apply");
1044
+ if (needsRef && directiveState.hasReferenceText) throwTailwindReferenceTextError(id, tw.rootStylesheet);
1045
+ if (needsRef) {
1010
1046
  debugTailwind("injected @reference via pre-transform", { id: id.split("/").slice(-2).join("/") });
1011
1047
  return `@reference "${tw.rootStylesheet}";\n${code}`;
1012
1048
  }
1013
1049
  }
1014
1050
  },
1015
1051
  angularPlugin(),
1016
- pluginOptions.hmr && liveReloadPlugin({
1052
+ pluginOptions.liveReload && liveReloadPlugin({
1017
1053
  classNames,
1018
1054
  fileEmitter
1019
1055
  }),
@@ -1033,6 +1069,74 @@ function angular(options) {
1033
1069
  absolute: true
1034
1070
  });
1035
1071
  }
1072
+ function ensureIncludeCache() {
1073
+ if (pluginOptions.include.length > 0 && includeCache.length === 0) includeCache = findIncludes();
1074
+ return includeCache;
1075
+ }
1076
+ function getTsconfigCacheKey(resolvedTsConfigPath, config) {
1077
+ return [
1078
+ resolvedTsConfigPath,
1079
+ config.mode === "production" ? "prod" : "dev",
1080
+ isTest ? "test" : "app",
1081
+ config.build?.lib ? "lib" : "nolib",
1082
+ pluginOptions.hmr ? "hmr" : "nohmr",
1083
+ pluginOptions.hasTailwindCss ? "tw" : "notw"
1084
+ ].join("|");
1085
+ }
1086
+ function getCachedTsconfigOptions(resolvedTsConfigPath, config) {
1087
+ const isProd = config.mode === "production";
1088
+ const tsconfigKey = getTsconfigCacheKey(resolvedTsConfigPath, config);
1089
+ let cached = tsconfigOptionsCache.get(tsconfigKey);
1090
+ 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
+ });
1108
+ cached = {
1109
+ options: read.options,
1110
+ rootNames: read.rootNames
1111
+ };
1112
+ tsconfigOptionsCache.set(tsconfigKey, cached);
1113
+ }
1114
+ return cached;
1115
+ }
1116
+ function resolveCompilationApiTsConfigPath(resolvedTsConfigPath, config) {
1117
+ const includedFiles = ensureIncludeCache();
1118
+ if (includedFiles.length === 0) return resolvedTsConfigPath;
1119
+ const cached = getCachedTsconfigOptions(resolvedTsConfigPath, config);
1120
+ const mergedRootNames = union(cached.rootNames, includedFiles).map((file) => normalizePath(file));
1121
+ if (mergedRootNames.length === cached.rootNames.length) return resolvedTsConfigPath;
1122
+ const wrapperDir = join(isAbsolute(config.cacheDir) ? config.cacheDir : resolve(config.root, config.cacheDir), "analog-angular", "compilation-api");
1123
+ const rawTsconfig = ts.readConfigFile(resolvedTsConfigPath, ts.sys.readFile).config ?? {};
1124
+ const wrapperPayload = {
1125
+ extends: normalizePath(resolvedTsConfigPath),
1126
+ files: [...mergedRootNames].sort(),
1127
+ ...rawTsconfig.references ? { references: rawTsconfig.references } : {}
1128
+ };
1129
+ const wrapperPath = join(wrapperDir, `tsconfig.includes.${createHash("sha1").update(JSON.stringify(wrapperPayload)).digest("hex").slice(0, 12)}.json`);
1130
+ mkdirSync(wrapperDir, { recursive: true });
1131
+ if (!existsSync(wrapperPath)) writeFileSync(wrapperPath, `${JSON.stringify(wrapperPayload, null, 2)}\n`, "utf-8");
1132
+ debugCompilationApi("generated include wrapper tsconfig", {
1133
+ originalTsconfig: resolvedTsConfigPath,
1134
+ wrapperTsconfig: wrapperPath,
1135
+ includeCount: includedFiles.length,
1136
+ rootNameCount: mergedRootNames.length
1137
+ });
1138
+ return wrapperPath;
1139
+ }
1036
1140
  function resolveTsConfigPath() {
1037
1141
  const tsconfigValue = pluginOptions.tsconfigGetter();
1038
1142
  return getTsConfigPath(tsConfigResolutionContext.root, tsconfigValue, tsConfigResolutionContext.isProd, isTest, tsConfigResolutionContext.isLib);
@@ -1060,8 +1164,8 @@ function angular(options) {
1060
1164
  debugCompilationApi("incremental update", { files: [...modifiedFiles] });
1061
1165
  await angularCompilation.update(modifiedFiles);
1062
1166
  }
1063
- const resolvedTsConfigPath = resolveTsConfigPath();
1064
- const compilationResult = await angularCompilation.initialize(resolvedTsConfigPath, {
1167
+ const compilationApiTsConfigPath = resolveCompilationApiTsConfigPath(resolveTsConfigPath(), config);
1168
+ const compilationResult = await angularCompilation.initialize(compilationApiTsConfigPath, {
1065
1169
  fileReplacements: toAngularCompilationFileReplacements(pluginOptions.fileReplacements, pluginOptions.workspaceRoot),
1066
1170
  modifiedFiles,
1067
1171
  async transformStylesheet(data, containingFile, resourceFile, order, className) {
@@ -1074,7 +1178,7 @@ function angular(options) {
1074
1178
  order,
1075
1179
  inline: !resourceFile
1076
1180
  });
1077
- if (shouldEnableHmr() && className && containingFile) classNames.set(normalizePath(containingFile), className);
1181
+ if (shouldEnableLiveReload() && className && containingFile) classNames.set(normalizePath(containingFile), className);
1078
1182
  if (shouldExternalizeStyles()) {
1079
1183
  const stylesheetId = registerStylesheetContent(stylesheetRegistry, {
1080
1184
  code: preprocessed.code,
@@ -1111,6 +1215,7 @@ function angular(options) {
1111
1215
  try {
1112
1216
  stylesheetResult = await preprocessCSS(preprocessed.code, `${filename}?direct`, resolvedConfig);
1113
1217
  } catch (e) {
1218
+ if (isTailwindReferenceError(e)) throw e;
1114
1219
  debugStyles("preprocessCSS error", {
1115
1220
  filename,
1116
1221
  resourceFile: resourceFile ?? "(inline)",
@@ -1124,12 +1229,13 @@ function angular(options) {
1124
1229
  }
1125
1230
  }, (tsCompilerOptions) => {
1126
1231
  if (shouldExternalizeStyles()) tsCompilerOptions["externalRuntimeStyles"] = true;
1127
- if (shouldEnableHmr()) {
1232
+ if (shouldEnableLiveReload()) {
1128
1233
  tsCompilerOptions["_enableHmr"] = true;
1129
1234
  tsCompilerOptions["supportTestBed"] = true;
1130
1235
  }
1131
1236
  debugCompiler("tsCompilerOptions (compilation API)", {
1132
- hmr: pluginOptions.hmr,
1237
+ liveReload: pluginOptions.liveReload,
1238
+ viteHmr: hasViteHmrTransport(),
1133
1239
  hasTailwindCss: pluginOptions.hasTailwindCss,
1134
1240
  watchMode,
1135
1241
  shouldExternalize: shouldExternalizeStyles(),
@@ -1281,50 +1387,17 @@ function angular(options) {
1281
1387
  const modifiedFiles = new Set(ids ?? []);
1282
1388
  sourceFileCache$1.invalidate(modifiedFiles);
1283
1389
  if (ids?.length) for (const id of ids || []) fileTransformMap.delete(id);
1284
- if (pluginOptions.include.length > 0 && includeCache.length === 0) includeCache = findIncludes();
1285
- const resolvedTsConfigPath = resolveTsConfigPath();
1286
- const tsconfigKey = [
1287
- resolvedTsConfigPath,
1288
- isProd ? "prod" : "dev",
1289
- isTest ? "test" : "app",
1290
- config.build?.lib ? "lib" : "nolib",
1291
- pluginOptions.hmr ? "hmr" : "nohmr",
1292
- pluginOptions.hasTailwindCss ? "tw" : "notw"
1293
- ].join("|");
1294
- let cached = tsconfigOptionsCache.get(tsconfigKey);
1295
- if (!cached) {
1296
- const read = compilerCli.readConfiguration(resolvedTsConfigPath, {
1297
- suppressOutputPathCheck: true,
1298
- outDir: void 0,
1299
- sourceMap: false,
1300
- inlineSourceMap: !isProd,
1301
- inlineSources: !isProd,
1302
- declaration: false,
1303
- declarationMap: false,
1304
- allowEmptyCodegenFiles: false,
1305
- annotationsAs: "decorators",
1306
- enableResourceInlining: false,
1307
- noEmitOnError: false,
1308
- mapRoot: void 0,
1309
- sourceRoot: void 0,
1310
- supportTestBed: false,
1311
- supportJitMode: false
1312
- });
1313
- cached = {
1314
- options: read.options,
1315
- rootNames: read.rootNames
1316
- };
1317
- tsconfigOptionsCache.set(tsconfigKey, cached);
1318
- }
1390
+ const cached = getCachedTsconfigOptions(resolveTsConfigPath(), config);
1319
1391
  const tsCompilerOptions = { ...cached.options };
1320
1392
  let rootNames = [...cached.rootNames];
1321
1393
  if (shouldExternalizeStyles()) tsCompilerOptions["externalRuntimeStyles"] = true;
1322
- if (shouldEnableHmr()) {
1394
+ if (shouldEnableLiveReload()) {
1323
1395
  tsCompilerOptions["_enableHmr"] = true;
1324
1396
  tsCompilerOptions["supportTestBed"] = true;
1325
1397
  }
1326
1398
  debugCompiler("tsCompilerOptions (NgtscProgram path)", {
1327
- hmr: pluginOptions.hmr,
1399
+ liveReload: pluginOptions.liveReload,
1400
+ viteHmr: hasViteHmrTransport(),
1328
1401
  shouldExternalize: shouldExternalizeStyles(),
1329
1402
  externalRuntimeStyles: !!tsCompilerOptions["externalRuntimeStyles"],
1330
1403
  hmrEnabled: !!tsCompilerOptions["_enableHmr"]
@@ -1341,7 +1414,7 @@ function angular(options) {
1341
1414
  }
1342
1415
  if (isTest) tsCompilerOptions["supportTestBed"] = true;
1343
1416
  const replacements = pluginOptions.fileReplacements.map((rp) => join(pluginOptions.workspaceRoot, rp.ssr || rp.with));
1344
- rootNames = union(rootNames, includeCache, replacements);
1417
+ rootNames = union(rootNames, ensureIncludeCache(), replacements);
1345
1418
  const hostKey = JSON.stringify(tsCompilerOptions);
1346
1419
  let host;
1347
1420
  if (cachedHost && cachedHostKey === hostKey) host = cachedHost;
@@ -1394,7 +1467,7 @@ function angular(options) {
1394
1467
  if (!watchMode) builder = ts.createAbstractBuilder(typeScriptProgram, host, oldBuilder);
1395
1468
  if (angularCompiler) await angularCompiler.analyzeAsync();
1396
1469
  const transformers = mergeTransformers({ before: jit ? [compilerCli.constructorParametersDownlevelTransform(builder.getProgram()), cjt(() => builder.getProgram().getTypeChecker())] : [] }, jit ? {} : angularCompiler.prepareEmit().transformers);
1397
- const fileMetadata = getFileMetadata(builder, angularCompiler, pluginOptions.hmr, pluginOptions.disableTypeChecking);
1470
+ const fileMetadata = getFileMetadata(builder, angularCompiler, pluginOptions.liveReload, pluginOptions.disableTypeChecking);
1398
1471
  const writeFileCallback = (_filename, content, _a, _b, sourceFiles) => {
1399
1472
  if (!sourceFiles?.length) return;
1400
1473
  const filename = normalizePath(sourceFiles[0].fileName);