@analogjs/vite-plugin-angular 3.0.0-alpha.42 → 3.0.0-alpha.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/lib/angular-jit-plugin.js +1 -1
- package/src/lib/angular-vite-plugin.d.ts +3 -77
- package/src/lib/angular-vite-plugin.js +77 -1012
- package/src/lib/angular-vite-plugin.js.map +1 -1
- package/src/lib/compilation-api/compilation-api-plugin.d.ts +29 -0
- package/src/lib/compilation-api/compilation-api-plugin.js +468 -0
- package/src/lib/compilation-api/compilation-api-plugin.js.map +1 -0
- package/src/lib/compilation-api/index.d.ts +1 -0
- package/src/lib/compilation-api/index.js +1 -0
- package/src/lib/compiler/compile.js +2 -2
- package/src/lib/compiler/defer.js +1 -1
- package/src/lib/compiler/js-emitter.js +1 -1
- package/src/lib/encapsulation-plugin.d.ts +13 -0
- package/src/lib/encapsulation-plugin.js +48 -0
- package/src/lib/encapsulation-plugin.js.map +1 -0
- package/src/lib/fast-compile-plugin.js +2 -28
- package/src/lib/fast-compile-plugin.js.map +1 -1
- package/src/lib/host.js +1 -1
- package/src/lib/stylesheet-registry.js +1 -1
- package/src/lib/tailwind-plugin.d.ts +34 -0
- package/src/lib/tailwind-plugin.js +116 -0
- package/src/lib/tailwind-plugin.js.map +1 -0
- package/src/lib/template-class-binding-guard-plugin.d.ts +30 -0
- package/src/lib/template-class-binding-guard-plugin.js +237 -0
- package/src/lib/template-class-binding-guard-plugin.js.map +1 -0
- package/src/lib/utils/compilation-shared.d.ts +58 -0
- package/src/lib/utils/compilation-shared.js +133 -0
- package/src/lib/utils/compilation-shared.js.map +1 -0
- package/src/lib/utils/tsconfig-resolver.d.ts +28 -0
- package/src/lib/utils/tsconfig-resolver.js +191 -0
- package/src/lib/utils/tsconfig-resolver.js.map +1 -0
- package/src/lib/utils/virtual-resources.js +4 -31
- package/src/lib/utils/virtual-resources.js.map +1 -1
- package/src/lib/virtual-modules-plugin.d.ts +5 -0
- package/src/lib/virtual-modules-plugin.js +50 -0
- package/src/lib/virtual-modules-plugin.js.map +1 -0
|
@@ -1,51 +1,38 @@
|
|
|
1
|
-
import { angularFullVersion, cjt,
|
|
1
|
+
import { angularFullVersion, cjt, 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,
|
|
5
|
-
import { inspectCssTailwindDirectives, isTailwindReferenceError, throwTailwindReferenceTextError } from "./utils/tailwind-reference.js";
|
|
4
|
+
import { activateDeferredDebug, applyDebugOption, debugCompiler, debugCompilerV, debugEmit, debugEmitV, debugHmr, debugHmrV, debugStyles, debugStylesV } from "./utils/debug.js";
|
|
6
5
|
import { toVirtualRawId, toVirtualStyleId } from "./utils/virtual-ids.js";
|
|
7
|
-
import { loadVirtualRawModule, loadVirtualStyleModule, shouldPreprocessTestCss } from "./utils/virtual-resources.js";
|
|
8
6
|
import { jitPlugin } from "./angular-jit-plugin.js";
|
|
9
7
|
import { createCompilerPlugin, createRolldownCompilerPlugin } from "./compiler-plugin.js";
|
|
10
8
|
import { StyleUrlsResolver, TemplateUrlsResolver, getAngularComponentMetadata } from "./component-resolvers.js";
|
|
11
|
-
import {
|
|
12
|
-
import { AnalogStylesheetRegistry, preprocessStylesheet, preprocessStylesheetResult, registerStylesheetContent, rewriteRelativeCssImports } from "./stylesheet-registry.js";
|
|
9
|
+
import { AnalogStylesheetRegistry, preprocessStylesheet, rewriteRelativeCssImports } from "./stylesheet-registry.js";
|
|
13
10
|
import { augmentHostWithCaching, augmentHostWithResources, augmentProgramWithVersioning, mergeTransformers } from "./host.js";
|
|
14
11
|
import { TS_EXT_REGEX, createTsConfigGetter, getTsConfigPath } from "./utils/plugin-config.js";
|
|
12
|
+
import { TsconfigResolver } from "./utils/tsconfig-resolver.js";
|
|
13
|
+
import { configureStylePipelineRegistry } from "./style-pipeline.js";
|
|
14
|
+
import { describeStylesheetContent, injectViteIgnoreForHmrMetadata, isIgnoredHmrFile, isTestWatchMode, refreshStylesheetRegistryForFile } from "./utils/compilation-shared.js";
|
|
15
|
+
import { compilationAPIPlugin } from "./compilation-api/compilation-api-plugin.js";
|
|
16
|
+
import "./compilation-api/index.js";
|
|
15
17
|
import { fastCompilePlugin } from "./fast-compile-plugin.js";
|
|
18
|
+
import { removeActiveGraphMetadata, removeStyleOwnerMetadata, templateClassBindingGuardPlugin } from "./template-class-binding-guard-plugin.js";
|
|
19
|
+
import { buildStylePreprocessor, tailwindReferencePlugin, validateTailwindConfig } from "./tailwind-plugin.js";
|
|
20
|
+
import { encapsulationPlugin, getComponentStyleSheetMeta, isComponentStyleSheet } from "./encapsulation-plugin.js";
|
|
21
|
+
import { virtualModulesPlugin } from "./virtual-modules-plugin.js";
|
|
16
22
|
import { angularVitestPlugins } from "./angular-vitest-plugin.js";
|
|
17
23
|
import { pendingTasksPlugin } from "./angular-pending-tasks.plugin.js";
|
|
18
24
|
import { liveReloadPlugin } from "./live-reload-plugin.js";
|
|
19
25
|
import { nxFolderPlugin } from "./nx-folder-plugin.js";
|
|
20
26
|
import { replaceFiles } from "./plugins/file-replacements.plugin.js";
|
|
21
27
|
import { routerPlugin } from "./router-plugin.js";
|
|
22
|
-
import { configureStylePipelineRegistry, stylePipelinePreprocessorFromPlugins } from "./style-pipeline.js";
|
|
23
28
|
import { union } from "es-toolkit";
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
29
|
+
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
30
|
+
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
27
31
|
import * as compilerCli from "@angular/compiler-cli";
|
|
28
32
|
import { createRequire } from "node:module";
|
|
29
|
-
import * as ngCompiler from "@angular/compiler";
|
|
30
|
-
import { globSync } from "tinyglobby";
|
|
31
33
|
import { defaultClientConditions, normalizePath, preprocessCSS } from "vite";
|
|
32
34
|
//#region packages/vite-plugin-angular/src/lib/angular-vite-plugin.ts
|
|
33
35
|
var require = createRequire(import.meta.url);
|
|
34
|
-
var DiagnosticModes = /* @__PURE__ */ function(DiagnosticModes) {
|
|
35
|
-
DiagnosticModes[DiagnosticModes["None"] = 0] = "None";
|
|
36
|
-
DiagnosticModes[DiagnosticModes["Option"] = 1] = "Option";
|
|
37
|
-
DiagnosticModes[DiagnosticModes["Syntactic"] = 2] = "Syntactic";
|
|
38
|
-
DiagnosticModes[DiagnosticModes["Semantic"] = 4] = "Semantic";
|
|
39
|
-
DiagnosticModes[DiagnosticModes["All"] = 7] = "All";
|
|
40
|
-
return DiagnosticModes;
|
|
41
|
-
}({});
|
|
42
|
-
function normalizeIncludeGlob(workspaceRoot, glob) {
|
|
43
|
-
const normalizedWorkspaceRoot = normalizePath(resolve(workspaceRoot));
|
|
44
|
-
const normalizedGlob = normalizePath(glob);
|
|
45
|
-
if (normalizedGlob === normalizedWorkspaceRoot || normalizedGlob.startsWith(`${normalizedWorkspaceRoot}/`)) return normalizedGlob;
|
|
46
|
-
if (normalizedGlob.startsWith("/")) return `${normalizedWorkspaceRoot}${normalizedGlob}`;
|
|
47
|
-
return normalizePath(resolve(normalizedWorkspaceRoot, normalizedGlob));
|
|
48
|
-
}
|
|
49
36
|
var classNames = /* @__PURE__ */ new Map();
|
|
50
37
|
function evictDeletedFileMetadata(file, { removeActiveGraphMetadata, removeStyleOwnerMetadata, classNamesMap, fileTransformMap }) {
|
|
51
38
|
const normalizedFile = normalizePath(file.split("?")[0]);
|
|
@@ -54,63 +41,6 @@ function evictDeletedFileMetadata(file, { removeActiveGraphMetadata, removeStyle
|
|
|
54
41
|
classNamesMap.delete(normalizedFile);
|
|
55
42
|
fileTransformMap.delete(normalizedFile);
|
|
56
43
|
}
|
|
57
|
-
function injectViteIgnoreForHmrMetadata(code) {
|
|
58
|
-
let patched = code.replace(/\bimport\(([a-zA-Z_$][\w$]*\.\u0275\u0275getReplaceMetadataURL)/g, "import(/* @vite-ignore */ $1");
|
|
59
|
-
if (patched === code) patched = patched.replace(/import\((\S+getReplaceMetadataURL)/g, "import(/* @vite-ignore */ $1");
|
|
60
|
-
return patched;
|
|
61
|
-
}
|
|
62
|
-
function isIgnoredHmrFile(file) {
|
|
63
|
-
return file.endsWith(".tsbuildinfo");
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Builds a resolved stylePreprocessor function from plugin options.
|
|
67
|
-
*
|
|
68
|
-
* When `tailwindCss` is configured, creates an injector that prepends
|
|
69
|
-
* `@reference "<rootStylesheet>"` into component CSS that uses Tailwind
|
|
70
|
-
* utilities. Uses absolute paths because Angular's externalRuntimeStyles
|
|
71
|
-
* serves component CSS as virtual modules (hash-based IDs) with no
|
|
72
|
-
* meaningful directory — relative paths can't resolve from a hash.
|
|
73
|
-
*
|
|
74
|
-
* If both `tailwindCss` and `stylePreprocessor` are provided, they are
|
|
75
|
-
* chained: Tailwind reference injection runs first, then the user's
|
|
76
|
-
* custom preprocessor.
|
|
77
|
-
*/
|
|
78
|
-
function buildStylePreprocessor(options) {
|
|
79
|
-
const userPreprocessor = options?.stylePreprocessor;
|
|
80
|
-
const stylePipelinePreprocessor = stylePipelinePreprocessorFromPlugins(options?.stylePipeline);
|
|
81
|
-
const tw = options?.tailwindCss;
|
|
82
|
-
if (!tw && !userPreprocessor && !stylePipelinePreprocessor) return;
|
|
83
|
-
let tailwindPreprocessor;
|
|
84
|
-
if (tw) {
|
|
85
|
-
const rootStylesheet = tw.rootStylesheet;
|
|
86
|
-
const prefixes = tw.prefixes;
|
|
87
|
-
debugTailwind("configured", {
|
|
88
|
-
rootStylesheet,
|
|
89
|
-
prefixes
|
|
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.`);
|
|
92
|
-
tailwindPreprocessor = (code, filename) => {
|
|
93
|
-
const directiveState = inspectCssTailwindDirectives(code);
|
|
94
|
-
if (directiveState.hasReferenceDirective || directiveState.hasTailwindImportDirective) {
|
|
95
|
-
debugTailwindV("skip (already has @reference or is root)", { filename });
|
|
96
|
-
return code;
|
|
97
|
-
}
|
|
98
|
-
if (!(prefixes ? prefixes.some((prefix) => directiveState.commentlessCode.includes(prefix)) : directiveState.commentlessCode.includes("@apply"))) {
|
|
99
|
-
debugTailwindV("skip (no Tailwind usage detected)", { filename });
|
|
100
|
-
return code;
|
|
101
|
-
}
|
|
102
|
-
if (directiveState.hasReferenceText) throwTailwindReferenceTextError(filename, rootStylesheet);
|
|
103
|
-
debugTailwind("injected @reference via preprocessor", { filename });
|
|
104
|
-
return `@reference "${rootStylesheet.replace(/\\/g, "/")}";\n${code}`;
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
if (tailwindPreprocessor && (stylePipelinePreprocessor || userPreprocessor)) debugTailwind("chained with style pipeline or user stylePreprocessor");
|
|
108
|
-
return composeStylePreprocessors([
|
|
109
|
-
tailwindPreprocessor,
|
|
110
|
-
stylePipelinePreprocessor,
|
|
111
|
-
userPreprocessor
|
|
112
|
-
]);
|
|
113
|
-
}
|
|
114
44
|
function angular(options) {
|
|
115
45
|
applyDebugOption(options?.debug, options?.workspaceRoot);
|
|
116
46
|
const liveReload = options?.liveReload ?? true;
|
|
@@ -146,17 +76,21 @@ function angular(options) {
|
|
|
146
76
|
const ts = require("typescript");
|
|
147
77
|
let builder;
|
|
148
78
|
let nextProgram;
|
|
149
|
-
const tsconfigOptionsCache = /* @__PURE__ */ new Map();
|
|
150
|
-
const tsconfigGraphRootCache = /* @__PURE__ */ new Map();
|
|
151
79
|
let cachedHost;
|
|
152
80
|
let cachedHostKey;
|
|
153
|
-
|
|
81
|
+
const isTest = process.env.NODE_ENV === "test" || !!process.env["VITEST"];
|
|
82
|
+
const tsconfigResolver = new TsconfigResolver({
|
|
83
|
+
workspaceRoot: pluginOptions.workspaceRoot,
|
|
84
|
+
include: pluginOptions.include,
|
|
85
|
+
liveReload: pluginOptions.liveReload,
|
|
86
|
+
hasTailwindCss: pluginOptions.hasTailwindCss,
|
|
87
|
+
isTest
|
|
88
|
+
});
|
|
154
89
|
function invalidateFsCaches() {
|
|
155
|
-
|
|
90
|
+
tsconfigResolver.invalidateIncludeCache();
|
|
156
91
|
}
|
|
157
92
|
function invalidateTsconfigCaches() {
|
|
158
|
-
|
|
159
|
-
tsconfigGraphRootCache.clear();
|
|
93
|
+
tsconfigResolver.invalidateTsconfigCaches();
|
|
160
94
|
cachedHost = void 0;
|
|
161
95
|
cachedHostKey = void 0;
|
|
162
96
|
}
|
|
@@ -193,140 +127,26 @@ function angular(options) {
|
|
|
193
127
|
if (!(isTest ? testWatchMode : watchMode)) return false;
|
|
194
128
|
return !!(shouldEnableLiveReload() || pluginOptions.hasTailwindCss);
|
|
195
129
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
*
|
|
200
|
-
* Called once during `configResolved` when `tailwindCss` is configured.
|
|
201
|
-
*/
|
|
202
|
-
function validateTailwindConfig(config, isWatchMode) {
|
|
203
|
-
const PREFIX = "[@analogjs/vite-plugin-angular]";
|
|
204
|
-
const tw = pluginOptions.tailwindCss;
|
|
205
|
-
if (!tw) return;
|
|
206
|
-
if (!isAbsolute(tw.rootStylesheet)) console.warn(`${PREFIX} tailwindCss.rootStylesheet must be an absolute path. Got: "${tw.rootStylesheet}". Use path.resolve(__dirname, '...') in your vite.config to convert it.`);
|
|
207
|
-
const resolvedPlugins = config.plugins;
|
|
208
|
-
const hasTailwindPlugin = resolvedPlugins.some((p) => p.name.startsWith("@tailwindcss/vite") || p.name.startsWith("tailwindcss"));
|
|
209
|
-
if (isWatchMode && !hasTailwindPlugin) throw new Error(`${PREFIX} tailwindCss is configured but no @tailwindcss/vite plugin was found. Component CSS with @apply directives will not be processed.\n\n Fix: npm install @tailwindcss/vite --save-dev\n Then add tailwindcss() to your vite.config plugins array.\n`);
|
|
210
|
-
if (isWatchMode && tw.rootStylesheet) {
|
|
211
|
-
const projectRoot = normalizePath(config.root);
|
|
212
|
-
const normalizedRootStylesheet = normalizePath(tw.rootStylesheet);
|
|
213
|
-
if (!normalizedRootStylesheet.startsWith(projectRoot)) {
|
|
214
|
-
if (!(config.server?.fs?.allow ?? []).some((allowed) => normalizedRootStylesheet.startsWith(normalizePath(allowed)))) console.warn(`${PREFIX} tailwindCss.rootStylesheet is outside the Vite project root. The dev server may reject it with 403.\n\n Root: ${projectRoot}\n Stylesheet: ${tw.rootStylesheet}\n\n Fix: server.fs.allow: ['${dirname(tw.rootStylesheet)}']\n`);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
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`);
|
|
218
|
-
/**
|
|
219
|
-
* Duplicate analog() registrations are a real bug for the non-SSR/client
|
|
220
|
-
* build because each plugin instance creates its own component-style state.
|
|
221
|
-
*
|
|
222
|
-
* That state includes the style maps/registries used to:
|
|
223
|
-
* - track transformed component styles
|
|
224
|
-
* - map owner components back to stylesheet requests
|
|
225
|
-
* - coordinate Tailwind/@reference processing and style reload behavior
|
|
226
|
-
*
|
|
227
|
-
* If two plugin instances are active for the same client build, one
|
|
228
|
-
* instance can record stylesheet metadata while the other services the
|
|
229
|
-
* request. The result is "missing" component CSS even though compilation
|
|
230
|
-
* appeared to succeed.
|
|
231
|
-
*
|
|
232
|
-
* SSR is different. Analog's Nitro/SSR build path reuses the already
|
|
233
|
-
* resolved plugin graph and then runs an additional `build.ssr === true`
|
|
234
|
-
* pass for the server bundle. In that flow Vite can expose multiple
|
|
235
|
-
* `@analogjs/vite-plugin-angular` entries in `config.plugins`, but that is
|
|
236
|
-
* not the same failure mode as a duplicated client build. The server build
|
|
237
|
-
* does not rely on the client-side style maps that this guard is protecting.
|
|
238
|
-
*
|
|
239
|
-
* Because of that, we only throw for duplicate registrations on non-SSR
|
|
240
|
-
* builds. Throwing during SSR would be a false positive that breaks valid
|
|
241
|
-
* Analog SSR/Nitro builds.
|
|
242
|
-
*/
|
|
243
|
-
const analogInstances = resolvedPlugins.filter((p) => p.name === "@analogjs/vite-plugin-angular");
|
|
244
|
-
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.`);
|
|
245
|
-
if (existsSync(tw.rootStylesheet)) try {
|
|
246
|
-
const rootContent = readFileSync(tw.rootStylesheet, "utf-8");
|
|
247
|
-
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`);
|
|
248
|
-
} catch {}
|
|
249
|
-
}
|
|
250
|
-
function isLikelyPageOnlyComponent(id) {
|
|
251
|
-
return id.includes("/pages/") || /\.page\.[cm]?[jt]sx?$/i.test(id) || /\([^/]+\)\.page\.[cm]?[jt]sx?$/i.test(id);
|
|
252
|
-
}
|
|
253
|
-
function removeActiveGraphMetadata(file) {
|
|
254
|
-
const previous = activeGraphComponentMetadata.get(file);
|
|
255
|
-
if (!previous) return;
|
|
256
|
-
for (const record of previous) {
|
|
257
|
-
const location = `${record.file}#${record.className}`;
|
|
258
|
-
if (record.selector) {
|
|
259
|
-
const selectorSet = selectorOwners.get(record.selector);
|
|
260
|
-
selectorSet?.delete(location);
|
|
261
|
-
if (selectorSet?.size === 0) selectorOwners.delete(record.selector);
|
|
262
|
-
}
|
|
263
|
-
const classNameSet = classNameOwners.get(record.className);
|
|
264
|
-
classNameSet?.delete(location);
|
|
265
|
-
if (classNameSet?.size === 0) classNameOwners.delete(record.className);
|
|
266
|
-
}
|
|
267
|
-
activeGraphComponentMetadata.delete(file);
|
|
268
|
-
}
|
|
269
|
-
function registerActiveGraphMetadata(file, records) {
|
|
270
|
-
removeActiveGraphMetadata(file);
|
|
271
|
-
if (records.length === 0) return;
|
|
272
|
-
activeGraphComponentMetadata.set(file, records);
|
|
273
|
-
for (const record of records) {
|
|
274
|
-
const location = `${record.file}#${record.className}`;
|
|
275
|
-
if (record.selector) {
|
|
276
|
-
let selectorSet = selectorOwners.get(record.selector);
|
|
277
|
-
if (!selectorSet) {
|
|
278
|
-
selectorSet = /* @__PURE__ */ new Set();
|
|
279
|
-
selectorOwners.set(record.selector, selectorSet);
|
|
280
|
-
}
|
|
281
|
-
selectorSet.add(location);
|
|
282
|
-
}
|
|
283
|
-
let classNameSet = classNameOwners.get(record.className);
|
|
284
|
-
if (!classNameSet) {
|
|
285
|
-
classNameSet = /* @__PURE__ */ new Set();
|
|
286
|
-
classNameOwners.set(record.className, classNameSet);
|
|
287
|
-
}
|
|
288
|
-
classNameSet.add(location);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
function removeStyleOwnerMetadata(file) {
|
|
292
|
-
const previous = transformedStyleOwnerMetadata.get(file);
|
|
293
|
-
if (!previous) return;
|
|
294
|
-
for (const record of previous) {
|
|
295
|
-
const owners = styleSourceOwners.get(record.sourcePath);
|
|
296
|
-
owners?.delete(record.ownerFile);
|
|
297
|
-
if (owners?.size === 0) styleSourceOwners.delete(record.sourcePath);
|
|
298
|
-
}
|
|
299
|
-
transformedStyleOwnerMetadata.delete(file);
|
|
300
|
-
}
|
|
301
|
-
function registerStyleOwnerMetadata(file, styleUrls) {
|
|
302
|
-
removeStyleOwnerMetadata(file);
|
|
303
|
-
const records = styleUrls.map((urlSet) => {
|
|
304
|
-
const [, absoluteFileUrl] = urlSet.split("|");
|
|
305
|
-
return absoluteFileUrl ? {
|
|
306
|
-
ownerFile: file,
|
|
307
|
-
sourcePath: normalizePath(absoluteFileUrl)
|
|
308
|
-
} : void 0;
|
|
309
|
-
}).filter((record) => !!record);
|
|
310
|
-
if (records.length === 0) return;
|
|
311
|
-
transformedStyleOwnerMetadata.set(file, records);
|
|
312
|
-
for (const record of records) {
|
|
313
|
-
let owners = styleSourceOwners.get(record.sourcePath);
|
|
314
|
-
if (!owners) {
|
|
315
|
-
owners = /* @__PURE__ */ new Set();
|
|
316
|
-
styleSourceOwners.set(record.sourcePath, owners);
|
|
317
|
-
}
|
|
318
|
-
owners.add(record.ownerFile);
|
|
319
|
-
}
|
|
130
|
+
function validateNoDuplicateAnalogPlugins(config) {
|
|
131
|
+
const analogInstances = (config.plugins ?? []).filter((p) => p.name === "@analogjs/vite-plugin-angular");
|
|
132
|
+
if (analogInstances.length > 1 && !config.build?.ssr) throw new Error(`[@analogjs/vite-plugin-angular] analog() is registered ${analogInstances.length} times. Each instance creates separate style maps, causing component styles to be lost. Remove duplicate registrations.`);
|
|
320
133
|
}
|
|
321
134
|
let stylesheetRegistry;
|
|
322
135
|
const sourceFileCache$1 = new sourceFileCache();
|
|
323
|
-
const isTest = process.env.NODE_ENV === "test" || !!process.env["VITEST"];
|
|
324
136
|
const isVitestVscode = !!process.env["VITEST_VSCODE"];
|
|
325
137
|
const isStackBlitz = !!process.versions["webcontainer"];
|
|
326
138
|
const isAstroIntegration = process.env["ANALOG_ASTRO"] === "true";
|
|
327
139
|
const jit = typeof pluginOptions?.jit !== "undefined" ? pluginOptions.jit : isTest;
|
|
328
140
|
let viteServer;
|
|
329
141
|
const styleUrlsResolver = new StyleUrlsResolver();
|
|
142
|
+
const guardContext = {
|
|
143
|
+
styleUrlsResolver,
|
|
144
|
+
activeGraphComponentMetadata,
|
|
145
|
+
selectorOwners,
|
|
146
|
+
classNameOwners,
|
|
147
|
+
transformedStyleOwnerMetadata,
|
|
148
|
+
styleSourceOwners
|
|
149
|
+
};
|
|
330
150
|
const templateUrlsResolver = new TemplateUrlsResolver();
|
|
331
151
|
let outputFile;
|
|
332
152
|
const outputFiles = /* @__PURE__ */ new Map();
|
|
@@ -367,7 +187,6 @@ function angular(options) {
|
|
|
367
187
|
let styleTransform;
|
|
368
188
|
let pendingCompilation;
|
|
369
189
|
let compilationLock = Promise.resolve();
|
|
370
|
-
let angularCompilation;
|
|
371
190
|
function angularPlugin() {
|
|
372
191
|
let isProd = false;
|
|
373
192
|
if (angularFullVersion < 19e4 && pluginOptions.liveReload) {
|
|
@@ -385,11 +204,6 @@ function angular(options) {
|
|
|
385
204
|
isTest
|
|
386
205
|
});
|
|
387
206
|
}
|
|
388
|
-
if (pluginOptions.useAngularCompilationAPI) if (angularFullVersion < 200100) {
|
|
389
|
-
pluginOptions.useAngularCompilationAPI = false;
|
|
390
|
-
debugCompilationApi("disabled: Angular version %s < 20.1", angularFullVersion);
|
|
391
|
-
console.warn("[@analogjs/vite-plugin-angular]: The Angular Compilation API is only available with Angular v20.1 and later");
|
|
392
|
-
} else debugCompilationApi("enabled (Angular %s)", angularFullVersion);
|
|
393
207
|
return {
|
|
394
208
|
name: "@analogjs/vite-plugin-angular",
|
|
395
209
|
async config(config, { command }) {
|
|
@@ -402,9 +216,8 @@ function angular(options) {
|
|
|
402
216
|
isLib: !!config?.build?.lib
|
|
403
217
|
};
|
|
404
218
|
const preliminaryTsConfigPath = resolveTsConfigPath();
|
|
405
|
-
const esbuild =
|
|
406
|
-
const oxc =
|
|
407
|
-
if (pluginOptions.useAngularCompilationAPI) debugCompilationApi("esbuild/oxc disabled, Angular handles transforms");
|
|
219
|
+
const esbuild = config.esbuild ?? false;
|
|
220
|
+
const oxc = config.oxc ?? false;
|
|
408
221
|
const defineOptions = {
|
|
409
222
|
ngJitMode: "false",
|
|
410
223
|
ngI18nClosureMode: "false",
|
|
@@ -446,11 +259,16 @@ function angular(options) {
|
|
|
446
259
|
},
|
|
447
260
|
configResolved(config) {
|
|
448
261
|
resolvedConfig = config;
|
|
449
|
-
if (
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
262
|
+
if (config.logger?.warnOnce) {
|
|
263
|
+
const originalWarnOnce = config.logger.warnOnce;
|
|
264
|
+
config.logger.warnOnce = (msg, options) => {
|
|
265
|
+
if (typeof msg === "string" && msg.includes("Sourcemap") && msg.includes("node_modules")) return;
|
|
266
|
+
originalWarnOnce(msg, options);
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
if (pluginOptions.hasTailwindCss) {
|
|
270
|
+
validateTailwindConfig(pluginOptions.tailwindCss, config, watchMode);
|
|
271
|
+
validateNoDuplicateAnalogPlugins(config);
|
|
454
272
|
}
|
|
455
273
|
if (!jit) styleTransform = (code, filename) => preprocessCSS(code, filename, config);
|
|
456
274
|
if (isTest) testWatchMode = !(config.server.watch === null) || config.test?.watch === true || testWatchMode;
|
|
@@ -461,8 +279,8 @@ function angular(options) {
|
|
|
461
279
|
server.watcher.on("add", invalidateCompilationOnFsChange);
|
|
462
280
|
server.watcher.on("unlink", (file) => {
|
|
463
281
|
evictDeletedFileMetadata(file, {
|
|
464
|
-
removeActiveGraphMetadata,
|
|
465
|
-
removeStyleOwnerMetadata,
|
|
282
|
+
removeActiveGraphMetadata: (f) => removeActiveGraphMetadata(guardContext, f),
|
|
283
|
+
removeStyleOwnerMetadata: (f) => removeStyleOwnerMetadata(guardContext, f),
|
|
466
284
|
classNamesMap: classNames,
|
|
467
285
|
fileTransformMap
|
|
468
286
|
});
|
|
@@ -773,24 +591,7 @@ function angular(options) {
|
|
|
773
591
|
classNames.clear();
|
|
774
592
|
return ctx.modules;
|
|
775
593
|
},
|
|
776
|
-
resolveId(id
|
|
777
|
-
if (id.startsWith("virtual:@analogjs/vite-plugin-angular:inline-style:") || id.startsWith("virtual:@analogjs/vite-plugin-angular:raw:")) return `\0${id}`;
|
|
778
|
-
if (jit && id.startsWith("angular:jit:")) {
|
|
779
|
-
const path = id.split(";")[1];
|
|
780
|
-
const resolved = normalizePath(resolve(dirname(importer), path));
|
|
781
|
-
if (id.includes(":style")) return toVirtualStyleId(resolved);
|
|
782
|
-
return toVirtualRawId(resolved);
|
|
783
|
-
}
|
|
784
|
-
if (id.includes(".html?raw")) {
|
|
785
|
-
const filePath = id.split("?")[0];
|
|
786
|
-
const resolved = isAbsolute(filePath) ? normalizePath(filePath) : importer ? normalizePath(resolve(dirname(importer), filePath)) : void 0;
|
|
787
|
-
if (resolved) return toVirtualRawId(resolved);
|
|
788
|
-
}
|
|
789
|
-
if (/\.(css|scss|sass|less)\?inline$/.test(id)) {
|
|
790
|
-
const filePath = id.split("?")[0];
|
|
791
|
-
const resolved = isAbsolute(filePath) ? normalizePath(filePath) : importer ? normalizePath(resolve(dirname(importer), filePath)) : void 0;
|
|
792
|
-
if (resolved) return toVirtualStyleId(resolved);
|
|
793
|
-
}
|
|
594
|
+
resolveId(id) {
|
|
794
595
|
if (isComponentStyleSheet(id)) {
|
|
795
596
|
const filename = getFilenameFromPath(id);
|
|
796
597
|
if (stylesheetRegistry?.hasServed(filename)) {
|
|
@@ -813,17 +614,6 @@ function angular(options) {
|
|
|
813
614
|
}
|
|
814
615
|
},
|
|
815
616
|
async load(id) {
|
|
816
|
-
const styleModule = await loadVirtualStyleModule(this, id, resolvedConfig);
|
|
817
|
-
if (styleModule !== void 0) return styleModule;
|
|
818
|
-
const rawModule = await loadVirtualRawModule(this, id);
|
|
819
|
-
if (rawModule !== void 0) return rawModule;
|
|
820
|
-
if (/\.(css|scss|sass|less)\?inline$/.test(id)) {
|
|
821
|
-
const filePath = id.split("?")[0];
|
|
822
|
-
const code = await promises.readFile(filePath, "utf-8");
|
|
823
|
-
if (!shouldPreprocessTestCss(resolvedConfig, filePath)) return `export default ${JSON.stringify(code)}`;
|
|
824
|
-
const result = await preprocessCSS(code, filePath, resolvedConfig);
|
|
825
|
-
return `export default ${JSON.stringify(result.code)}`;
|
|
826
|
-
}
|
|
827
617
|
if (isComponentStyleSheet(id)) {
|
|
828
618
|
const filename = getFilenameFromPath(id);
|
|
829
619
|
const componentStyles = stylesheetRegistry?.getServedContent(filename);
|
|
@@ -859,12 +649,6 @@ function angular(options) {
|
|
|
859
649
|
* Check for options.transformFilter
|
|
860
650
|
*/
|
|
861
651
|
if (options?.transformFilter && !(options?.transformFilter(code, id) ?? true)) return;
|
|
862
|
-
if (pluginOptions.useAngularCompilationAPI) {
|
|
863
|
-
if (!/(Component|Directive|Pipe|Injectable|NgModule)\(/.test(code)) {
|
|
864
|
-
debugCompilationApi("transform skip (non-Angular file)", { id });
|
|
865
|
-
return;
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
652
|
/**
|
|
869
653
|
* Skip transforming content files
|
|
870
654
|
*/
|
|
@@ -961,12 +745,29 @@ function angular(options) {
|
|
|
961
745
|
mkdirSync(declarationFileDir, { recursive: true });
|
|
962
746
|
writeFileSync(declarationPath, data, "utf-8");
|
|
963
747
|
});
|
|
964
|
-
angularCompilation?.close?.();
|
|
965
|
-
angularCompilation = void 0;
|
|
966
748
|
}
|
|
967
749
|
};
|
|
968
750
|
}
|
|
969
|
-
const compilationPlugin = pluginOptions.
|
|
751
|
+
const compilationPlugin = pluginOptions.useAngularCompilationAPI ? compilationAPIPlugin({
|
|
752
|
+
tsconfigGetter: pluginOptions.tsconfigGetter,
|
|
753
|
+
workspaceRoot: pluginOptions.workspaceRoot,
|
|
754
|
+
inlineStylesExtension: pluginOptions.inlineStylesExtension,
|
|
755
|
+
jit,
|
|
756
|
+
liveReload: pluginOptions.liveReload,
|
|
757
|
+
disableTypeChecking: pluginOptions.disableTypeChecking,
|
|
758
|
+
supportedBrowsers: pluginOptions.supportedBrowsers,
|
|
759
|
+
transformFilter: options?.transformFilter,
|
|
760
|
+
fileReplacements: pluginOptions.fileReplacements,
|
|
761
|
+
stylePreprocessor: pluginOptions.stylePreprocessor,
|
|
762
|
+
stylePipeline: options?.stylePipeline,
|
|
763
|
+
hasTailwindCss: pluginOptions.hasTailwindCss,
|
|
764
|
+
tailwindCss: pluginOptions.tailwindCss,
|
|
765
|
+
isTest,
|
|
766
|
+
isAstroIntegration,
|
|
767
|
+
include: pluginOptions.include,
|
|
768
|
+
additionalContentDirs: pluginOptions.additionalContentDirs,
|
|
769
|
+
debug: options?.debug
|
|
770
|
+
}) : pluginOptions.fastCompile ? fastCompilePlugin({
|
|
970
771
|
tsconfigGetter: pluginOptions.tsconfigGetter,
|
|
971
772
|
workspaceRoot: pluginOptions.workspaceRoot,
|
|
972
773
|
inlineStylesExtension: pluginOptions.inlineStylesExtension,
|
|
@@ -980,104 +781,9 @@ function angular(options) {
|
|
|
980
781
|
}) : angularPlugin();
|
|
981
782
|
return [
|
|
982
783
|
replaceFiles(pluginOptions.fileReplacements, pluginOptions.workspaceRoot),
|
|
983
|
-
{
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
transform(code, id) {
|
|
987
|
-
if (id.includes("node_modules")) return;
|
|
988
|
-
const cleanId = id.split("?")[0];
|
|
989
|
-
if (/\.(html|htm)$/i.test(cleanId)) {
|
|
990
|
-
const staticClassIssue = findStaticClassAndBoundClassConflicts(code)[0];
|
|
991
|
-
if (staticClassIssue) throwTemplateClassBindingConflict(cleanId, staticClassIssue);
|
|
992
|
-
const mixedClassIssue = findBoundClassAndNgClassConflicts(code)[0];
|
|
993
|
-
if (mixedClassIssue) this.warn([
|
|
994
|
-
"[Analog Angular] Conflicting class composition.",
|
|
995
|
-
`File: ${cleanId}:${mixedClassIssue.line}:${mixedClassIssue.column}`,
|
|
996
|
-
"This element mixes `[class]` and `[ngClass]`.",
|
|
997
|
-
"Prefer a single class-binding strategy so class merging stays predictable.",
|
|
998
|
-
"Use one `[ngClass]` expression or explicit `[class.foo]` bindings.",
|
|
999
|
-
`Snippet: ${mixedClassIssue.snippet}`
|
|
1000
|
-
].join("\n"));
|
|
1001
|
-
return;
|
|
1002
|
-
}
|
|
1003
|
-
if (TS_EXT_REGEX.test(cleanId)) {
|
|
1004
|
-
const rawStyleUrls = styleUrlsResolver.resolve(code, cleanId);
|
|
1005
|
-
registerStyleOwnerMetadata(cleanId, rawStyleUrls);
|
|
1006
|
-
debugHmrV("component stylesheet owner metadata registered", {
|
|
1007
|
-
file: cleanId,
|
|
1008
|
-
styleUrlCount: rawStyleUrls.length,
|
|
1009
|
-
styleUrls: rawStyleUrls,
|
|
1010
|
-
ownerSources: [...transformedStyleOwnerMetadata.get(cleanId)?.map((record) => record.sourcePath) ?? []]
|
|
1011
|
-
});
|
|
1012
|
-
const components = getAngularComponentMetadata(code);
|
|
1013
|
-
const inlineTemplateIssue = components.flatMap((component) => component.inlineTemplates.flatMap((template) => findStaticClassAndBoundClassConflicts(template)))[0];
|
|
1014
|
-
if (inlineTemplateIssue) throwTemplateClassBindingConflict(cleanId, inlineTemplateIssue);
|
|
1015
|
-
const mixedInlineClassIssue = components.flatMap((component) => component.inlineTemplates.flatMap((template) => findBoundClassAndNgClassConflicts(template)))[0];
|
|
1016
|
-
if (mixedInlineClassIssue) this.warn([
|
|
1017
|
-
"[Analog Angular] Conflicting class composition.",
|
|
1018
|
-
`File: ${cleanId}:${mixedInlineClassIssue.line}:${mixedInlineClassIssue.column}`,
|
|
1019
|
-
"This element mixes `[class]` and `[ngClass]`.",
|
|
1020
|
-
"Prefer a single class-binding strategy so class merging stays predictable.",
|
|
1021
|
-
"Use one `[ngClass]` expression or explicit `[class.foo]` bindings.",
|
|
1022
|
-
`Snippet: ${mixedInlineClassIssue.snippet}`
|
|
1023
|
-
].join("\n"));
|
|
1024
|
-
registerActiveGraphMetadata(cleanId, components.map((component) => ({
|
|
1025
|
-
file: cleanId,
|
|
1026
|
-
className: component.className,
|
|
1027
|
-
selector: component.selector
|
|
1028
|
-
})));
|
|
1029
|
-
for (const component of components) {
|
|
1030
|
-
if (!component.selector && !isLikelyPageOnlyComponent(cleanId)) throw new Error([
|
|
1031
|
-
"[Analog Angular] Selectorless component detected.",
|
|
1032
|
-
`File: ${cleanId}`,
|
|
1033
|
-
`Component: ${component.className}`,
|
|
1034
|
-
"This component has no `selector`, so Angular will render it as `ng-component`.",
|
|
1035
|
-
"That increases the chance of component ID collisions and makes diagnostics harder to interpret.",
|
|
1036
|
-
"Add an explicit selector for reusable components.",
|
|
1037
|
-
"Selectorless components are only supported for page and route-only files."
|
|
1038
|
-
].join("\n"));
|
|
1039
|
-
if (component.selector) {
|
|
1040
|
-
const selectorEntries = selectorOwners.get(component.selector);
|
|
1041
|
-
if (selectorEntries && selectorEntries.size > 1) throw new Error([
|
|
1042
|
-
"[Analog Angular] Duplicate component selector detected.",
|
|
1043
|
-
`Selector: ${component.selector}`,
|
|
1044
|
-
"Multiple components in the active application graph use the same selector.",
|
|
1045
|
-
"Selectors must be unique within the active graph to avoid ambiguous rendering and confusing diagnostics.",
|
|
1046
|
-
`Locations:\n${formatActiveGraphLocations(selectorEntries)}`
|
|
1047
|
-
].join("\n"));
|
|
1048
|
-
}
|
|
1049
|
-
const classNameEntries = classNameOwners.get(component.className);
|
|
1050
|
-
if (classNameEntries && classNameEntries.size > 1) this.warn([
|
|
1051
|
-
"[Analog Angular] Duplicate component class name detected.",
|
|
1052
|
-
`Class name: ${component.className}`,
|
|
1053
|
-
"Two or more Angular components in the active graph share the same exported class name.",
|
|
1054
|
-
"Rename one of them to keep HMR, stack traces, and compiler diagnostics unambiguous.",
|
|
1055
|
-
`Locations:\n${formatActiveGraphLocations(classNameEntries)}`
|
|
1056
|
-
].join("\n"));
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
},
|
|
1061
|
-
pluginOptions.hasTailwindCss && {
|
|
1062
|
-
name: "@analogjs/vite-plugin-angular:tailwind-reference",
|
|
1063
|
-
enforce: "pre",
|
|
1064
|
-
transform(code, id) {
|
|
1065
|
-
const tw = pluginOptions.tailwindCss;
|
|
1066
|
-
if (!tw || !id.includes(".css")) return;
|
|
1067
|
-
if (id.split("?")[0] === tw.rootStylesheet) return;
|
|
1068
|
-
const directiveState = inspectCssTailwindDirectives(code);
|
|
1069
|
-
if (directiveState.hasReferenceDirective || directiveState.hasTailwindImportDirective) return;
|
|
1070
|
-
const rootBasename = basename(tw.rootStylesheet);
|
|
1071
|
-
if (directiveState.commentlessCode.includes(rootBasename)) return;
|
|
1072
|
-
const prefixes = tw.prefixes;
|
|
1073
|
-
const needsRef = prefixes ? prefixes.some((p) => directiveState.commentlessCode.includes(p)) : directiveState.commentlessCode.includes("@apply");
|
|
1074
|
-
if (needsRef && directiveState.hasReferenceText) throwTailwindReferenceTextError(id, tw.rootStylesheet);
|
|
1075
|
-
if (needsRef) {
|
|
1076
|
-
debugTailwind("injected @reference via pre-transform", { id: id.split("/").slice(-2).join("/") });
|
|
1077
|
-
return `@reference "${tw.rootStylesheet.replace(/\\/g, "/")}";\n${code}`;
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
|
-
},
|
|
784
|
+
virtualModulesPlugin({ jit }),
|
|
785
|
+
templateClassBindingGuardPlugin(guardContext),
|
|
786
|
+
pluginOptions.hasTailwindCss && tailwindReferencePlugin({ tailwindCss: pluginOptions.tailwindCss }),
|
|
1081
787
|
angularPlugin(),
|
|
1082
788
|
pluginOptions.liveReload && liveReloadPlugin({
|
|
1083
789
|
classNames,
|
|
@@ -1097,457 +803,12 @@ function angular(options) {
|
|
|
1097
803
|
routerPlugin(),
|
|
1098
804
|
angularFullVersion < 190004 && pendingTasksPlugin(),
|
|
1099
805
|
nxFolderPlugin(),
|
|
1100
|
-
|
|
1101
|
-
name: "@analogjs/vite-plugin-angular:encapsulation",
|
|
1102
|
-
enforce: "post",
|
|
1103
|
-
transform(code, id) {
|
|
1104
|
-
if (shouldExternalizeStyles() && isComponentStyleSheet(id)) {
|
|
1105
|
-
const { encapsulation, componentId } = getComponentStyleSheetMeta(id);
|
|
1106
|
-
if (encapsulation === "emulated" && componentId) {
|
|
1107
|
-
debugStylesV("applying emulated view encapsulation (post)", {
|
|
1108
|
-
stylesheet: id.split("?")[0],
|
|
1109
|
-
componentId
|
|
1110
|
-
});
|
|
1111
|
-
return {
|
|
1112
|
-
code: ngCompiler.encapsulateStyle(code, componentId),
|
|
1113
|
-
map: null
|
|
1114
|
-
};
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
806
|
+
encapsulationPlugin(shouldExternalizeStyles)
|
|
1119
807
|
].filter(Boolean);
|
|
1120
|
-
function findIncludes() {
|
|
1121
|
-
const globs = pluginOptions.include.map((glob) => normalizeIncludeGlob(pluginOptions.workspaceRoot, glob));
|
|
1122
|
-
const files = globSync(globs, {
|
|
1123
|
-
dot: true,
|
|
1124
|
-
absolute: true
|
|
1125
|
-
});
|
|
1126
|
-
debugEmit("include discovery", {
|
|
1127
|
-
patternCount: globs.length,
|
|
1128
|
-
fileCount: files.length
|
|
1129
|
-
});
|
|
1130
|
-
debugEmitV("include discovery files", {
|
|
1131
|
-
globs,
|
|
1132
|
-
files: files.map((file) => normalizePath(file))
|
|
1133
|
-
});
|
|
1134
|
-
return files;
|
|
1135
|
-
}
|
|
1136
|
-
function ensureIncludeCache() {
|
|
1137
|
-
if (pluginOptions.include.length > 0 && includeCache.length === 0) {
|
|
1138
|
-
includeCache = findIncludes();
|
|
1139
|
-
debugEmit("include cache populated", { fileCount: includeCache.length });
|
|
1140
|
-
}
|
|
1141
|
-
return includeCache;
|
|
1142
|
-
}
|
|
1143
|
-
function getTsconfigCacheKey(resolvedTsConfigPath, config) {
|
|
1144
|
-
return [
|
|
1145
|
-
resolvedTsConfigPath,
|
|
1146
|
-
config.mode === "production" ? "prod" : "dev",
|
|
1147
|
-
isTest ? "test" : "app",
|
|
1148
|
-
config.build?.lib ? "lib" : "nolib",
|
|
1149
|
-
pluginOptions.liveReload ? "live-reload" : "no-live-reload",
|
|
1150
|
-
pluginOptions.hasTailwindCss ? "tw" : "notw"
|
|
1151
|
-
].join("|");
|
|
1152
|
-
}
|
|
1153
|
-
function readAngularTsconfigConfiguration(resolvedTsConfigPath, config) {
|
|
1154
|
-
const isProd = config.mode === "production";
|
|
1155
|
-
return compilerCli.readConfiguration(resolvedTsConfigPath, {
|
|
1156
|
-
suppressOutputPathCheck: true,
|
|
1157
|
-
outDir: void 0,
|
|
1158
|
-
sourceMap: false,
|
|
1159
|
-
inlineSourceMap: !isProd,
|
|
1160
|
-
inlineSources: !isProd,
|
|
1161
|
-
declaration: false,
|
|
1162
|
-
declarationMap: false,
|
|
1163
|
-
allowEmptyCodegenFiles: false,
|
|
1164
|
-
annotationsAs: "decorators",
|
|
1165
|
-
enableResourceInlining: false,
|
|
1166
|
-
noEmitOnError: false,
|
|
1167
|
-
mapRoot: void 0,
|
|
1168
|
-
sourceRoot: void 0,
|
|
1169
|
-
supportTestBed: false,
|
|
1170
|
-
supportJitMode: false
|
|
1171
|
-
});
|
|
1172
|
-
}
|
|
1173
|
-
function getCachedTsconfigOptions(resolvedTsConfigPath, config) {
|
|
1174
|
-
const tsconfigKey = getTsconfigCacheKey(resolvedTsConfigPath, config);
|
|
1175
|
-
let cached = tsconfigOptionsCache.get(tsconfigKey);
|
|
1176
|
-
if (!cached) {
|
|
1177
|
-
const read = readAngularTsconfigConfiguration(resolvedTsConfigPath, config);
|
|
1178
|
-
cached = {
|
|
1179
|
-
options: read.options,
|
|
1180
|
-
rootNames: read.rootNames
|
|
1181
|
-
};
|
|
1182
|
-
tsconfigOptionsCache.set(tsconfigKey, cached);
|
|
1183
|
-
debugEmit("tsconfig root names loaded", {
|
|
1184
|
-
resolvedTsConfigPath,
|
|
1185
|
-
rootNameCount: read.rootNames.length
|
|
1186
|
-
});
|
|
1187
|
-
debugEmitV("tsconfig root names", {
|
|
1188
|
-
resolvedTsConfigPath,
|
|
1189
|
-
rootNames: read.rootNames.map((file) => normalizePath(file))
|
|
1190
|
-
});
|
|
1191
|
-
}
|
|
1192
|
-
return cached;
|
|
1193
|
-
}
|
|
1194
|
-
function resolveReferenceTsconfigPath(referencePath, ownerTsconfigPath) {
|
|
1195
|
-
const ownerDir = dirname(ownerTsconfigPath);
|
|
1196
|
-
const resolvedReference = normalizePath(isAbsolute(referencePath) ? referencePath : resolve(ownerDir, referencePath));
|
|
1197
|
-
if (existsSync(resolvedReference)) {
|
|
1198
|
-
try {
|
|
1199
|
-
if (statSync(resolvedReference).isDirectory()) {
|
|
1200
|
-
const nestedTsconfig = join(resolvedReference, "tsconfig.json");
|
|
1201
|
-
return existsSync(nestedTsconfig) ? normalizePath(nestedTsconfig) : void 0;
|
|
1202
|
-
}
|
|
1203
|
-
} catch {
|
|
1204
|
-
return;
|
|
1205
|
-
}
|
|
1206
|
-
return resolvedReference;
|
|
1207
|
-
}
|
|
1208
|
-
if (!resolvedReference.endsWith(".json")) {
|
|
1209
|
-
const asJson = `${resolvedReference}.json`;
|
|
1210
|
-
if (existsSync(asJson)) return normalizePath(asJson);
|
|
1211
|
-
const nestedTsconfig = join(resolvedReference, "tsconfig.json");
|
|
1212
|
-
if (existsSync(nestedTsconfig)) return normalizePath(nestedTsconfig);
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
|
-
function collectTsconfigPathRoots(resolvedTsConfigPath, options, rawTsconfig) {
|
|
1216
|
-
const tsPaths = rawTsconfig.compilerOptions?.paths ?? options.paths;
|
|
1217
|
-
if (!tsPaths) return [];
|
|
1218
|
-
const tsconfigDir = dirname(resolvedTsConfigPath);
|
|
1219
|
-
const configuredBaseUrl = typeof options.baseUrl === "string" ? options.baseUrl : typeof rawTsconfig.compilerOptions?.baseUrl === "string" ? rawTsconfig.compilerOptions.baseUrl : void 0;
|
|
1220
|
-
const resolvedBaseUrl = configuredBaseUrl ? isAbsolute(configuredBaseUrl) ? configuredBaseUrl : resolve(tsconfigDir, configuredBaseUrl) : tsconfigDir;
|
|
1221
|
-
const discoveredRoots = /* @__PURE__ */ new Set();
|
|
1222
|
-
for (const targets of Object.values(tsPaths)) for (const target of targets) {
|
|
1223
|
-
const resolvedTarget = normalizePath(isAbsolute(target) ? target : resolve(resolvedBaseUrl, target));
|
|
1224
|
-
if (target.includes("*")) {
|
|
1225
|
-
for (const match of globSync(resolvedTarget, {
|
|
1226
|
-
dot: true,
|
|
1227
|
-
absolute: true
|
|
1228
|
-
})) discoveredRoots.add(normalizePath(match));
|
|
1229
|
-
continue;
|
|
1230
|
-
}
|
|
1231
|
-
if (existsSync(resolvedTarget)) discoveredRoots.add(resolvedTarget);
|
|
1232
|
-
}
|
|
1233
|
-
return [...discoveredRoots];
|
|
1234
|
-
}
|
|
1235
|
-
function collectExpandedTsconfigRoots(resolvedTsConfigPath, config, visited = /* @__PURE__ */ new Set()) {
|
|
1236
|
-
const normalizedTsConfigPath = normalizePath(resolvedTsConfigPath);
|
|
1237
|
-
if (visited.has(normalizedTsConfigPath)) return [];
|
|
1238
|
-
const tsconfigKey = `${getTsconfigCacheKey(normalizedTsConfigPath, config)}|graph`;
|
|
1239
|
-
const cached = tsconfigGraphRootCache.get(tsconfigKey);
|
|
1240
|
-
if (cached) return cached;
|
|
1241
|
-
visited.add(normalizedTsConfigPath);
|
|
1242
|
-
const read = readAngularTsconfigConfiguration(normalizedTsConfigPath, config);
|
|
1243
|
-
const rawTsconfig = ts.readConfigFile(normalizedTsConfigPath, ts.sys.readFile).config ?? {};
|
|
1244
|
-
const expandedRoots = new Set(read.rootNames.map((file) => normalizePath(file)));
|
|
1245
|
-
const pathRoots = collectTsconfigPathRoots(normalizedTsConfigPath, read.options, rawTsconfig);
|
|
1246
|
-
for (const pathRoot of pathRoots) expandedRoots.add(pathRoot);
|
|
1247
|
-
const referenceConfigs = (rawTsconfig.references ?? []).flatMap((reference) => typeof reference.path === "string" ? [resolveReferenceTsconfigPath(reference.path, normalizedTsConfigPath)] : []).filter((reference) => !!reference);
|
|
1248
|
-
for (const referenceConfig of referenceConfigs) for (const referenceRoot of collectExpandedTsconfigRoots(referenceConfig, config, visited)) expandedRoots.add(referenceRoot);
|
|
1249
|
-
const expandedRootList = [...expandedRoots];
|
|
1250
|
-
tsconfigGraphRootCache.set(tsconfigKey, expandedRootList);
|
|
1251
|
-
debugEmit("expanded tsconfig graph roots", {
|
|
1252
|
-
resolvedTsConfigPath: normalizedTsConfigPath,
|
|
1253
|
-
directRootNameCount: read.rootNames.length,
|
|
1254
|
-
pathRootCount: pathRoots.length,
|
|
1255
|
-
referenceConfigCount: referenceConfigs.length,
|
|
1256
|
-
expandedRootCount: expandedRootList.length
|
|
1257
|
-
});
|
|
1258
|
-
debugEmitV("expanded tsconfig graph root files", {
|
|
1259
|
-
resolvedTsConfigPath: normalizedTsConfigPath,
|
|
1260
|
-
pathRoots,
|
|
1261
|
-
referenceConfigs,
|
|
1262
|
-
rootNames: expandedRootList
|
|
1263
|
-
});
|
|
1264
|
-
return expandedRootList;
|
|
1265
|
-
}
|
|
1266
|
-
function resolveCompilationApiTsConfigPath(resolvedTsConfigPath, config) {
|
|
1267
|
-
const includedFiles = ensureIncludeCache();
|
|
1268
|
-
const cached = getCachedTsconfigOptions(resolvedTsConfigPath, config);
|
|
1269
|
-
const expandedGraphRoots = collectExpandedTsconfigRoots(resolvedTsConfigPath, config);
|
|
1270
|
-
const mergedRootNames = union(cached.rootNames, expandedGraphRoots, includedFiles).map((file) => normalizePath(file));
|
|
1271
|
-
if (mergedRootNames.length === cached.rootNames.length) return resolvedTsConfigPath;
|
|
1272
|
-
const wrapperDir = join(isAbsolute(config.cacheDir) ? config.cacheDir : resolve(config.root, config.cacheDir), "analog-angular", "compilation-api");
|
|
1273
|
-
const rawTsconfig = ts.readConfigFile(resolvedTsConfigPath, ts.sys.readFile).config ?? {};
|
|
1274
|
-
const wrapperPayload = {
|
|
1275
|
-
extends: normalizePath(resolvedTsConfigPath),
|
|
1276
|
-
files: [...mergedRootNames].sort(),
|
|
1277
|
-
...rawTsconfig.references ? { references: rawTsconfig.references } : {}
|
|
1278
|
-
};
|
|
1279
|
-
const wrapperPath = join(wrapperDir, `tsconfig.includes.${createHash("sha1").update(JSON.stringify(wrapperPayload)).digest("hex").slice(0, 12)}.json`);
|
|
1280
|
-
mkdirSync(wrapperDir, { recursive: true });
|
|
1281
|
-
if (!existsSync(wrapperPath)) writeFileSync(wrapperPath, `${JSON.stringify(wrapperPayload, null, 2)}\n`, "utf-8");
|
|
1282
|
-
debugCompilationApi("generated include wrapper tsconfig", {
|
|
1283
|
-
originalTsconfig: resolvedTsConfigPath,
|
|
1284
|
-
wrapperTsconfig: wrapperPath,
|
|
1285
|
-
includeCount: includedFiles.length,
|
|
1286
|
-
rootNameCount: mergedRootNames.length
|
|
1287
|
-
});
|
|
1288
|
-
debugEmit("wrapper tsconfig root merge", {
|
|
1289
|
-
originalTsconfig: resolvedTsConfigPath,
|
|
1290
|
-
wrapperTsconfig: wrapperPath,
|
|
1291
|
-
baseRootNameCount: cached.rootNames.length,
|
|
1292
|
-
expandedGraphRootCount: expandedGraphRoots.length,
|
|
1293
|
-
includeCount: includedFiles.length,
|
|
1294
|
-
mergedRootNameCount: mergedRootNames.length,
|
|
1295
|
-
referenceCount: rawTsconfig.references?.length ?? 0
|
|
1296
|
-
});
|
|
1297
|
-
debugEmitV("wrapper tsconfig root names", {
|
|
1298
|
-
wrapperTsconfig: wrapperPath,
|
|
1299
|
-
rootNames: mergedRootNames
|
|
1300
|
-
});
|
|
1301
|
-
return wrapperPath;
|
|
1302
|
-
}
|
|
1303
808
|
function resolveTsConfigPath() {
|
|
1304
809
|
const tsconfigValue = pluginOptions.tsconfigGetter();
|
|
1305
810
|
return getTsConfigPath(tsConfigResolutionContext.root, tsconfigValue, tsConfigResolutionContext.isProd, isTest, tsConfigResolutionContext.isLib);
|
|
1306
811
|
}
|
|
1307
|
-
/**
|
|
1308
|
-
* Perform compilation using Angular's private Compilation API.
|
|
1309
|
-
*
|
|
1310
|
-
* Key differences from the standard `performCompilation` path:
|
|
1311
|
-
* 1. The compilation instance is reused across rebuilds (nullish-coalescing
|
|
1312
|
-
* assignment below) so Angular retains prior state and can diff it to
|
|
1313
|
-
* produce `templateUpdates` for HMR.
|
|
1314
|
-
* 2. `ids` (modified files) are forwarded to both the source-file cache and
|
|
1315
|
-
* `angularCompilation.update()` so that incremental re-analysis is
|
|
1316
|
-
* scoped to what actually changed.
|
|
1317
|
-
* 3. `fileReplacements` are converted and passed into Angular's host via
|
|
1318
|
-
* `toAngularCompilationFileReplacements`.
|
|
1319
|
-
* 4. `templateUpdates` from the compilation result are mapped back to
|
|
1320
|
-
* file-level HMR metadata (`hmrUpdateCode`, `hmrEligible`, `classNames`).
|
|
1321
|
-
*/
|
|
1322
|
-
async function performAngularCompilation(config, ids) {
|
|
1323
|
-
const compilation = angularCompilation ??= await createAngularCompilation(!!pluginOptions.jit, false);
|
|
1324
|
-
const modifiedFiles = ids?.length ? new Set(ids.map((file) => normalizePath(file))) : void 0;
|
|
1325
|
-
if (modifiedFiles?.size) sourceFileCache$1.invalidate(modifiedFiles);
|
|
1326
|
-
if (modifiedFiles?.size && compilation.update) {
|
|
1327
|
-
debugCompilationApi("incremental update", { files: [...modifiedFiles] });
|
|
1328
|
-
await compilation.update(modifiedFiles);
|
|
1329
|
-
}
|
|
1330
|
-
const resolvedTsConfigPath = resolveTsConfigPath();
|
|
1331
|
-
const compilationApiTsConfigPath = resolveCompilationApiTsConfigPath(resolvedTsConfigPath, config);
|
|
1332
|
-
debugEmit("compilation initialize", {
|
|
1333
|
-
resolvedTsConfigPath,
|
|
1334
|
-
compilationApiTsConfigPath,
|
|
1335
|
-
modifiedFileCount: modifiedFiles?.size ?? 0
|
|
1336
|
-
});
|
|
1337
|
-
const compilationResult = await compilation.initialize(compilationApiTsConfigPath, {
|
|
1338
|
-
fileReplacements: toAngularCompilationFileReplacements(pluginOptions.fileReplacements, pluginOptions.workspaceRoot),
|
|
1339
|
-
modifiedFiles,
|
|
1340
|
-
async transformStylesheet(data, containingFile, resourceFile, order, className) {
|
|
1341
|
-
const filename = resourceFile ?? containingFile.replace(".ts", `.${pluginOptions.inlineStylesExtension}`);
|
|
1342
|
-
const preprocessed = preprocessStylesheetResult(data, filename, pluginOptions.stylePreprocessor, {
|
|
1343
|
-
filename,
|
|
1344
|
-
containingFile,
|
|
1345
|
-
resourceFile,
|
|
1346
|
-
className,
|
|
1347
|
-
order,
|
|
1348
|
-
inline: !resourceFile
|
|
1349
|
-
});
|
|
1350
|
-
if (shouldEnableLiveReload() && className && containingFile) classNames.set(normalizePath(containingFile), className);
|
|
1351
|
-
if (shouldExternalizeStyles()) {
|
|
1352
|
-
const stylesheetId = registerStylesheetContent(stylesheetRegistry, {
|
|
1353
|
-
code: preprocessed.code,
|
|
1354
|
-
dependencies: normalizeStylesheetDependencies(preprocessed.dependencies),
|
|
1355
|
-
diagnostics: preprocessed.diagnostics,
|
|
1356
|
-
tags: preprocessed.tags,
|
|
1357
|
-
containingFile,
|
|
1358
|
-
className,
|
|
1359
|
-
order,
|
|
1360
|
-
inlineStylesExtension: pluginOptions.inlineStylesExtension,
|
|
1361
|
-
resourceFile: resourceFile ?? void 0
|
|
1362
|
-
});
|
|
1363
|
-
debugStyles("stylesheet deferred to Vite pipeline", {
|
|
1364
|
-
stylesheetId,
|
|
1365
|
-
resourceFile: resourceFile ?? "(inline)"
|
|
1366
|
-
});
|
|
1367
|
-
debugStylesV("stylesheet deferred content snapshot", {
|
|
1368
|
-
stylesheetId,
|
|
1369
|
-
filename,
|
|
1370
|
-
resourceFile: resourceFile ?? "(inline)",
|
|
1371
|
-
dependencies: preprocessed.dependencies,
|
|
1372
|
-
diagnostics: preprocessed.diagnostics,
|
|
1373
|
-
tags: preprocessed.tags,
|
|
1374
|
-
...describeStylesheetContent(preprocessed.code)
|
|
1375
|
-
});
|
|
1376
|
-
return stylesheetId;
|
|
1377
|
-
}
|
|
1378
|
-
debugStyles("stylesheet processed inline via preprocessCSS", {
|
|
1379
|
-
filename,
|
|
1380
|
-
resourceFile: resourceFile ?? "(inline)",
|
|
1381
|
-
dataLength: preprocessed.code.length
|
|
1382
|
-
});
|
|
1383
|
-
if (!shouldPreprocessTestCss(resolvedConfig, filename)) return "";
|
|
1384
|
-
let stylesheetResult;
|
|
1385
|
-
try {
|
|
1386
|
-
stylesheetResult = await preprocessCSS(preprocessed.code, `${filename}?direct`, resolvedConfig);
|
|
1387
|
-
} catch (e) {
|
|
1388
|
-
if (isTailwindReferenceError(e)) throw e;
|
|
1389
|
-
debugStyles("preprocessCSS error", {
|
|
1390
|
-
filename,
|
|
1391
|
-
resourceFile: resourceFile ?? "(inline)",
|
|
1392
|
-
error: String(e)
|
|
1393
|
-
});
|
|
1394
|
-
}
|
|
1395
|
-
return stylesheetResult?.code || "";
|
|
1396
|
-
},
|
|
1397
|
-
processWebWorker(workerFile, containingFile) {
|
|
1398
|
-
return "";
|
|
1399
|
-
}
|
|
1400
|
-
}, (tsCompilerOptions) => {
|
|
1401
|
-
if (shouldExternalizeStyles()) tsCompilerOptions["externalRuntimeStyles"] = true;
|
|
1402
|
-
if (shouldEnableLiveReload()) {
|
|
1403
|
-
tsCompilerOptions["_enableHmr"] = true;
|
|
1404
|
-
tsCompilerOptions["supportTestBed"] = true;
|
|
1405
|
-
}
|
|
1406
|
-
debugCompiler("tsCompilerOptions (compilation API)", {
|
|
1407
|
-
liveReload: pluginOptions.liveReload,
|
|
1408
|
-
viteHmr: hasViteHmrTransport(),
|
|
1409
|
-
hasTailwindCss: pluginOptions.hasTailwindCss,
|
|
1410
|
-
watchMode,
|
|
1411
|
-
shouldExternalize: shouldExternalizeStyles(),
|
|
1412
|
-
externalRuntimeStyles: !!tsCompilerOptions["externalRuntimeStyles"],
|
|
1413
|
-
hmrEnabled: !!tsCompilerOptions["_enableHmr"]
|
|
1414
|
-
});
|
|
1415
|
-
if (tsCompilerOptions.compilationMode === "partial") {
|
|
1416
|
-
tsCompilerOptions["supportTestBed"] = true;
|
|
1417
|
-
tsCompilerOptions["supportJitMode"] = true;
|
|
1418
|
-
}
|
|
1419
|
-
if (!isTest && config.build?.lib) {
|
|
1420
|
-
tsCompilerOptions["declaration"] = true;
|
|
1421
|
-
tsCompilerOptions["declarationMap"] = watchMode;
|
|
1422
|
-
tsCompilerOptions["inlineSources"] = true;
|
|
1423
|
-
}
|
|
1424
|
-
if (isTest) tsCompilerOptions["supportTestBed"] = true;
|
|
1425
|
-
return tsCompilerOptions;
|
|
1426
|
-
});
|
|
1427
|
-
debugStyles("external stylesheets from compilation API", {
|
|
1428
|
-
count: compilationResult.externalStylesheets?.size ?? 0,
|
|
1429
|
-
hasPreprocessor: !!pluginOptions.stylePreprocessor,
|
|
1430
|
-
hasInlineMap: !!stylesheetRegistry
|
|
1431
|
-
});
|
|
1432
|
-
const preprocessStats = {
|
|
1433
|
-
total: 0,
|
|
1434
|
-
injected: 0,
|
|
1435
|
-
skipped: 0,
|
|
1436
|
-
errors: 0
|
|
1437
|
-
};
|
|
1438
|
-
for (const [key, value] of compilationResult.externalStylesheets ?? []) {
|
|
1439
|
-
preprocessStats.total++;
|
|
1440
|
-
const angularHash = `${value}.css`;
|
|
1441
|
-
stylesheetRegistry?.registerExternalRequest(angularHash, key);
|
|
1442
|
-
if (stylesheetRegistry && pluginOptions.stylePreprocessor && existsSync(key)) try {
|
|
1443
|
-
const rawCss = readFileSync(key, "utf-8");
|
|
1444
|
-
const preprocessed = preprocessStylesheetResult(rawCss, key, pluginOptions.stylePreprocessor);
|
|
1445
|
-
debugStylesV("external stylesheet raw snapshot", {
|
|
1446
|
-
angularHash,
|
|
1447
|
-
resolvedPath: key,
|
|
1448
|
-
mtimeMs: safeStatMtimeMs(key),
|
|
1449
|
-
...describeStylesheetContent(rawCss)
|
|
1450
|
-
});
|
|
1451
|
-
const servedCss = rewriteRelativeCssImports(preprocessed.code, key);
|
|
1452
|
-
stylesheetRegistry.registerServedStylesheet({
|
|
1453
|
-
publicId: angularHash,
|
|
1454
|
-
sourcePath: key,
|
|
1455
|
-
originalCode: rawCss,
|
|
1456
|
-
normalizedCode: servedCss,
|
|
1457
|
-
dependencies: normalizeStylesheetDependencies(preprocessed.dependencies),
|
|
1458
|
-
diagnostics: preprocessed.diagnostics,
|
|
1459
|
-
tags: preprocessed.tags
|
|
1460
|
-
}, [
|
|
1461
|
-
key,
|
|
1462
|
-
normalizePath(key),
|
|
1463
|
-
basename(key),
|
|
1464
|
-
key.replace(/^\//, "")
|
|
1465
|
-
]);
|
|
1466
|
-
if (servedCss && servedCss !== rawCss) {
|
|
1467
|
-
preprocessStats.injected++;
|
|
1468
|
-
debugStylesV("preprocessed external stylesheet for Tailwind @reference", {
|
|
1469
|
-
angularHash,
|
|
1470
|
-
resolvedPath: key,
|
|
1471
|
-
mtimeMs: safeStatMtimeMs(key),
|
|
1472
|
-
raw: describeStylesheetContent(rawCss),
|
|
1473
|
-
served: describeStylesheetContent(servedCss),
|
|
1474
|
-
dependencies: preprocessed.dependencies,
|
|
1475
|
-
diagnostics: preprocessed.diagnostics,
|
|
1476
|
-
tags: preprocessed.tags
|
|
1477
|
-
});
|
|
1478
|
-
} else {
|
|
1479
|
-
preprocessStats.skipped++;
|
|
1480
|
-
debugStylesV("external stylesheet unchanged after preprocessing", {
|
|
1481
|
-
angularHash,
|
|
1482
|
-
resolvedPath: key,
|
|
1483
|
-
mtimeMs: safeStatMtimeMs(key),
|
|
1484
|
-
raw: describeStylesheetContent(rawCss),
|
|
1485
|
-
served: describeStylesheetContent(servedCss),
|
|
1486
|
-
dependencies: preprocessed.dependencies,
|
|
1487
|
-
diagnostics: preprocessed.diagnostics,
|
|
1488
|
-
tags: preprocessed.tags,
|
|
1489
|
-
hint: "Registry mapping is still registered so Angular component stylesheet HMR can track and refresh this file even when preprocessing makes no textual changes."
|
|
1490
|
-
});
|
|
1491
|
-
}
|
|
1492
|
-
} catch (e) {
|
|
1493
|
-
preprocessStats.errors++;
|
|
1494
|
-
console.warn(`[@analogjs/vite-plugin-angular] failed to preprocess external stylesheet: ${key}: ${e}`);
|
|
1495
|
-
}
|
|
1496
|
-
else {
|
|
1497
|
-
preprocessStats.skipped++;
|
|
1498
|
-
debugStylesV("external stylesheet preprocessing skipped", {
|
|
1499
|
-
filename: angularHash,
|
|
1500
|
-
resolvedPath: key,
|
|
1501
|
-
reason: !stylesheetRegistry ? "no stylesheetRegistry" : !pluginOptions.stylePreprocessor ? "no stylePreprocessor" : "file not found on disk"
|
|
1502
|
-
});
|
|
1503
|
-
}
|
|
1504
|
-
debugStylesV("external stylesheet registered for resolveId mapping", {
|
|
1505
|
-
filename: angularHash,
|
|
1506
|
-
resolvedPath: key
|
|
1507
|
-
});
|
|
1508
|
-
}
|
|
1509
|
-
debugStyles("external stylesheet preprocessing complete", preprocessStats);
|
|
1510
|
-
const diagnostics = await compilation.diagnoseFiles(pluginOptions.disableTypeChecking ? DiagnosticModes.All & ~DiagnosticModes.Semantic : DiagnosticModes.All);
|
|
1511
|
-
const errors = diagnostics.errors?.length ? diagnostics.errors : [];
|
|
1512
|
-
const warnings = diagnostics.warnings?.length ? diagnostics.warnings : [];
|
|
1513
|
-
debugEmit("compilation diagnostics", {
|
|
1514
|
-
errorCount: errors.length,
|
|
1515
|
-
warningCount: warnings.length
|
|
1516
|
-
});
|
|
1517
|
-
const templateUpdates = mapTemplateUpdatesToFiles(compilationResult.templateUpdates);
|
|
1518
|
-
if (templateUpdates.size > 0) debugHmr("compilation API template updates", {
|
|
1519
|
-
count: templateUpdates.size,
|
|
1520
|
-
files: [...templateUpdates.keys()]
|
|
1521
|
-
});
|
|
1522
|
-
const affectedFiles = await compilation.emitAffectedFiles();
|
|
1523
|
-
debugEmit("emitAffectedFiles summary", {
|
|
1524
|
-
count: affectedFiles.length,
|
|
1525
|
-
templateUpdateCount: templateUpdates.size,
|
|
1526
|
-
knownOutputCountBefore: outputFiles.size
|
|
1527
|
-
});
|
|
1528
|
-
debugEmitV("emitAffectedFiles files", { files: affectedFiles.map((file) => normalizePath(file.filename)) });
|
|
1529
|
-
for (const file of affectedFiles) {
|
|
1530
|
-
const normalizedFilename = normalizePath(file.filename);
|
|
1531
|
-
const templateUpdate = templateUpdates.get(normalizedFilename);
|
|
1532
|
-
if (templateUpdate) classNames.set(normalizedFilename, templateUpdate.className);
|
|
1533
|
-
outputFiles.set(normalizedFilename, {
|
|
1534
|
-
content: file.contents,
|
|
1535
|
-
dependencies: [],
|
|
1536
|
-
errors: errors.map((error) => error.text || ""),
|
|
1537
|
-
warnings: warnings.map((warning) => warning.text || ""),
|
|
1538
|
-
hmrUpdateCode: templateUpdate?.code,
|
|
1539
|
-
hmrEligible: !!templateUpdate?.code
|
|
1540
|
-
});
|
|
1541
|
-
debugEmitV("registered compilation API output", {
|
|
1542
|
-
filename: normalizedFilename,
|
|
1543
|
-
...describeEmitMarkers(file.contents),
|
|
1544
|
-
hasTemplateUpdate: !!templateUpdate,
|
|
1545
|
-
errorCount: errors.length,
|
|
1546
|
-
warningCount: warnings.length,
|
|
1547
|
-
knownOutputCount: outputFiles.size
|
|
1548
|
-
});
|
|
1549
|
-
}
|
|
1550
|
-
}
|
|
1551
812
|
async function performCompilation(config, ids) {
|
|
1552
813
|
let resolve;
|
|
1553
814
|
const previousLock = compilationLock;
|
|
@@ -1566,16 +827,12 @@ function angular(options) {
|
|
|
1566
827
|
* It should not be called concurrently. Use `performCompilation` which wraps this method in a lock to ensure only one compilation runs at a time.
|
|
1567
828
|
*/
|
|
1568
829
|
async function _doPerformCompilation(config, ids) {
|
|
1569
|
-
if (pluginOptions.useAngularCompilationAPI) {
|
|
1570
|
-
debugCompilationApi("using compilation API path", { modifiedFiles: ids?.length ?? 0 });
|
|
1571
|
-
await performAngularCompilation(config, ids);
|
|
1572
|
-
return;
|
|
1573
|
-
}
|
|
1574
830
|
const isProd = config.mode === "production";
|
|
1575
831
|
const modifiedFiles = new Set(ids ?? []);
|
|
1576
832
|
sourceFileCache$1.invalidate(modifiedFiles);
|
|
1577
833
|
if (ids?.length) for (const id of ids || []) fileTransformMap.delete(id);
|
|
1578
|
-
const
|
|
834
|
+
const resolvedTsConfigPath = resolveTsConfigPath();
|
|
835
|
+
const cached = tsconfigResolver.getCachedTsconfigOptions(resolvedTsConfigPath, config);
|
|
1579
836
|
const tsCompilerOptions = { ...cached.options };
|
|
1580
837
|
let rootNames = [...cached.rootNames];
|
|
1581
838
|
if (shouldExternalizeStyles()) tsCompilerOptions["externalRuntimeStyles"] = true;
|
|
@@ -1601,7 +858,7 @@ function angular(options) {
|
|
|
1601
858
|
}
|
|
1602
859
|
if (isTest) tsCompilerOptions["supportTestBed"] = true;
|
|
1603
860
|
const replacements = pluginOptions.fileReplacements.map((rp) => join(pluginOptions.workspaceRoot, rp.ssr || rp.with));
|
|
1604
|
-
rootNames = union(rootNames, ensureIncludeCache(), replacements);
|
|
861
|
+
rootNames = union(rootNames, tsconfigResolver.ensureIncludeCache(), replacements);
|
|
1605
862
|
const hostKey = JSON.stringify(tsCompilerOptions);
|
|
1606
863
|
let host;
|
|
1607
864
|
if (cachedHost && cachedHostKey === hostKey) host = cachedHost;
|
|
@@ -1716,47 +973,6 @@ function createFsWatcherCacheInvalidator(invalidateFsCaches, invalidateTsconfigC
|
|
|
1716
973
|
};
|
|
1717
974
|
}
|
|
1718
975
|
/**
|
|
1719
|
-
* Convert Analog/Angular CLI-style file replacements into the flat record
|
|
1720
|
-
* expected by `AngularHostOptions.fileReplacements`.
|
|
1721
|
-
*
|
|
1722
|
-
* Only browser replacements (`{ replace, with }`) are converted. SSR-only
|
|
1723
|
-
* replacements (`{ replace, ssr }`) are left for the Vite runtime plugin to
|
|
1724
|
-
* handle — they should not be baked into the Angular compilation host because
|
|
1725
|
-
* that would apply them to both browser and server builds.
|
|
1726
|
-
*
|
|
1727
|
-
* Relative paths are resolved against `workspaceRoot` so that the host
|
|
1728
|
-
* receives the same absolute paths it would get from the Angular CLI.
|
|
1729
|
-
*/
|
|
1730
|
-
function toAngularCompilationFileReplacements(replacements, workspaceRoot) {
|
|
1731
|
-
const mappedReplacements = replacements.flatMap((replacement) => {
|
|
1732
|
-
if (!("with" in replacement)) return [];
|
|
1733
|
-
return [[isAbsolute(replacement.replace) ? replacement.replace : resolve(workspaceRoot, replacement.replace), isAbsolute(replacement.with) ? replacement.with : resolve(workspaceRoot, replacement.with)]];
|
|
1734
|
-
});
|
|
1735
|
-
return mappedReplacements.length ? Object.fromEntries(mappedReplacements) : void 0;
|
|
1736
|
-
}
|
|
1737
|
-
/**
|
|
1738
|
-
* Map Angular's `templateUpdates` (keyed by `encodedFilePath@ClassName`)
|
|
1739
|
-
* back to absolute file paths with their associated HMR code and component
|
|
1740
|
-
* class name.
|
|
1741
|
-
*
|
|
1742
|
-
* Angular's private Compilation API emits template update keys in the form
|
|
1743
|
-
* `encodeURIComponent(relativePath + '@' + className)`. We decode and resolve
|
|
1744
|
-
* them so the caller can look up updates by the same normalized absolute path
|
|
1745
|
-
* used elsewhere in the plugin (`outputFiles`, `classNames`, etc.).
|
|
1746
|
-
*/
|
|
1747
|
-
function mapTemplateUpdatesToFiles(templateUpdates) {
|
|
1748
|
-
const updatesByFile = /* @__PURE__ */ new Map();
|
|
1749
|
-
templateUpdates?.forEach((code, encodedUpdateId) => {
|
|
1750
|
-
const [file, className = ""] = decodeURIComponent(encodedUpdateId).split("@");
|
|
1751
|
-
const resolvedFile = normalizePath(resolve(process.cwd(), file));
|
|
1752
|
-
updatesByFile.set(resolvedFile, {
|
|
1753
|
-
className,
|
|
1754
|
-
code
|
|
1755
|
-
});
|
|
1756
|
-
});
|
|
1757
|
-
return updatesByFile;
|
|
1758
|
-
}
|
|
1759
|
-
/**
|
|
1760
976
|
* Returns every live Vite module that can legitimately represent a changed
|
|
1761
977
|
* Angular resource file.
|
|
1762
978
|
*
|
|
@@ -1805,13 +1021,6 @@ function isModuleForChangedResource(mod, changedFile, stylesheetRegistry) {
|
|
|
1805
1021
|
const requestPath = getFilenameFromPath(mod.id);
|
|
1806
1022
|
return normalizePath((stylesheetRegistry?.resolveExternalSource(requestPath) ?? stylesheetRegistry?.resolveExternalSource(requestPath.replace(/^\//, "")) ?? "").split("?")[0]) === normalizedChangedFile;
|
|
1807
1023
|
}
|
|
1808
|
-
function describeStylesheetContent(code) {
|
|
1809
|
-
return {
|
|
1810
|
-
length: code.length,
|
|
1811
|
-
digest: createHash("sha256").update(code).digest("hex").slice(0, 12),
|
|
1812
|
-
preview: code.replace(/\s+/g, " ").trim().slice(0, 160)
|
|
1813
|
-
};
|
|
1814
|
-
}
|
|
1815
1024
|
function safeStatMtimeMs(file) {
|
|
1816
1025
|
try {
|
|
1817
1026
|
return statSync(file).mtimeMs;
|
|
@@ -1819,50 +1028,6 @@ function safeStatMtimeMs(file) {
|
|
|
1819
1028
|
return;
|
|
1820
1029
|
}
|
|
1821
1030
|
}
|
|
1822
|
-
/**
|
|
1823
|
-
* Refreshes any already-served stylesheet records that map back to a changed
|
|
1824
|
-
* source file.
|
|
1825
|
-
*
|
|
1826
|
-
* This is the critical bridge for externalized Angular component styles during
|
|
1827
|
-
* HMR. Angular's resource watcher can notice that `/src/...component.css`
|
|
1828
|
-
* changed before Angular recompilation has had a chance to repopulate the
|
|
1829
|
-
* stylesheet registry. If we emit a CSS update against the existing virtual
|
|
1830
|
-
* stylesheet id without first refreshing the registry content, the browser gets
|
|
1831
|
-
* a hot update containing stale CSS. By rewriting the existing served records
|
|
1832
|
-
* from disk up front, HMR always pushes the latest source content.
|
|
1833
|
-
*/
|
|
1834
|
-
function refreshStylesheetRegistryForFile(file, stylesheetRegistry, stylePreprocessor) {
|
|
1835
|
-
const normalizedFile = normalizePath(file.split("?")[0]);
|
|
1836
|
-
if (!stylesheetRegistry || !existsSync(normalizedFile)) return;
|
|
1837
|
-
const publicIds = stylesheetRegistry.getPublicIdsForSource(normalizedFile);
|
|
1838
|
-
if (publicIds.length === 0) return;
|
|
1839
|
-
const rawCss = readFileSync(normalizedFile, "utf-8");
|
|
1840
|
-
const preprocessed = preprocessStylesheetResult(rawCss, normalizedFile, stylePreprocessor);
|
|
1841
|
-
const servedCss = rewriteRelativeCssImports(preprocessed.code, normalizedFile);
|
|
1842
|
-
for (const publicId of publicIds) stylesheetRegistry.registerServedStylesheet({
|
|
1843
|
-
publicId,
|
|
1844
|
-
sourcePath: normalizedFile,
|
|
1845
|
-
originalCode: rawCss,
|
|
1846
|
-
normalizedCode: servedCss,
|
|
1847
|
-
dependencies: normalizeStylesheetDependencies(preprocessed.dependencies),
|
|
1848
|
-
diagnostics: preprocessed.diagnostics,
|
|
1849
|
-
tags: preprocessed.tags
|
|
1850
|
-
}, [
|
|
1851
|
-
normalizedFile,
|
|
1852
|
-
normalizePath(normalizedFile),
|
|
1853
|
-
basename(normalizedFile),
|
|
1854
|
-
normalizedFile.replace(/^\//, "")
|
|
1855
|
-
]);
|
|
1856
|
-
debugStylesV("stylesheet registry refreshed from source file", {
|
|
1857
|
-
file: normalizedFile,
|
|
1858
|
-
publicIds,
|
|
1859
|
-
dependencies: preprocessed.dependencies,
|
|
1860
|
-
diagnostics: preprocessed.diagnostics,
|
|
1861
|
-
tags: preprocessed.tags,
|
|
1862
|
-
source: describeStylesheetContent(rawCss),
|
|
1863
|
-
served: describeStylesheetContent(servedCss)
|
|
1864
|
-
});
|
|
1865
|
-
}
|
|
1866
1031
|
function diagnoseComponentStylesheetPipeline(changedFile, directModule, stylesheetRegistry, wrapperModules, stylePreprocessor) {
|
|
1867
1032
|
const normalizedFile = normalizePath(changedFile.split("?")[0]);
|
|
1868
1033
|
const sourceExists = existsSync(normalizedFile);
|
|
@@ -1996,83 +1161,6 @@ function resolveComponentClassNamesForStyleOwner(ownerFile, sourcePath) {
|
|
|
1996
1161
|
const normalizedSourcePath = normalizePath(sourcePath);
|
|
1997
1162
|
return components.filter((component) => component.styleUrls.some((styleUrl) => normalizePath(resolve(dirname(ownerFile), styleUrl)) === normalizedSourcePath)).map((component) => component.className);
|
|
1998
1163
|
}
|
|
1999
|
-
function findStaticClassAndBoundClassConflicts(template) {
|
|
2000
|
-
const issues = [];
|
|
2001
|
-
for (const { index, snippet } of findOpeningTagSnippets(template)) {
|
|
2002
|
-
if (!snippet.includes("[class]")) continue;
|
|
2003
|
-
const hasStaticClass = /\sclass\s*=\s*(['"])(?:(?!\1)[\s\S])*\1/.test(snippet);
|
|
2004
|
-
const hasBoundClass = /\s\[class\]\s*=\s*(['"])(?:(?!\1)[\s\S])*\1/.test(snippet);
|
|
2005
|
-
if (hasStaticClass && hasBoundClass) {
|
|
2006
|
-
const prefix = template.slice(0, index);
|
|
2007
|
-
const line = prefix.split("\n").length;
|
|
2008
|
-
const column = index - prefix.lastIndexOf("\n");
|
|
2009
|
-
issues.push({
|
|
2010
|
-
line,
|
|
2011
|
-
column,
|
|
2012
|
-
snippet: snippet.replace(/\s+/g, " ").trim()
|
|
2013
|
-
});
|
|
2014
|
-
}
|
|
2015
|
-
}
|
|
2016
|
-
return issues;
|
|
2017
|
-
}
|
|
2018
|
-
function throwTemplateClassBindingConflict(id, issue) {
|
|
2019
|
-
throw new Error([
|
|
2020
|
-
"[Analog Angular] Invalid template class binding.",
|
|
2021
|
-
`File: ${id}:${issue.line}:${issue.column}`,
|
|
2022
|
-
"The same element uses both a static `class=\"...\"` attribute and a whole-element `[class]=\"...\"` binding.",
|
|
2023
|
-
"That pattern can replace or conflict with static Tailwind classes, which makes styles appear to stop applying.",
|
|
2024
|
-
"Use `[ngClass]` or explicit `[class.foo]` bindings instead of `[class]` when the element also has static classes.",
|
|
2025
|
-
`Snippet: ${issue.snippet}`
|
|
2026
|
-
].join("\n"));
|
|
2027
|
-
}
|
|
2028
|
-
function findBoundClassAndNgClassConflicts(template) {
|
|
2029
|
-
const issues = [];
|
|
2030
|
-
if (!/\[class\]\s*=/.test(template) || !template.includes("[ngClass]")) return issues;
|
|
2031
|
-
for (const { index, snippet } of findOpeningTagSnippets(template)) {
|
|
2032
|
-
if (!/\[class\]\s*=/.test(snippet) || !snippet.includes("[ngClass]")) continue;
|
|
2033
|
-
const prefix = template.slice(0, index);
|
|
2034
|
-
const line = prefix.split("\n").length;
|
|
2035
|
-
const column = index - prefix.lastIndexOf("\n");
|
|
2036
|
-
issues.push({
|
|
2037
|
-
line,
|
|
2038
|
-
column,
|
|
2039
|
-
snippet: snippet.replace(/\s+/g, " ").trim()
|
|
2040
|
-
});
|
|
2041
|
-
}
|
|
2042
|
-
return issues;
|
|
2043
|
-
}
|
|
2044
|
-
function findOpeningTagSnippets(template) {
|
|
2045
|
-
const matches = [];
|
|
2046
|
-
for (let index = 0; index < template.length; index++) {
|
|
2047
|
-
if (template[index] !== "<") continue;
|
|
2048
|
-
const tagStart = template[index + 1];
|
|
2049
|
-
if (!tagStart || !/[a-zA-Z]/.test(tagStart)) continue;
|
|
2050
|
-
let quote = null;
|
|
2051
|
-
for (let end = index + 1; end < template.length; end++) {
|
|
2052
|
-
const char = template[end];
|
|
2053
|
-
if (quote) {
|
|
2054
|
-
if (char === quote) quote = null;
|
|
2055
|
-
continue;
|
|
2056
|
-
}
|
|
2057
|
-
if (char === "\"" || char === "'") {
|
|
2058
|
-
quote = char;
|
|
2059
|
-
continue;
|
|
2060
|
-
}
|
|
2061
|
-
if (char === ">") {
|
|
2062
|
-
matches.push({
|
|
2063
|
-
index,
|
|
2064
|
-
snippet: template.slice(index, end + 1)
|
|
2065
|
-
});
|
|
2066
|
-
index = end;
|
|
2067
|
-
break;
|
|
2068
|
-
}
|
|
2069
|
-
}
|
|
2070
|
-
}
|
|
2071
|
-
return matches;
|
|
2072
|
-
}
|
|
2073
|
-
function formatActiveGraphLocations(entries) {
|
|
2074
|
-
return [...entries].sort().map((entry) => `- ${entry}`).join("\n");
|
|
2075
|
-
}
|
|
2076
1164
|
function logComponentStylesheetHmrOutcome(details) {
|
|
2077
1165
|
const pitfalls = [];
|
|
2078
1166
|
const rejectedPreferredPaths = [];
|
|
@@ -2188,20 +1276,6 @@ function markModuleSelfAccepting(mod) {
|
|
|
2188
1276
|
isSelfAccepting: true
|
|
2189
1277
|
};
|
|
2190
1278
|
}
|
|
2191
|
-
function isComponentStyleSheet(id) {
|
|
2192
|
-
return id.includes("ngcomp=");
|
|
2193
|
-
}
|
|
2194
|
-
function getComponentStyleSheetMeta(id) {
|
|
2195
|
-
const params = new URL(id, "http://localhost").searchParams;
|
|
2196
|
-
return {
|
|
2197
|
-
componentId: params.get("ngcomp"),
|
|
2198
|
-
encapsulation: {
|
|
2199
|
-
"0": "emulated",
|
|
2200
|
-
"2": "none",
|
|
2201
|
-
"3": "shadow"
|
|
2202
|
-
}[params.get("e")]
|
|
2203
|
-
};
|
|
2204
|
-
}
|
|
2205
1279
|
/**
|
|
2206
1280
|
* Removes leading / and query string from a url path
|
|
2207
1281
|
* e.g. /foo.scss?direct&ngcomp=ng-c3153525609&e=0 returns foo.scss
|
|
@@ -2219,15 +1293,6 @@ function getFilenameFromPath(id) {
|
|
|
2219
1293
|
* Checks for vitest run from the command line
|
|
2220
1294
|
* @returns boolean
|
|
2221
1295
|
*/
|
|
2222
|
-
function isTestWatchMode(args = process.argv) {
|
|
2223
|
-
if (args.find((arg) => arg.includes("--run"))) return false;
|
|
2224
|
-
if (args.find((arg) => arg.includes("--no-run"))) return true;
|
|
2225
|
-
const hasWatch = args.find((arg) => arg.includes("watch"));
|
|
2226
|
-
if (hasWatch && ["false", "no"].some((neg) => hasWatch.includes(neg))) return false;
|
|
2227
|
-
const watchArg = args[args.findIndex((arg) => arg.includes("watch")) + 1];
|
|
2228
|
-
if (watchArg && watchArg === "false") return false;
|
|
2229
|
-
return true;
|
|
2230
|
-
}
|
|
2231
1296
|
//#endregion
|
|
2232
1297
|
export { angular };
|
|
2233
1298
|
|