@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 +6 -0
- package/package.json +2 -2
- package/src/lib/angular-jit-plugin.js +2 -0
- package/src/lib/angular-jit-plugin.js.map +1 -1
- package/src/lib/angular-vite-plugin.d.ts +21 -7
- package/src/lib/angular-vite-plugin.js +134 -61
- package/src/lib/angular-vite-plugin.js.map +1 -1
- package/src/lib/host.js +2 -0
- package/src/lib/host.js.map +1 -1
- package/src/lib/live-reload-plugin.js +4 -0
- package/src/lib/live-reload-plugin.js.map +1 -1
- package/src/lib/utils/tailwind-reference.d.ts +12 -0
- package/src/lib/utils/tailwind-reference.js +99 -0
- package/src/lib/utils/tailwind-reference.js.map +1 -0
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.
|
|
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.
|
|
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":"
|
|
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
|
|
35
|
+
* Enables Analog's Angular live-reload/HMR pipeline during development/watch mode.
|
|
36
36
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
*
|
|
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
|
-
|
|
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) =>
|
|
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
|
-
|
|
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
|
|
163
|
-
return
|
|
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 !!(
|
|
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.
|
|
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.
|
|
347
|
+
pluginOptions.liveReload = false;
|
|
316
348
|
}
|
|
317
349
|
if (isTest) {
|
|
318
|
-
pluginOptions.
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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
|
-
|
|
1038
|
+
const directiveState = inspectCssTailwindDirectives(code);
|
|
1039
|
+
if (directiveState.hasReferenceDirective || directiveState.hasTailwindImportDirective) return;
|
|
1006
1040
|
const rootBasename = basename(tw.rootStylesheet);
|
|
1007
|
-
if (
|
|
1041
|
+
if (directiveState.commentlessCode.includes(rootBasename)) return;
|
|
1008
1042
|
const prefixes = tw.prefixes;
|
|
1009
|
-
|
|
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.
|
|
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
|
|
1064
|
-
const compilationResult = await angularCompilation.initialize(
|
|
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 (
|
|
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 (
|
|
1232
|
+
if (shouldEnableLiveReload()) {
|
|
1128
1233
|
tsCompilerOptions["_enableHmr"] = true;
|
|
1129
1234
|
tsCompilerOptions["supportTestBed"] = true;
|
|
1130
1235
|
}
|
|
1131
1236
|
debugCompiler("tsCompilerOptions (compilation API)", {
|
|
1132
|
-
|
|
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
|
-
|
|
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 (
|
|
1394
|
+
if (shouldEnableLiveReload()) {
|
|
1323
1395
|
tsCompilerOptions["_enableHmr"] = true;
|
|
1324
1396
|
tsCompilerOptions["supportTestBed"] = true;
|
|
1325
1397
|
}
|
|
1326
1398
|
debugCompiler("tsCompilerOptions (NgtscProgram path)", {
|
|
1327
|
-
|
|
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,
|
|
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.
|
|
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);
|