@animus-ui/vite-plugin 0.1.4 → 0.1.6
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/dist/build-start.d.ts.map +1 -1
- package/dist/constants.d.ts +22 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/context.d.ts +69 -9
- package/dist/context.d.ts.map +1 -1
- package/dist/hmr.d.ts +1 -1
- package/dist/hmr.d.ts.map +1 -1
- package/dist/hot-update-events.d.ts +15 -1
- package/dist/hot-update-events.d.ts.map +1 -1
- package/dist/index-html.d.ts +9 -7
- package/dist/index-html.d.ts.map +1 -1
- package/dist/index.cjs +356 -124
- package/dist/index.d.ts.map +1 -1
- package/dist/transform.d.ts +16 -2
- package/dist/transform.d.ts.map +1 -1
- package/dist/virtual-modules.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-start.d.ts","sourceRoot":"","sources":["../src/build-start.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,aAAa,EAClB,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,EAC/D,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,MAAM,GAC3D,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"build-start.d.ts","sourceRoot":"","sources":["../src/build-start.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,aAAa,EAClB,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,EAC/D,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,MAAM,GAC3D,OAAO,CAAC,IAAI,CAAC,CAuRf"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,9 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The namespace every virtual module this plugin owns lives under. Exported so
|
|
3
|
+
* the `transform` guard that keeps those modules out of source-file handling
|
|
4
|
+
* matches on the same string the ids are built from — a rename of the
|
|
5
|
+
* namespace cannot leave the guard behind.
|
|
6
|
+
*/
|
|
7
|
+
export declare const VIRTUAL_PREFIX = "virtual:animus/";
|
|
1
8
|
export declare const VIRTUAL_CSS_ID = "virtual:animus/styles.css";
|
|
2
9
|
export declare const RESOLVED_CSS_ID = "\0virtual:animus/styles.css";
|
|
3
10
|
export declare const VIRTUAL_COMPONENTS_ID = "virtual:animus/components.js";
|
|
4
11
|
export declare const RESOLVED_COMPONENTS_ID = "\0virtual:animus/components.js";
|
|
5
12
|
export declare const VIRTUAL_BRIDGE_ID = "virtual:animus/hmr-bridge.js";
|
|
6
13
|
export declare const RESOLVED_BRIDGE_ID = "\0virtual:animus/hmr-bridge.js";
|
|
14
|
+
/**
|
|
15
|
+
* Browser-addressable URL for the bridge, used as the `src` of the dev
|
|
16
|
+
* `<script type="module">` (see index-html.ts). THE explanation of the `/@id/`
|
|
17
|
+
* convention lives here; everything else points at it.
|
|
18
|
+
*
|
|
19
|
+
* Vite reserves `/@id/` for module ids that are not file paths. Its transform
|
|
20
|
+
* middleware normalizes such a URL before serving it (`unwrapId`): strip the
|
|
21
|
+
* prefix, then decode the `__x00__` placeholder back to a NUL byte. The
|
|
22
|
+
* UNPREFIXED specifier is what travels here — `resolveVirtualId` is the hook
|
|
23
|
+
* that answers it, and it answers with the `\0` form. (Vite's own `wrapId`
|
|
24
|
+
* encodes an already-`\0`-prefixed id as `__x00__`; that form resolves too, but
|
|
25
|
+
* it leans on the placeholder convention rather than on this plugin's own
|
|
26
|
+
* `resolveId` contract.)
|
|
27
|
+
*/
|
|
28
|
+
export declare const BRIDGE_SCRIPT_SRC = "/@id/virtual:animus/hmr-bridge.js";
|
|
7
29
|
export declare const VIRTUAL_SYSTEM_PROPS_ID = "virtual:animus/system-props";
|
|
8
30
|
export declare const RESOLVED_SYSTEM_PROPS_ID = "\0virtual:animus/system-props";
|
|
9
31
|
export declare const DEFAULT_EXCLUDE: string[];
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,cAAc,oBAAoB,CAAC;AAEhD,eAAO,MAAM,cAAc,8BAAgC,CAAC;AAC5D,eAAO,MAAM,eAAe,gCAAwB,CAAC;AAErD,eAAO,MAAM,qBAAqB,iCAAmC,CAAC;AACtE,eAAO,MAAM,sBAAsB,mCAA+B,CAAC;AAEnE,eAAO,MAAM,iBAAiB,iCAAmC,CAAC;AAClE,eAAO,MAAM,kBAAkB,mCAA2B,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,sCAA8B,CAAC;AAE7D,eAAO,MAAM,uBAAuB,gCAAkC,CAAC;AACvE,eAAO,MAAM,wBAAwB,kCAAiC,CAAC;AAEvE,eAAO,MAAM,eAAe,UAA+C,CAAC"}
|
package/dist/context.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { HotUpdateEvents } from './hot-update-events';
|
|
2
2
|
import type { LightningTargets } from './css';
|
|
3
3
|
import type { AnimusExtractOptions } from './index';
|
|
4
|
-
import type { ExternalPackageOutcome, SystemConfig } from '@animus-ui/extract/pipeline';
|
|
4
|
+
import type { ExternalPackageOutcome, ManifestDiagnostic, SystemConfig } from '@animus-ui/extract/pipeline';
|
|
5
5
|
import type { Logger } from 'vite';
|
|
6
6
|
/**
|
|
7
7
|
* Structured per-layer CSS sheets from the Rust crate (dev split delivery).
|
|
@@ -33,6 +33,45 @@ export declare function buildFileEntriesFromCache(cache: Map<string, {
|
|
|
33
33
|
source: string;
|
|
34
34
|
hash: string;
|
|
35
35
|
}>;
|
|
36
|
+
/**
|
|
37
|
+
* The exact source `virtual:animus/system-props` serves for the current state.
|
|
38
|
+
* One definition, so the served bytes and the change decision below can never
|
|
39
|
+
* be computed from different inputs.
|
|
40
|
+
*
|
|
41
|
+
* A real context carries the module already generated (`systemPropsModuleMemo`,
|
|
42
|
+
* refreshed wherever the four inputs move), so serving it and deciding whether
|
|
43
|
+
* it changed are both reads. Contexts that publish those inputs by hand — the
|
|
44
|
+
* behavioral test doubles — carry no memo and generate here instead.
|
|
45
|
+
*/
|
|
46
|
+
export declare function systemPropsModuleSource(ctx: PluginContext): string;
|
|
47
|
+
/**
|
|
48
|
+
* Run project analysis and report whether the served system-props module
|
|
49
|
+
* CHANGED.
|
|
50
|
+
*
|
|
51
|
+
* The module is imported by every module that renders a system prop, so
|
|
52
|
+
* re-delivering it pushes an update through all of them; every analysis
|
|
53
|
+
* republishes its inputs whether or not they moved, so a new analysis is not
|
|
54
|
+
* itself an admissible trigger (openspec: vite-extraction-plugin, "System prop
|
|
55
|
+
* map HMR invalidation").
|
|
56
|
+
*
|
|
57
|
+
* The comparison is over the GENERATED MODULE, not over the prop map alone.
|
|
58
|
+
* The map is one of four inputs, and they move independently: widening a
|
|
59
|
+
* component's `.system({ ... })` opt-in adds a `dynamicPropConfig` entry while
|
|
60
|
+
* minting no new utility class, so a map-only comparison reports "unchanged"
|
|
61
|
+
* and the client is left with a config missing the new prop — permanently,
|
|
62
|
+
* since Vite keeps serving the module's cached transform result across full
|
|
63
|
+
* page reloads. Comparing the artifact itself needs no argument about which
|
|
64
|
+
* inputs are volatile this month.
|
|
65
|
+
*
|
|
66
|
+
* A free function rather than a method: the comparison must run for real
|
|
67
|
+
* against any context the caller holds, including the behavioral test doubles
|
|
68
|
+
* that stand in for the engine.
|
|
69
|
+
*/
|
|
70
|
+
export declare function runAnalysisTrackingSystemProps(ctx: PluginContext, fileEntries: Array<{
|
|
71
|
+
path: string;
|
|
72
|
+
source: string;
|
|
73
|
+
hash?: string;
|
|
74
|
+
}>): boolean;
|
|
36
75
|
/**
|
|
37
76
|
* Drop a deleted (or renamed-away) file from the dev file cache so its
|
|
38
77
|
* last-known source stops riding along as a ghost entry on every later
|
|
@@ -52,7 +91,7 @@ export declare function pruneFileCache(cache: Map<string, {
|
|
|
52
91
|
* index.ts only wires Vite hooks to those functions.
|
|
53
92
|
*
|
|
54
93
|
* A class rather than closure variables so each hook module names exactly
|
|
55
|
-
* the state it touches, and the engine store (
|
|
94
|
+
* the state it touches, and the engine store (per-instance, never
|
|
56
95
|
* module-level) is explicit.
|
|
57
96
|
*/
|
|
58
97
|
export declare class PluginContext {
|
|
@@ -74,16 +113,24 @@ export declare class PluginContext {
|
|
|
74
113
|
resolvedComponentCss: string;
|
|
75
114
|
storedSheets: CssSheets | null;
|
|
76
115
|
layerDeclaration: string;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
116
|
+
transformOutputHashes: Map<string, string>;
|
|
117
|
+
recordTransformOutput(relativePath: string, code: string): void;
|
|
118
|
+
/**
|
|
119
|
+
* Merge `Keyframes` collections from discovered external package entries
|
|
120
|
+
* into the system's collections (keyframes-only carve-out — the consumer
|
|
121
|
+
* system stays the singular config authority). Runs after buildStart
|
|
122
|
+
* discovery AND after every geological-reset system reload, since a reload
|
|
123
|
+
* rebuilds `this.system` from the consumer entry alone.
|
|
124
|
+
*/
|
|
125
|
+
applyExternalKeyframes(): void;
|
|
126
|
+
/** Discovery-time keyframes diagnostics awaiting the next analysis's
|
|
127
|
+
* shared surfacing pass. */
|
|
128
|
+
externalKeyframesDiagnostics: ManifestDiagnostic[];
|
|
83
129
|
reverseProvenance: Record<string, string[]>;
|
|
84
130
|
storedSystemPropMapJson: string;
|
|
85
131
|
storedDynamicPropsJson: string;
|
|
86
132
|
storedTransformsSource: string;
|
|
133
|
+
systemPropsModuleMemo: string | null;
|
|
87
134
|
fileCache: Map<string, {
|
|
88
135
|
hash: string;
|
|
89
136
|
source: string;
|
|
@@ -100,7 +147,6 @@ export declare class PluginContext {
|
|
|
100
147
|
externalSourceEntries: Map<string, string>;
|
|
101
148
|
externalPackageOutcomes: ExternalPackageOutcome[];
|
|
102
149
|
devServer: any;
|
|
103
|
-
bridgeInjected: boolean;
|
|
104
150
|
resolvedSystemPath: string | null;
|
|
105
151
|
systemDependencyKeys: Set<string>;
|
|
106
152
|
systemDependencyPaths: string[];
|
|
@@ -111,6 +157,13 @@ export declare class PluginContext {
|
|
|
111
157
|
readonly engineApi: () => any;
|
|
112
158
|
constructor(options: AnimusExtractOptions, engineApiOverride?: () => any);
|
|
113
159
|
log(msg: string): void;
|
|
160
|
+
/**
|
|
161
|
+
* Standard-level information — emitted whether or not `verbose` is on.
|
|
162
|
+
* Reserved for events a developer must see without opting in, e.g. a file
|
|
163
|
+
* created after buildStart being folded into the analysis (openspec:
|
|
164
|
+
* hmr-new-file-detection, "New file detection logging").
|
|
165
|
+
*/
|
|
166
|
+
info(msg: string): void;
|
|
114
167
|
warn(msg: string): void;
|
|
115
168
|
logTimingWaterfall(timing: Record<string, number>): void;
|
|
116
169
|
/**
|
|
@@ -197,6 +250,13 @@ export declare class PluginContext {
|
|
|
197
250
|
* `getModuleById` searches the client AND ssr environment graphs and its
|
|
198
251
|
* `invalidateModule` invalidates both instances behind the returned node,
|
|
199
252
|
* which is exactly the reach this path wants. It stays the seam here.
|
|
253
|
+
*
|
|
254
|
+
* Both modules are invalidated unconditionally, and deliberately so: the
|
|
255
|
+
* appearance or disappearance of a whole component file is not the
|
|
256
|
+
* steady-state edit the change-gated path governs, and a client reload does
|
|
257
|
+
* NOT rescue a module that was never invalidated — Vite keeps serving its
|
|
258
|
+
* cached transform result across reloads (openspec: hmr-new-file-detection,
|
|
259
|
+
* "CSS invalidation after new file analysis").
|
|
200
260
|
*/
|
|
201
261
|
invalidateExtractedModules(): void;
|
|
202
262
|
/**
|
package/dist/context.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
|
package/dist/hmr.d.ts
CHANGED
|
@@ -19,5 +19,5 @@ import type { DevEnvironment, EnvironmentModuleNode, HotUpdateOptions } from 'vi
|
|
|
19
19
|
* graph, so system dependencies registered through `watcher.add` outside the
|
|
20
20
|
* root still reach the reset branch, with an empty `modules` list.
|
|
21
21
|
*/
|
|
22
|
-
export declare function handleHotUpdate(ctx: PluginContext, environment: DevEnvironment, { type, file, timestamp, modules }: HotUpdateOptions): Promise<EnvironmentModuleNode[] | void>;
|
|
22
|
+
export declare function handleHotUpdate(ctx: PluginContext, environment: DevEnvironment, { type, file, timestamp, modules, read }: HotUpdateOptions): Promise<EnvironmentModuleNode[] | void>;
|
|
23
23
|
//# sourceMappingURL=hmr.d.ts.map
|
package/dist/hmr.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hmr.d.ts","sourceRoot":"","sources":["../src/hmr.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hmr.d.ts","sourceRoot":"","sources":["../src/hmr.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,MAAM,CAAC;AAEd;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,aAAa,EAClB,WAAW,EAAE,cAAc,EAC3B,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,gBAAgB,GACzD,OAAO,CAAC,qBAAqB,EAAE,GAAG,IAAI,CAAC,CAmEzC"}
|
|
@@ -9,7 +9,19 @@
|
|
|
9
9
|
* - `analyzed` — re-analysis ran; every environment invalidates the affected
|
|
10
10
|
* modules in its own graph. `staleDefinitionFiles` are rootDir-relative
|
|
11
11
|
* definition files whose component replacement changed (the changed file
|
|
12
|
-
* itself is never listed).
|
|
12
|
+
* itself is never listed). `systemPropsChanged` reports whether the served
|
|
13
|
+
* system-props module moved (see `runAnalysisTrackingSystemProps` in
|
|
14
|
+
* context.ts) — only the owning dispatch holds the before/after values, so
|
|
15
|
+
* it travels with the decision rather than being re-derived per environment.
|
|
16
|
+
* `presentationOnly` reports that the changed file's transform output is
|
|
17
|
+
* byte-identical before and after the edit (style values are not part of
|
|
18
|
+
* the emitted replacement — class names hash `filename::binding`): every
|
|
19
|
+
* environment then excludes the file's own modules from the update it
|
|
20
|
+
* returns, so the module never re-executes and React component identity,
|
|
21
|
+
* generated IDs, focus, and DOM-owned state survive the edit. Computed once
|
|
22
|
+
* by the owning dispatch (it needs the pre-edit source and manifest, which
|
|
23
|
+
* the owner consumed while re-analyzing) — the same travel rule as
|
|
24
|
+
* `systemPropsChanged`.
|
|
13
25
|
*/
|
|
14
26
|
export type HotUpdateResult = {
|
|
15
27
|
kind: 'ignored';
|
|
@@ -18,6 +30,8 @@ export type HotUpdateResult = {
|
|
|
18
30
|
} | {
|
|
19
31
|
kind: 'analyzed';
|
|
20
32
|
staleDefinitionFiles: string[];
|
|
33
|
+
systemPropsChanged: boolean;
|
|
34
|
+
presentationOnly: boolean;
|
|
21
35
|
};
|
|
22
36
|
/**
|
|
23
37
|
* Once-per-file-event coordination across the `hotUpdate` dispatches.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hot-update-events.d.ts","sourceRoot":"","sources":["../src/hot-update-events.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"hot-update-events.d.ts","sourceRoot":"","sources":["../src/hot-update-events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEN;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,eAAe;IAGd,OAAO,CAAC,QAAQ,CAAC,YAAY;IAFzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsC;IAE9D,YAA6B,YAAY,SAAK,EAAI;IAElD,0EAA0E;IAC1E,KAAK,CAAC,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAUvE;IAED,wEAAwE;IACxE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAErE;IAED,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,eAAe,CAEzD;CACF"}
|
package/dist/index-html.d.ts
CHANGED
|
@@ -3,16 +3,18 @@ import type { HtmlTagDescriptor } from 'vite';
|
|
|
3
3
|
/**
|
|
4
4
|
* transformIndexHtml: build the head-prepend tag set.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* Three independent tags, all delivery-only:
|
|
7
7
|
* - the appearance bootstrap script, when the host build passed a
|
|
8
8
|
* pre-generated artifact via `appearanceBootstrap` (absent otherwise);
|
|
9
|
-
* - the `@layer` declaration style, when `buildStart` computed one
|
|
9
|
+
* - the `@layer` declaration style, when `buildStart` computed one;
|
|
10
|
+
* - the HMR bridge module script, in dev only.
|
|
10
11
|
*
|
|
11
|
-
*
|
|
12
|
-
* artifact whose `code` is empty is a caller defect, and emitting
|
|
12
|
+
* The two build-time branches are guarded on non-empty CONTENT, not on mere
|
|
13
|
+
* presence: an artifact whose `code` is empty is a caller defect, and emitting
|
|
13
14
|
* `<script data-animus-bootstrap></script>` for it would break the
|
|
14
15
|
* unconfigured-parity contract in spirit (a tag that does nothing) while
|
|
15
|
-
* hiding the defect. Symmetric with `layerDeclaration`.
|
|
16
|
+
* hiding the defect. Symmetric with `layerDeclaration`. The bridge has no
|
|
17
|
+
* content of its own — it is a `src` reference — so its only guard is the mode.
|
|
16
18
|
*
|
|
17
19
|
* Ordering: every descriptor rides the same `head-prepend` bucket, which Vite
|
|
18
20
|
* serializes in array order (`serializeTags`) and splices in immediately after
|
|
@@ -20,8 +22,8 @@ import type { HtmlTagDescriptor } from 'vite';
|
|
|
20
22
|
* before the layer declaration and — since built stylesheet links are appended
|
|
21
23
|
* at `</head>` — before any stylesheet reference.
|
|
22
24
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
+
* With neither build-time input set, a production build emits no tag,
|
|
26
|
+
* attribute, or whitespace of its own.
|
|
25
27
|
*/
|
|
26
28
|
export declare function buildIndexHtmlTags(ctx: PluginContext): HtmlTagDescriptor[];
|
|
27
29
|
//# sourceMappingURL=index-html.d.ts.map
|
package/dist/index-html.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-html.d.ts","sourceRoot":"","sources":["../src/index-html.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index-html.d.ts","sourceRoot":"","sources":["../src/index-html.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,GAAG,iBAAiB,EAAE,CAyD1E"}
|
package/dist/index.cjs
CHANGED
|
@@ -7,13 +7,36 @@ let fs = require("fs");
|
|
|
7
7
|
let path = require("path");
|
|
8
8
|
let crypto = require("crypto");
|
|
9
9
|
//#region src/constants.ts
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
10
|
+
/**
|
|
11
|
+
* The namespace every virtual module this plugin owns lives under. Exported so
|
|
12
|
+
* the `transform` guard that keeps those modules out of source-file handling
|
|
13
|
+
* matches on the same string the ids are built from — a rename of the
|
|
14
|
+
* namespace cannot leave the guard behind.
|
|
15
|
+
*/
|
|
16
|
+
const VIRTUAL_PREFIX = "virtual:animus/";
|
|
17
|
+
const VIRTUAL_CSS_ID = `${VIRTUAL_PREFIX}styles.css`;
|
|
18
|
+
const RESOLVED_CSS_ID = `\0${VIRTUAL_CSS_ID}`;
|
|
19
|
+
const VIRTUAL_COMPONENTS_ID = `${VIRTUAL_PREFIX}components.js`;
|
|
20
|
+
const RESOLVED_COMPONENTS_ID = `\0${VIRTUAL_COMPONENTS_ID}`;
|
|
21
|
+
const VIRTUAL_BRIDGE_ID = `${VIRTUAL_PREFIX}hmr-bridge.js`;
|
|
22
|
+
const RESOLVED_BRIDGE_ID = `\0${VIRTUAL_BRIDGE_ID}`;
|
|
23
|
+
/**
|
|
24
|
+
* Browser-addressable URL for the bridge, used as the `src` of the dev
|
|
25
|
+
* `<script type="module">` (see index-html.ts). THE explanation of the `/@id/`
|
|
26
|
+
* convention lives here; everything else points at it.
|
|
27
|
+
*
|
|
28
|
+
* Vite reserves `/@id/` for module ids that are not file paths. Its transform
|
|
29
|
+
* middleware normalizes such a URL before serving it (`unwrapId`): strip the
|
|
30
|
+
* prefix, then decode the `__x00__` placeholder back to a NUL byte. The
|
|
31
|
+
* UNPREFIXED specifier is what travels here — `resolveVirtualId` is the hook
|
|
32
|
+
* that answers it, and it answers with the `\0` form. (Vite's own `wrapId`
|
|
33
|
+
* encodes an already-`\0`-prefixed id as `__x00__`; that form resolves too, but
|
|
34
|
+
* it leans on the placeholder convention rather than on this plugin's own
|
|
35
|
+
* `resolveId` contract.)
|
|
36
|
+
*/
|
|
37
|
+
const BRIDGE_SCRIPT_SRC = `/@id/${VIRTUAL_BRIDGE_ID}`;
|
|
38
|
+
const VIRTUAL_SYSTEM_PROPS_ID = `${VIRTUAL_PREFIX}system-props`;
|
|
39
|
+
const RESOLVED_SYSTEM_PROPS_ID = `\0${VIRTUAL_SYSTEM_PROPS_ID}`;
|
|
17
40
|
const DEFAULT_EXCLUDE = [
|
|
18
41
|
"node_modules",
|
|
19
42
|
"dist",
|
|
@@ -129,6 +152,7 @@ async function runBuildStart(ctx, resolveSpecifier, emitAsset) {
|
|
|
129
152
|
}
|
|
130
153
|
ctx.externalPackageDirs = collected.packageDirs;
|
|
131
154
|
ctx.registerSystemWatchPaths();
|
|
155
|
+
ctx.applyExternalKeyframes();
|
|
132
156
|
const packageFileCount = fileEntries.length - localFileCount;
|
|
133
157
|
ctx.log(`Discovered ${fileEntries.length} files (${packageFileCount} from packages) (${Math.round(performance.now() - t0)}ms)`);
|
|
134
158
|
t0 = performance.now();
|
|
@@ -349,6 +373,56 @@ function buildFileEntriesFromCache(cache, changedPath) {
|
|
|
349
373
|
});
|
|
350
374
|
return entries;
|
|
351
375
|
}
|
|
376
|
+
/** Generate the module from the four inputs the context currently holds. */
|
|
377
|
+
function generateSystemPropsModule(ctx) {
|
|
378
|
+
return (0, _animus_ui_extract_pipeline.buildSystemPropsModule)({
|
|
379
|
+
systemPropMapJson: ctx.storedSystemPropMapJson,
|
|
380
|
+
groupRegistryJson: ctx.system.groupRegistryJson,
|
|
381
|
+
dynamicProps: JSON.parse(ctx.storedDynamicPropsJson),
|
|
382
|
+
transformsSource: ctx.storedTransformsSource
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* The exact source `virtual:animus/system-props` serves for the current state.
|
|
387
|
+
* One definition, so the served bytes and the change decision below can never
|
|
388
|
+
* be computed from different inputs.
|
|
389
|
+
*
|
|
390
|
+
* A real context carries the module already generated (`systemPropsModuleMemo`,
|
|
391
|
+
* refreshed wherever the four inputs move), so serving it and deciding whether
|
|
392
|
+
* it changed are both reads. Contexts that publish those inputs by hand — the
|
|
393
|
+
* behavioral test doubles — carry no memo and generate here instead.
|
|
394
|
+
*/
|
|
395
|
+
function systemPropsModuleSource(ctx) {
|
|
396
|
+
return ctx.systemPropsModuleMemo ??= generateSystemPropsModule(ctx);
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Run project analysis and report whether the served system-props module
|
|
400
|
+
* CHANGED.
|
|
401
|
+
*
|
|
402
|
+
* The module is imported by every module that renders a system prop, so
|
|
403
|
+
* re-delivering it pushes an update through all of them; every analysis
|
|
404
|
+
* republishes its inputs whether or not they moved, so a new analysis is not
|
|
405
|
+
* itself an admissible trigger (openspec: vite-extraction-plugin, "System prop
|
|
406
|
+
* map HMR invalidation").
|
|
407
|
+
*
|
|
408
|
+
* The comparison is over the GENERATED MODULE, not over the prop map alone.
|
|
409
|
+
* The map is one of four inputs, and they move independently: widening a
|
|
410
|
+
* component's `.system({ ... })` opt-in adds a `dynamicPropConfig` entry while
|
|
411
|
+
* minting no new utility class, so a map-only comparison reports "unchanged"
|
|
412
|
+
* and the client is left with a config missing the new prop — permanently,
|
|
413
|
+
* since Vite keeps serving the module's cached transform result across full
|
|
414
|
+
* page reloads. Comparing the artifact itself needs no argument about which
|
|
415
|
+
* inputs are volatile this month.
|
|
416
|
+
*
|
|
417
|
+
* A free function rather than a method: the comparison must run for real
|
|
418
|
+
* against any context the caller holds, including the behavioral test doubles
|
|
419
|
+
* that stand in for the engine.
|
|
420
|
+
*/
|
|
421
|
+
function runAnalysisTrackingSystemProps(ctx, fileEntries) {
|
|
422
|
+
const before = systemPropsModuleSource(ctx);
|
|
423
|
+
ctx.runAnalysis(fileEntries);
|
|
424
|
+
return systemPropsModuleSource(ctx) !== before;
|
|
425
|
+
}
|
|
352
426
|
/**
|
|
353
427
|
* Drop a deleted (or renamed-away) file from the dev file cache so its
|
|
354
428
|
* last-known source stops riding along as a ghost entry on every later
|
|
@@ -368,7 +442,7 @@ function pruneFileCache(cache, rootDir, absPath) {
|
|
|
368
442
|
* index.ts only wires Vite hooks to those functions.
|
|
369
443
|
*
|
|
370
444
|
* A class rather than closure variables so each hook module names exactly
|
|
371
|
-
* the state it touches, and the engine store (
|
|
445
|
+
* the state it touches, and the engine store (per-instance, never
|
|
372
446
|
* module-level) is explicit.
|
|
373
447
|
*/
|
|
374
448
|
var PluginContext = class {
|
|
@@ -390,11 +464,31 @@ var PluginContext = class {
|
|
|
390
464
|
resolvedComponentCss = "";
|
|
391
465
|
storedSheets = null;
|
|
392
466
|
layerDeclaration = "";
|
|
393
|
-
|
|
467
|
+
transformOutputHashes = /* @__PURE__ */ new Map();
|
|
468
|
+
recordTransformOutput(relativePath, code) {
|
|
469
|
+
this.transformOutputHashes.set(relativePath, (0, _animus_ui_extract_pipeline.contentHash)(code));
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Merge `Keyframes` collections from discovered external package entries
|
|
473
|
+
* into the system's collections (keyframes-only carve-out — the consumer
|
|
474
|
+
* system stays the singular config authority). Runs after buildStart
|
|
475
|
+
* discovery AND after every geological-reset system reload, since a reload
|
|
476
|
+
* rebuilds `this.system` from the consumer entry alone.
|
|
477
|
+
*/
|
|
478
|
+
applyExternalKeyframes() {
|
|
479
|
+
if (this.externalSourceEntries.size === 0) return;
|
|
480
|
+
const merge = (0, _animus_ui_extract_pipeline.mergeExternalKeyframes)((entry, root) => this.engineApi().scanKeyframesExports(entry, root), this.system.keyframesJson, this.externalSourceEntries.values(), this.rootDir);
|
|
481
|
+
this.system.keyframesJson = merge.keyframesJson;
|
|
482
|
+
this.externalKeyframesDiagnostics = merge.diagnostics;
|
|
483
|
+
}
|
|
484
|
+
/** Discovery-time keyframes diagnostics awaiting the next analysis's
|
|
485
|
+
* shared surfacing pass. */
|
|
486
|
+
externalKeyframesDiagnostics = [];
|
|
394
487
|
reverseProvenance = {};
|
|
395
488
|
storedSystemPropMapJson = "{}";
|
|
396
489
|
storedDynamicPropsJson = "{}";
|
|
397
490
|
storedTransformsSource = "{}";
|
|
491
|
+
systemPropsModuleMemo = null;
|
|
398
492
|
fileCache = /* @__PURE__ */ new Map();
|
|
399
493
|
hotUpdateEvents = new HotUpdateEvents();
|
|
400
494
|
packageMap = {};
|
|
@@ -408,7 +502,6 @@ var PluginContext = class {
|
|
|
408
502
|
externalSourceEntries = /* @__PURE__ */ new Map();
|
|
409
503
|
externalPackageOutcomes = [];
|
|
410
504
|
devServer;
|
|
411
|
-
bridgeInjected = false;
|
|
412
505
|
resolvedSystemPath = null;
|
|
413
506
|
systemDependencyKeys = /* @__PURE__ */ new Set();
|
|
414
507
|
systemDependencyPaths = [];
|
|
@@ -456,6 +549,15 @@ var PluginContext = class {
|
|
|
456
549
|
log(msg) {
|
|
457
550
|
if (this.verbose) (this.logger ?? console).info(`[animus] ${msg}`);
|
|
458
551
|
}
|
|
552
|
+
/**
|
|
553
|
+
* Standard-level information — emitted whether or not `verbose` is on.
|
|
554
|
+
* Reserved for events a developer must see without opting in, e.g. a file
|
|
555
|
+
* created after buildStart being folded into the analysis (openspec:
|
|
556
|
+
* hmr-new-file-detection, "New file detection logging").
|
|
557
|
+
*/
|
|
558
|
+
info(msg) {
|
|
559
|
+
(this.logger ?? console).info(`[animus] ${msg}`);
|
|
560
|
+
}
|
|
459
561
|
warn(msg) {
|
|
460
562
|
(this.logger ?? console).warn(`[animus] ${msg}`);
|
|
461
563
|
}
|
|
@@ -487,10 +589,12 @@ var PluginContext = class {
|
|
|
487
589
|
this.systemDependencyKeys = keys;
|
|
488
590
|
this.systemDependencyPaths = deps;
|
|
489
591
|
this.registerSystemWatchPaths();
|
|
592
|
+
this.applyExternalKeyframes();
|
|
490
593
|
} catch (e) {
|
|
491
594
|
if (this.options.strict) throw new Error(`[animus-extract] Failed to load system from ${this.resolvedSystemPath}: ${e}`, { cause: e });
|
|
492
595
|
console.warn(`[animus-extract] Failed to load system from ${this.resolvedSystemPath}:`, e);
|
|
493
596
|
}
|
|
597
|
+
this.systemPropsModuleMemo = generateSystemPropsModule(this);
|
|
494
598
|
}
|
|
495
599
|
/**
|
|
496
600
|
* Run project analysis via the shared `runProjectAnalysis` and update
|
|
@@ -510,18 +614,14 @@ var PluginContext = class {
|
|
|
510
614
|
staticCssJson: this.staticCssJson,
|
|
511
615
|
externalDirs: this.externalPackageDirs.map((dir) => (0, path.relative)(this.rootDir, dir)),
|
|
512
616
|
devMode: !this.isProd,
|
|
513
|
-
warn: (m) => this.warn(m)
|
|
617
|
+
warn: (m) => this.warn(m),
|
|
618
|
+
strict: this.options.strict,
|
|
619
|
+
extraDiagnostics: this.externalKeyframesDiagnostics
|
|
514
620
|
});
|
|
515
621
|
this.storedManifest = result.manifest;
|
|
516
622
|
this.storedManifestJson = result.manifestJson;
|
|
517
623
|
this.storedSystemPropMapJson = JSON.stringify(result.manifest?.system_prop_map ?? {});
|
|
518
624
|
this.storedDynamicPropsJson = JSON.stringify(result.manifest?.dynamic_props ?? {});
|
|
519
|
-
this.bridgeInjected = false;
|
|
520
|
-
const newFragments = result.manifest?.component_fragments;
|
|
521
|
-
if (newFragments && typeof newFragments === "object") {
|
|
522
|
-
this.fragmentCache.clear();
|
|
523
|
-
for (const [id, sheets] of Object.entries(newFragments)) this.fragmentCache.set(id, sheets);
|
|
524
|
-
}
|
|
525
625
|
this.reverseProvenance = result.manifest?.reverse_provenance ?? {};
|
|
526
626
|
this.storedSheets = result.manifest?.sheets ?? null;
|
|
527
627
|
this.globalCss = result.globalCss;
|
|
@@ -531,6 +631,7 @@ var PluginContext = class {
|
|
|
531
631
|
console.warn("[animus-extract] analyzeProject failed:", e);
|
|
532
632
|
return;
|
|
533
633
|
}
|
|
634
|
+
this.systemPropsModuleMemo = generateSystemPropsModule(this);
|
|
534
635
|
this.applyAssetSubstitutions();
|
|
535
636
|
this.enforceExternalTokenContracts();
|
|
536
637
|
}
|
|
@@ -665,6 +766,13 @@ var PluginContext = class {
|
|
|
665
766
|
* `getModuleById` searches the client AND ssr environment graphs and its
|
|
666
767
|
* `invalidateModule` invalidates both instances behind the returned node,
|
|
667
768
|
* which is exactly the reach this path wants. It stays the seam here.
|
|
769
|
+
*
|
|
770
|
+
* Both modules are invalidated unconditionally, and deliberately so: the
|
|
771
|
+
* appearance or disappearance of a whole component file is not the
|
|
772
|
+
* steady-state edit the change-gated path governs, and a client reload does
|
|
773
|
+
* NOT rescue a module that was never invalidated — Vite keeps serving its
|
|
774
|
+
* cached transform result across reloads (openspec: hmr-new-file-detection,
|
|
775
|
+
* "CSS invalidation after new file analysis").
|
|
668
776
|
*/
|
|
669
777
|
invalidateExtractedModules() {
|
|
670
778
|
const server = this.devServer;
|
|
@@ -741,6 +849,82 @@ var PluginContext = class {
|
|
|
741
849
|
}
|
|
742
850
|
};
|
|
743
851
|
//#endregion
|
|
852
|
+
//#region src/transform.ts
|
|
853
|
+
/**
|
|
854
|
+
* The dev-mode bridge prepend, shared with the hot-update gate so both
|
|
855
|
+
* compute byte-identical served output. The import goes AFTER the directive
|
|
856
|
+
* prologue the engine hoists to byte 0 — prepending above it would demote
|
|
857
|
+
* 'use client'/'use strict' to an ordinary expression statement, silently
|
|
858
|
+
* un-marking client modules on exactly the RSC-capable hosts this delivery
|
|
859
|
+
* path serves.
|
|
860
|
+
*/
|
|
861
|
+
function applyDevBridgeImport(code) {
|
|
862
|
+
const prologue = /^(?:(['"])use [a-z -]+\1;?\r?\n)*/.exec(code)?.[0] ?? "";
|
|
863
|
+
return prologue + `import '${VIRTUAL_BRIDGE_ID}';\n` + code.slice(prologue.length);
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* transform: replace builder chains with `createComponent()` calls using
|
|
867
|
+
* the pre-built manifest; detect files created after buildStart and fold
|
|
868
|
+
* them into the analysis.
|
|
869
|
+
*
|
|
870
|
+
* The HMR bridge is NOT injected here — `transformIndexHtml` delivers it as a
|
|
871
|
+
* `<script type="module">` per served document (openspec:
|
|
872
|
+
* dev-stylesheet-management, "HMR bridge auto-injected in dev mode"; "Transform
|
|
873
|
+
* emitter unchanged" forbids the emitter importing it).
|
|
874
|
+
*/
|
|
875
|
+
function transformSource(ctx, code, id) {
|
|
876
|
+
if (!ctx.storedManifest) return null;
|
|
877
|
+
if (id.startsWith("\0") || id.startsWith("virtual:animus/")) return null;
|
|
878
|
+
const isExternalPkg = ctx.externalPackageDirs.some((dir) => id.startsWith(dir + path.sep) || id === dir);
|
|
879
|
+
const relativePath = (0, path.relative)(ctx.rootDir, id);
|
|
880
|
+
if (!isExternalPkg) {
|
|
881
|
+
if (!/\.[jt]sx?$/.test(id)) return null;
|
|
882
|
+
if (id.includes("node_modules")) return null;
|
|
883
|
+
if (relativePath.startsWith("..") || (0, path.isAbsolute)(relativePath)) return null;
|
|
884
|
+
}
|
|
885
|
+
if (!ctx.storedManifest.files?.[relativePath]?.length) {
|
|
886
|
+
if (!ctx.isProd && !ctx.fileCache.has(relativePath)) {
|
|
887
|
+
if (isExternalPkg) {
|
|
888
|
+
const owner = Object.entries(ctx.externalDirOwners).find(([dir]) => id === dir || id.startsWith(dir + path.sep));
|
|
889
|
+
if (owner) ctx.externalFileOwners[relativePath] = owner[1];
|
|
890
|
+
}
|
|
891
|
+
const hash = (0, _animus_ui_extract_pipeline.contentHash)(code);
|
|
892
|
+
ctx.fileCache.set(relativePath, {
|
|
893
|
+
hash,
|
|
894
|
+
source: code
|
|
895
|
+
});
|
|
896
|
+
const fileEntries = buildFileEntriesFromCache(ctx.fileCache, relativePath);
|
|
897
|
+
ctx.runAnalysis(fileEntries);
|
|
898
|
+
const compCount = ctx.storedManifest.files?.[relativePath]?.length ?? 0;
|
|
899
|
+
ctx.info(`New file detected: ${relativePath} — ${compCount ? `${compCount} components extracted` : "no components"}`);
|
|
900
|
+
ctx.invalidateExtractedModules();
|
|
901
|
+
}
|
|
902
|
+
if (!ctx.storedManifest.files?.[relativePath]?.length) return null;
|
|
903
|
+
}
|
|
904
|
+
try {
|
|
905
|
+
const { transformFile } = ctx.engineApi();
|
|
906
|
+
const result = transformFile(code, relativePath, ctx.storedManifestJson);
|
|
907
|
+
if (!result.hasComponents) return null;
|
|
908
|
+
if (ctx.verbose) {
|
|
909
|
+
const compCount = ctx.storedManifest.files?.[relativePath]?.length ?? 0;
|
|
910
|
+
ctx.log(`transform ${relativePath}: ${compCount} components`);
|
|
911
|
+
}
|
|
912
|
+
let outputCode = result.code;
|
|
913
|
+
if (!ctx.isProd) {
|
|
914
|
+
outputCode = applyDevBridgeImport(result.code);
|
|
915
|
+
ctx.recordTransformOutput(relativePath, outputCode);
|
|
916
|
+
}
|
|
917
|
+
return {
|
|
918
|
+
code: outputCode,
|
|
919
|
+
map: null
|
|
920
|
+
};
|
|
921
|
+
} catch (e) {
|
|
922
|
+
if (ctx.options.strict) throw new Error(`[animus-extract] Failed to transform ${id}: ${e}`, { cause: e });
|
|
923
|
+
console.warn(`[animus-extract] Failed to transform ${id}:`, e);
|
|
924
|
+
return null;
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
//#endregion
|
|
744
928
|
//#region src/hmr.ts
|
|
745
929
|
/**
|
|
746
930
|
* hotUpdate: the single dev file-event hook. Handles system-dependency
|
|
@@ -761,13 +945,16 @@ var PluginContext = class {
|
|
|
761
945
|
* graph, so system dependencies registered through `watcher.add` outside the
|
|
762
946
|
* root still reach the reset branch, with an empty `modules` list.
|
|
763
947
|
*/
|
|
764
|
-
async function handleHotUpdate(ctx, environment, { type, file, timestamp, modules }) {
|
|
948
|
+
async function handleHotUpdate(ctx, environment, { type, file, timestamp, modules, read }) {
|
|
765
949
|
if (ctx.isProd) return;
|
|
766
950
|
const ownsEvent = ctx.hotUpdateEvents.claim(environment.name, file, timestamp);
|
|
767
951
|
const absFile = (0, path.resolve)(file);
|
|
768
952
|
ctx.log(`hotUpdate ${type} ${(0, path.relative)(ctx.rootDir, absFile)} env=${environment.name} owns=${ownsEvent}`);
|
|
769
953
|
if (ctx.isSystemDependency(absFile)) {
|
|
770
|
-
if (ownsEvent)
|
|
954
|
+
if (ownsEvent) {
|
|
955
|
+
await reconcileSourceEntry(ctx, absFile, type, read);
|
|
956
|
+
ctx.requestGeologicalReset((0, path.relative)(ctx.rootDir, absFile));
|
|
957
|
+
}
|
|
771
958
|
return [];
|
|
772
959
|
}
|
|
773
960
|
if (type === "create") return;
|
|
@@ -775,18 +962,69 @@ async function handleHotUpdate(ctx, environment, { type, file, timestamp, module
|
|
|
775
962
|
if (ownsEvent) pruneDeletedFile(ctx, absFile);
|
|
776
963
|
return;
|
|
777
964
|
}
|
|
778
|
-
if (ownsEvent) ctx.hotUpdateEvents.record(file, timestamp, await analyzeChangedFile(ctx, file, absFile));
|
|
965
|
+
if (ownsEvent) ctx.hotUpdateEvents.record(file, timestamp, await analyzeChangedFile(ctx, file, absFile, read));
|
|
779
966
|
const result = ctx.hotUpdateEvents.resultOf(file, timestamp);
|
|
780
967
|
if (result.kind === "ignored") return;
|
|
781
968
|
if (result.kind === "unchanged") return [];
|
|
782
|
-
return invalidateStaleModules(ctx, environment, modules, result
|
|
969
|
+
return invalidateStaleModules(ctx, environment, modules, result);
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* The changed file's text.
|
|
973
|
+
*
|
|
974
|
+
* Editors save atomically — truncate, then rewrite — so a watcher event can
|
|
975
|
+
* arrive while the path is momentarily EMPTY. Vite's `read()` helper retries on
|
|
976
|
+
* empty content for exactly that reason; reading the path directly at the same
|
|
977
|
+
* moment yields `''`, and since the corrective content produces no second
|
|
978
|
+
* event, that empty source would be cached permanently.
|
|
979
|
+
*
|
|
980
|
+
* Vite always supplies `read`, so the direct read is NOT a fallback for Vite:
|
|
981
|
+
* it exists for hosts that drive this hook without one. The dev-lane's adapter
|
|
982
|
+
* contract is deliberately bundler-neutral, and a second runtime satisfying it
|
|
983
|
+
* must not be forced to fabricate a helper to get correct behavior.
|
|
984
|
+
*/
|
|
985
|
+
async function readChangedSource(absFile, read) {
|
|
986
|
+
return read ? await read() : (0, fs.readFileSync)(absFile, "utf-8");
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* Reconcile the `fileCache` entry of a file that is BOTH a system dependency
|
|
990
|
+
* and a discovered component source, since the dependency branch is terminal —
|
|
991
|
+
* neither the edit path's cache write nor `pruneDeletedFile` runs for it.
|
|
992
|
+
*
|
|
993
|
+
* An edit refreshes the entry: `performGeologicalReset` rebuilds its
|
|
994
|
+
* full-source analysis from this cache, so a stale entry would be re-analyzed
|
|
995
|
+
* on every later reset. A delete prunes it, exactly as the ordinary delete path
|
|
996
|
+
* would (openspec: hmr-new-file-detection, "Watcher deletion pruning") — a
|
|
997
|
+
* surviving entry is a ghost source no watcher event can ever name again.
|
|
998
|
+
*
|
|
999
|
+
* Dependency-only files have no entry: `pruneFileCache` no-ops for them, and
|
|
1000
|
+
* the edit path must not create one — the cache is the component-source set,
|
|
1001
|
+
* and a phantom entry would feed the engine a file it never discovered.
|
|
1002
|
+
*/
|
|
1003
|
+
async function reconcileSourceEntry(ctx, absFile, type, read) {
|
|
1004
|
+
if (type === "delete") {
|
|
1005
|
+
pruneFileCache(ctx.fileCache, ctx.rootDir, absFile);
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
const relPath = (0, path.relative)(ctx.rootDir, absFile);
|
|
1009
|
+
if (!ctx.fileCache.has(relPath)) return;
|
|
1010
|
+
let source;
|
|
1011
|
+
try {
|
|
1012
|
+
source = await readChangedSource(absFile, read);
|
|
1013
|
+
} catch {
|
|
1014
|
+
ctx.warn(`could not re-read ${relPath} after a system-dependency edit — geological resets will analyze its pre-edit text until a later edit is read successfully`);
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
ctx.fileCache.set(relPath, {
|
|
1018
|
+
hash: (0, _animus_ui_extract_pipeline.contentHash)(source),
|
|
1019
|
+
source
|
|
1020
|
+
});
|
|
783
1021
|
}
|
|
784
1022
|
/**
|
|
785
1023
|
* The once-per-event analysis half: gate the file, diff its content hash,
|
|
786
1024
|
* refresh the cache, and re-run project analysis. The returned result is what
|
|
787
1025
|
* the remaining environments act on.
|
|
788
1026
|
*/
|
|
789
|
-
async function analyzeChangedFile(ctx, file, absFile) {
|
|
1027
|
+
async function analyzeChangedFile(ctx, file, absFile, read) {
|
|
790
1028
|
const ext = (0, path.extname)(file);
|
|
791
1029
|
if (!ctx.extensionsSet.has(ext)) return { kind: "ignored" };
|
|
792
1030
|
const excludePatterns = ctx.options.exclude ?? DEFAULT_EXCLUDE;
|
|
@@ -794,7 +1032,7 @@ async function analyzeChangedFile(ctx, file, absFile) {
|
|
|
794
1032
|
const relPath = (0, path.relative)(ctx.rootDir, absFile);
|
|
795
1033
|
let source;
|
|
796
1034
|
try {
|
|
797
|
-
source =
|
|
1035
|
+
source = await readChangedSource(absFile, read);
|
|
798
1036
|
} catch {
|
|
799
1037
|
return { kind: "ignored" };
|
|
800
1038
|
}
|
|
@@ -840,8 +1078,7 @@ async function analyzeChangedFile(ctx, file, absFile) {
|
|
|
840
1078
|
}
|
|
841
1079
|
if (ctx.verbose && invalidatedIds.size > directComponentIds.length) ctx.log(`HMR: ${directComponentIds.length} direct + ${invalidatedIds.size - directComponentIds.length} transitive components invalidated`);
|
|
842
1080
|
const analysisStart = performance.now();
|
|
843
|
-
const
|
|
844
|
-
ctx.runAnalysis(fileEntries);
|
|
1081
|
+
const systemPropsChanged = runAnalysisTrackingSystemProps(ctx, buildFileEntriesFromCache(ctx.fileCache, relPath));
|
|
845
1082
|
const analysisMs = Math.round(performance.now() - analysisStart);
|
|
846
1083
|
const staleDefinitionFiles = [];
|
|
847
1084
|
if (ctx.storedManifest?.components) {
|
|
@@ -852,15 +1089,44 @@ async function analyzeChangedFile(ctx, file, absFile) {
|
|
|
852
1089
|
staleDefinitionFiles.push(defFile);
|
|
853
1090
|
}
|
|
854
1091
|
}
|
|
1092
|
+
const presentationOnly = isPresentationOnlyEdit(ctx, scannerRelPath, source);
|
|
855
1093
|
const hmrMs = Math.round(performance.now() - hmrStart);
|
|
856
|
-
ctx.log(`HMR update: ${relPath} — analysis ${analysisMs}ms, total ${hmrMs}ms`);
|
|
1094
|
+
ctx.log(`HMR update: ${relPath} — analysis ${analysisMs}ms, total ${hmrMs}ms${presentationOnly ? " (presentation-only)" : ""}`);
|
|
857
1095
|
ctx.logTimingWaterfall(ctx.storedManifest?.timing ?? {});
|
|
858
1096
|
return {
|
|
859
1097
|
kind: "analyzed",
|
|
860
|
-
staleDefinitionFiles
|
|
1098
|
+
staleDefinitionFiles,
|
|
1099
|
+
systemPropsChanged,
|
|
1100
|
+
presentationOnly
|
|
861
1101
|
};
|
|
862
1102
|
}
|
|
863
1103
|
/**
|
|
1104
|
+
* True when the changed file's transform output is byte-identical across the
|
|
1105
|
+
* edit — a presentation-only change (style values are not part of the emitted
|
|
1106
|
+
* replacement, whose class names hash `filename::binding`).
|
|
1107
|
+
*
|
|
1108
|
+
* Compares a POST-analysis re-transform of the file (the engine transforms
|
|
1109
|
+
* from its retained facts, so this runs against the just-updated analysis)
|
|
1110
|
+
* with the hash of what the module LAST SERVED (`recordTransformOutput` in
|
|
1111
|
+
* the transform hook, bridge import included). Comparing the full served
|
|
1112
|
+
* output — never replacement strings — is what keeps a mixed style+code edit
|
|
1113
|
+
* deliverable. Fails open: a transform error, a file the manifest does not
|
|
1114
|
+
* list, or a module that never served (no recorded hash) delivers normally.
|
|
1115
|
+
*/
|
|
1116
|
+
function isPresentationOnlyEdit(ctx, scannerRelPath, source) {
|
|
1117
|
+
const servedHash = ctx.transformOutputHashes.get(scannerRelPath);
|
|
1118
|
+
if (!servedHash || !ctx.storedManifestJson) return false;
|
|
1119
|
+
if (!ctx.storedManifest?.files?.[scannerRelPath]?.length) return false;
|
|
1120
|
+
try {
|
|
1121
|
+
const { transformFile } = ctx.engineApi();
|
|
1122
|
+
const fresh = transformFile(source, scannerRelPath, ctx.storedManifestJson);
|
|
1123
|
+
if (!fresh.hasComponents) return false;
|
|
1124
|
+
return (0, _animus_ui_extract_pipeline.contentHash)(applyDevBridgeImport(fresh.code)) === servedHash;
|
|
1125
|
+
} catch {
|
|
1126
|
+
return false;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
/**
|
|
864
1130
|
* Reconcile a deleted file in dev.
|
|
865
1131
|
*
|
|
866
1132
|
* Without this the removed file's last-known source stays in `ctx.fileCache`,
|
|
@@ -880,17 +1146,19 @@ function pruneDeletedFile(ctx, absFile) {
|
|
|
880
1146
|
* (virtual:animus/styles.css) is NOT invalidated here — it only changes on a
|
|
881
1147
|
* geological reset (vars/globals are stable during dev).
|
|
882
1148
|
*/
|
|
883
|
-
function invalidateStaleModules(ctx, environment, modules,
|
|
1149
|
+
function invalidateStaleModules(ctx, environment, modules, analyzed) {
|
|
884
1150
|
const graph = environment.moduleGraph;
|
|
885
|
-
const modulesToUpdate = [...modules];
|
|
886
|
-
|
|
1151
|
+
const modulesToUpdate = analyzed.presentationOnly ? [] : [...modules];
|
|
1152
|
+
const moduleIds = [RESOLVED_COMPONENTS_ID];
|
|
1153
|
+
if (analyzed.systemPropsChanged) moduleIds.push(RESOLVED_SYSTEM_PROPS_ID);
|
|
1154
|
+
for (const moduleId of moduleIds) {
|
|
887
1155
|
const mod = graph.getModuleById(moduleId);
|
|
888
1156
|
if (mod) {
|
|
889
1157
|
graph.invalidateModule(mod);
|
|
890
1158
|
modulesToUpdate.push(mod);
|
|
891
1159
|
}
|
|
892
1160
|
}
|
|
893
|
-
for (const defFile of staleDefinitionFiles) {
|
|
1161
|
+
for (const defFile of analyzed.staleDefinitionFiles) {
|
|
894
1162
|
const absDefPath = (0, path.resolve)(ctx.rootDir, defFile);
|
|
895
1163
|
const defModule = graph.getModuleById(absDefPath) ?? graph.getModulesByFile(absDefPath)?.values().next().value;
|
|
896
1164
|
if (defModule) {
|
|
@@ -899,6 +1167,11 @@ function invalidateStaleModules(ctx, environment, modules, staleDefinitionFiles)
|
|
|
899
1167
|
modulesToUpdate.push(defModule);
|
|
900
1168
|
}
|
|
901
1169
|
}
|
|
1170
|
+
if (analyzed.presentationOnly) {
|
|
1171
|
+
ctx.log(`HMR (${environment.name}): presentation-only — ${modules.length} module update(s) suppressed, CSS delivered`);
|
|
1172
|
+
for (const mod of modules) if (mod.url) environment.transformRequest?.(mod.url)?.catch(() => {});
|
|
1173
|
+
return modulesToUpdate;
|
|
1174
|
+
}
|
|
902
1175
|
const invalidated = modulesToUpdate.length - modules.length;
|
|
903
1176
|
if (invalidated > 0) {
|
|
904
1177
|
ctx.log(`HMR (${environment.name}): ${invalidated} modules invalidated`);
|
|
@@ -910,16 +1183,18 @@ function invalidateStaleModules(ctx, environment, modules, staleDefinitionFiles)
|
|
|
910
1183
|
/**
|
|
911
1184
|
* transformIndexHtml: build the head-prepend tag set.
|
|
912
1185
|
*
|
|
913
|
-
*
|
|
1186
|
+
* Three independent tags, all delivery-only:
|
|
914
1187
|
* - the appearance bootstrap script, when the host build passed a
|
|
915
1188
|
* pre-generated artifact via `appearanceBootstrap` (absent otherwise);
|
|
916
|
-
* - the `@layer` declaration style, when `buildStart` computed one
|
|
1189
|
+
* - the `@layer` declaration style, when `buildStart` computed one;
|
|
1190
|
+
* - the HMR bridge module script, in dev only.
|
|
917
1191
|
*
|
|
918
|
-
*
|
|
919
|
-
* artifact whose `code` is empty is a caller defect, and emitting
|
|
1192
|
+
* The two build-time branches are guarded on non-empty CONTENT, not on mere
|
|
1193
|
+
* presence: an artifact whose `code` is empty is a caller defect, and emitting
|
|
920
1194
|
* `<script data-animus-bootstrap><\/script>` for it would break the
|
|
921
1195
|
* unconfigured-parity contract in spirit (a tag that does nothing) while
|
|
922
|
-
* hiding the defect. Symmetric with `layerDeclaration`.
|
|
1196
|
+
* hiding the defect. Symmetric with `layerDeclaration`. The bridge has no
|
|
1197
|
+
* content of its own — it is a `src` reference — so its only guard is the mode.
|
|
923
1198
|
*
|
|
924
1199
|
* Ordering: every descriptor rides the same `head-prepend` bucket, which Vite
|
|
925
1200
|
* serializes in array order (`serializeTags`) and splices in immediately after
|
|
@@ -927,8 +1202,8 @@ function invalidateStaleModules(ctx, environment, modules, staleDefinitionFiles)
|
|
|
927
1202
|
* before the layer declaration and — since built stylesheet links are appended
|
|
928
1203
|
* at `</head>` — before any stylesheet reference.
|
|
929
1204
|
*
|
|
930
|
-
*
|
|
931
|
-
*
|
|
1205
|
+
* With neither build-time input set, a production build emits no tag,
|
|
1206
|
+
* attribute, or whitespace of its own.
|
|
932
1207
|
*/
|
|
933
1208
|
function buildIndexHtmlTags(ctx) {
|
|
934
1209
|
const tags = [];
|
|
@@ -945,74 +1220,25 @@ function buildIndexHtmlTags(ctx) {
|
|
|
945
1220
|
children: ctx.layerDeclaration,
|
|
946
1221
|
injectTo: "head-prepend"
|
|
947
1222
|
});
|
|
1223
|
+
if (!ctx.isProd) tags.push({
|
|
1224
|
+
tag: "script",
|
|
1225
|
+
attrs: {
|
|
1226
|
+
type: "module",
|
|
1227
|
+
src: BRIDGE_SCRIPT_SRC,
|
|
1228
|
+
"data-animus-bridge": ""
|
|
1229
|
+
},
|
|
1230
|
+
injectTo: "head-prepend"
|
|
1231
|
+
});
|
|
948
1232
|
return tags;
|
|
949
1233
|
}
|
|
950
1234
|
//#endregion
|
|
951
|
-
//#region src/transform.ts
|
|
952
|
-
/**
|
|
953
|
-
* transform: replace builder chains with `createComponent()` calls using
|
|
954
|
-
* the pre-built manifest; inject the HMR bridge import once in dev; detect
|
|
955
|
-
* files created after buildStart and fold them into the analysis.
|
|
956
|
-
*/
|
|
957
|
-
function transformSource(ctx, code, id) {
|
|
958
|
-
if (!ctx.storedManifest) return null;
|
|
959
|
-
const isExternalPkg = ctx.externalPackageDirs.some((dir) => id.startsWith(dir + path.sep) || id === dir);
|
|
960
|
-
if (!isExternalPkg) {
|
|
961
|
-
if (!/\.[jt]sx?$/.test(id)) return null;
|
|
962
|
-
if (id.includes("node_modules")) return null;
|
|
963
|
-
}
|
|
964
|
-
const relativePath = (0, path.relative)(ctx.rootDir, id);
|
|
965
|
-
if (!ctx.storedManifest.files?.[relativePath]?.length) {
|
|
966
|
-
if (!ctx.isProd && !ctx.fileCache.has(relativePath)) {
|
|
967
|
-
if (isExternalPkg) {
|
|
968
|
-
const owner = Object.entries(ctx.externalDirOwners).find(([dir]) => id === dir || id.startsWith(dir + path.sep));
|
|
969
|
-
if (owner) ctx.externalFileOwners[relativePath] = owner[1];
|
|
970
|
-
}
|
|
971
|
-
const hash = (0, _animus_ui_extract_pipeline.contentHash)(code);
|
|
972
|
-
ctx.fileCache.set(relativePath, {
|
|
973
|
-
hash,
|
|
974
|
-
source: code
|
|
975
|
-
});
|
|
976
|
-
const fileEntries = buildFileEntriesFromCache(ctx.fileCache, relativePath);
|
|
977
|
-
ctx.runAnalysis(fileEntries);
|
|
978
|
-
const compCount = ctx.storedManifest.files?.[relativePath]?.length ?? 0;
|
|
979
|
-
ctx.log(`New file detected: ${relativePath} — ${compCount ? `${compCount} components extracted` : "no components"}`);
|
|
980
|
-
if (compCount) ctx.invalidateExtractedModules();
|
|
981
|
-
}
|
|
982
|
-
if (!ctx.storedManifest.files?.[relativePath]?.length) return null;
|
|
983
|
-
}
|
|
984
|
-
try {
|
|
985
|
-
const { transformFile } = ctx.engineApi();
|
|
986
|
-
const result = transformFile(code, relativePath, ctx.storedManifestJson);
|
|
987
|
-
if (!result.hasComponents) return null;
|
|
988
|
-
let transformedCode = result.code;
|
|
989
|
-
if (!ctx.isProd && !ctx.bridgeInjected && ctx.storedSheets) {
|
|
990
|
-
transformedCode = `import '${VIRTUAL_BRIDGE_ID}';\n${transformedCode}`;
|
|
991
|
-
ctx.bridgeInjected = true;
|
|
992
|
-
ctx.log("HMR bridge injected via transform");
|
|
993
|
-
}
|
|
994
|
-
if (ctx.verbose) {
|
|
995
|
-
const compCount = ctx.storedManifest.files?.[relativePath]?.length ?? 0;
|
|
996
|
-
ctx.log(`transform ${relativePath}: ${compCount} components`);
|
|
997
|
-
}
|
|
998
|
-
return {
|
|
999
|
-
code: transformedCode,
|
|
1000
|
-
map: null
|
|
1001
|
-
};
|
|
1002
|
-
} catch (e) {
|
|
1003
|
-
if (ctx.options.strict) throw new Error(`[animus-extract] Failed to transform ${id}: ${e}`, { cause: e });
|
|
1004
|
-
console.warn(`[animus-extract] Failed to transform ${id}:`, e);
|
|
1005
|
-
return null;
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
//#endregion
|
|
1009
1235
|
//#region src/virtual-modules.ts
|
|
1010
1236
|
/** resolveId: map virtual ids and redirect external DS package imports. */
|
|
1011
1237
|
function resolveVirtualId(ctx, id) {
|
|
1012
|
-
if (id ===
|
|
1013
|
-
if (id ===
|
|
1014
|
-
if (id ===
|
|
1015
|
-
if (id ===
|
|
1238
|
+
if (id === VIRTUAL_CSS_ID) return RESOLVED_CSS_ID;
|
|
1239
|
+
if (id === VIRTUAL_COMPONENTS_ID) return RESOLVED_COMPONENTS_ID;
|
|
1240
|
+
if (id === VIRTUAL_BRIDGE_ID) return RESOLVED_BRIDGE_ID;
|
|
1241
|
+
if (id === VIRTUAL_SYSTEM_PROPS_ID) return RESOLVED_SYSTEM_PROPS_ID;
|
|
1016
1242
|
const srcEntry = ctx.externalSourceEntries.get(id);
|
|
1017
1243
|
if (srcEntry) return srcEntry;
|
|
1018
1244
|
return null;
|
|
@@ -1025,7 +1251,7 @@ function loadVirtualModule(ctx, id) {
|
|
|
1025
1251
|
targets: ctx.lcssTargets,
|
|
1026
1252
|
warnFn: (msg) => ctx.warn(msg)
|
|
1027
1253
|
};
|
|
1028
|
-
if (id ===
|
|
1254
|
+
if (id === RESOLVED_CSS_ID) {
|
|
1029
1255
|
if (!ctx.isProd && ctx.storedSheets) {
|
|
1030
1256
|
const { variables, body } = (0, _animus_ui_extract_pipeline.assembleStylesheet)({
|
|
1031
1257
|
layers: ctx.options.layers,
|
|
@@ -1047,36 +1273,44 @@ function loadVirtualModule(ctx, id) {
|
|
|
1047
1273
|
});
|
|
1048
1274
|
return [variables, (0, _animus_ui_extract_pipeline.postProcessCss)(body, lcssOpts)].filter(Boolean).join("\n");
|
|
1049
1275
|
}
|
|
1050
|
-
if (id ===
|
|
1276
|
+
if (id === RESOLVED_COMPONENTS_ID) return `export default \`${(0, _animus_ui_extract_pipeline.postProcessCss)((0, _animus_ui_extract_pipeline.stripLeadingLayerDeclaration)(ctx.resolvedComponentCss || ""), {
|
|
1051
1277
|
...lcssOpts,
|
|
1052
1278
|
minify: false
|
|
1053
1279
|
}).replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$/g, "\\$")}\`;`;
|
|
1054
|
-
if (id ===
|
|
1280
|
+
if (id === RESOLVED_BRIDGE_ID) return `
|
|
1055
1281
|
import css from '${VIRTUAL_COMPONENTS_ID}';
|
|
1056
1282
|
|
|
1057
1283
|
const GLOBAL_KEY = '__animus_sheet_${(0, crypto.createHash)("md5").update(ctx.options.system).digest("hex").slice(0, 8)}__';
|
|
1058
1284
|
let sheet = globalThis[GLOBAL_KEY] || null;
|
|
1059
1285
|
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
document.
|
|
1286
|
+
// Server evaluation is a no-op: SSR hosts reach this module through the
|
|
1287
|
+
// bridge import prepended to transformed component modules, and only the
|
|
1288
|
+
// browser pass owns a document.
|
|
1289
|
+
if (typeof document !== 'undefined') {
|
|
1290
|
+
if (typeof CSSStyleSheet !== 'undefined' && 'adoptedStyleSheets' in document) {
|
|
1291
|
+
if (!sheet) {
|
|
1292
|
+
sheet = new CSSStyleSheet();
|
|
1293
|
+
globalThis[GLOBAL_KEY] = sheet;
|
|
1294
|
+
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
|
|
1295
|
+
}
|
|
1296
|
+
sheet.replaceSync(css);
|
|
1297
|
+
} else {
|
|
1298
|
+
// Fallback: inject or update <style> tag
|
|
1299
|
+
let el = document.querySelector('style[data-animus-components]');
|
|
1300
|
+
if (!el) {
|
|
1301
|
+
el = document.createElement('style');
|
|
1302
|
+
el.setAttribute('data-animus-components', '');
|
|
1303
|
+
document.head.appendChild(el);
|
|
1304
|
+
}
|
|
1305
|
+
el.textContent = css;
|
|
1074
1306
|
}
|
|
1075
|
-
el.textContent = css;
|
|
1076
1307
|
}
|
|
1077
1308
|
|
|
1078
1309
|
if (import.meta.hot) {
|
|
1079
1310
|
import.meta.hot.accept('${VIRTUAL_COMPONENTS_ID}', (newModule) => {
|
|
1311
|
+
// The server module runner has a hot channel too; only the browser
|
|
1312
|
+
// pass owns a document to update.
|
|
1313
|
+
if (typeof document === 'undefined') return;
|
|
1080
1314
|
if (sheet) {
|
|
1081
1315
|
sheet.replaceSync(newModule.default);
|
|
1082
1316
|
} else {
|
|
@@ -1086,12 +1320,7 @@ if (import.meta.hot) {
|
|
|
1086
1320
|
});
|
|
1087
1321
|
}
|
|
1088
1322
|
`;
|
|
1089
|
-
if (id ===
|
|
1090
|
-
systemPropMapJson: ctx.storedSystemPropMapJson,
|
|
1091
|
-
groupRegistryJson: ctx.system.groupRegistryJson,
|
|
1092
|
-
dynamicProps: JSON.parse(ctx.storedDynamicPropsJson),
|
|
1093
|
-
transformsSource: ctx.storedTransformsSource
|
|
1094
|
-
});
|
|
1323
|
+
if (id === RESOLVED_SYSTEM_PROPS_ID) return systemPropsModuleSource(ctx);
|
|
1095
1324
|
return null;
|
|
1096
1325
|
}
|
|
1097
1326
|
//#endregion
|
|
@@ -1107,6 +1336,9 @@ function animusExtract(options) {
|
|
|
1107
1336
|
return {
|
|
1108
1337
|
name: "animus-extract",
|
|
1109
1338
|
enforce: "pre",
|
|
1339
|
+
config(_config, env) {
|
|
1340
|
+
return { define: { __ANIMUS_DEV__: env.command !== "build" } };
|
|
1341
|
+
},
|
|
1110
1342
|
configureServer(server) {
|
|
1111
1343
|
ctx.devServer = server;
|
|
1112
1344
|
ctx.registerSystemWatchPaths();
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,MAAM,WAAW,oBAAoB;IACnC;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,qGAAqG;IACrG,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,IAAI,CAAC;IACd;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,mBAAmB,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACzD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,MAAM,WAAW,oBAAoB;IACnC;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,qGAAqG;IACrG,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,IAAI,CAAC;IACd;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,mBAAmB,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACzD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CA0EnE;eAEc,aAAa"}
|
package/dist/transform.d.ts
CHANGED
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
import type { PluginContext } from './context';
|
|
2
|
+
/**
|
|
3
|
+
* The dev-mode bridge prepend, shared with the hot-update gate so both
|
|
4
|
+
* compute byte-identical served output. The import goes AFTER the directive
|
|
5
|
+
* prologue the engine hoists to byte 0 — prepending above it would demote
|
|
6
|
+
* 'use client'/'use strict' to an ordinary expression statement, silently
|
|
7
|
+
* un-marking client modules on exactly the RSC-capable hosts this delivery
|
|
8
|
+
* path serves.
|
|
9
|
+
*/
|
|
10
|
+
export declare function applyDevBridgeImport(code: string): string;
|
|
2
11
|
/**
|
|
3
12
|
* transform: replace builder chains with `createComponent()` calls using
|
|
4
|
-
* the pre-built manifest;
|
|
5
|
-
*
|
|
13
|
+
* the pre-built manifest; detect files created after buildStart and fold
|
|
14
|
+
* them into the analysis.
|
|
15
|
+
*
|
|
16
|
+
* The HMR bridge is NOT injected here — `transformIndexHtml` delivers it as a
|
|
17
|
+
* `<script type="module">` per served document (openspec:
|
|
18
|
+
* dev-stylesheet-management, "HMR bridge auto-injected in dev mode"; "Transform
|
|
19
|
+
* emitter unchanged" forbids the emitter importing it).
|
|
6
20
|
*/
|
|
7
21
|
export declare function transformSource(ctx: PluginContext, code: string, id: string): {
|
|
8
22
|
code: string;
|
package/dist/transform.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKzD;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACT;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,IAAI,CAAA;CAAE,GAAG,IAAI,CAqHpC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"virtual-modules.d.ts","sourceRoot":"","sources":["../src/virtual-modules.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,aAAa,EAClB,EAAE,EAAE,MAAM,GACT,MAAM,GAAG,IAAI,CAYf;AAED;wDACwD;AACxD,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,aAAa,EAClB,EAAE,EAAE,MAAM,GACT,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"virtual-modules.d.ts","sourceRoot":"","sources":["../src/virtual-modules.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,aAAa,EAClB,EAAE,EAAE,MAAM,GACT,MAAM,GAAG,IAAI,CAYf;AAED;wDACwD;AACxD,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,aAAa,EAClB,EAAE,EAAE,MAAM,GACT,MAAM,GAAG,IAAI,CA8Gf"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@animus-ui/vite-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Animus static CSS extraction Vite plugin",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"animus",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"compile": "tsc --noEmit"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@animus-ui/extract": "0.1.
|
|
42
|
+
"@animus-ui/extract": "0.1.6",
|
|
43
43
|
"browserslist": "^4.24.0",
|
|
44
44
|
"lightningcss": "^1.29.0"
|
|
45
45
|
},
|