@microsoft/fast-element 2.7.0 → 2.8.0
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/CHANGELOG.json +16 -1
- package/CHANGELOG.md +10 -2
- package/dist/dts/components/element-controller.d.ts +30 -0
- package/dist/dts/components/fast-definitions.d.ts +31 -2
- package/dist/dts/index.d.ts +2 -2
- package/dist/esm/components/element-controller.js +29 -8
- package/dist/esm/components/fast-definitions.js +17 -12
- package/dist/esm/components/fast-element.js +14 -15
- package/dist/esm/index.js +1 -1
- package/dist/esm/templating/view.js +23 -2
- package/dist/fast-element.api.json +400 -2
- package/dist/fast-element.debug.js +74 -37
- package/dist/fast-element.debug.min.js +2 -2
- package/dist/fast-element.js +74 -37
- package/dist/fast-element.min.js +2 -2
- package/dist/fast-element.untrimmed.d.ts +64 -2
- package/docs/api-report.api.md +22 -1
- package/package.json +1 -1
package/CHANGELOG.json
CHANGED
|
@@ -2,7 +2,22 @@
|
|
|
2
2
|
"name": "@microsoft/fast-element",
|
|
3
3
|
"entries": [
|
|
4
4
|
{
|
|
5
|
-
"date": "
|
|
5
|
+
"date": "Mon, 13 Oct 2025 00:36:35 GMT",
|
|
6
|
+
"version": "2.8.0",
|
|
7
|
+
"tag": "@microsoft/fast-element_v2.8.0",
|
|
8
|
+
"comments": {
|
|
9
|
+
"minor": [
|
|
10
|
+
{
|
|
11
|
+
"author": "863023+radium-v@users.noreply.github.com",
|
|
12
|
+
"package": "@microsoft/fast-element",
|
|
13
|
+
"commit": "28a1d5dcae41f04e2ff8cb9114c312efb88fb1e1",
|
|
14
|
+
"comment": "[feat]: implement lifecycle callbacks for hydration and template events"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"date": "Wed, 20 Aug 2025 20:57:02 GMT",
|
|
6
21
|
"version": "2.7.0",
|
|
7
22
|
"tag": "@microsoft/fast-element_v2.7.0",
|
|
8
23
|
"comments": {
|
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
# Change Log - @microsoft/fast-element
|
|
2
2
|
|
|
3
|
-
<!-- This log was last generated on
|
|
3
|
+
<!-- This log was last generated on Mon, 13 Oct 2025 00:36:35 GMT and should not be manually modified. -->
|
|
4
4
|
|
|
5
5
|
<!-- Start content -->
|
|
6
6
|
|
|
7
|
+
## 2.8.0
|
|
8
|
+
|
|
9
|
+
Mon, 13 Oct 2025 00:36:35 GMT
|
|
10
|
+
|
|
11
|
+
### Minor changes
|
|
12
|
+
|
|
13
|
+
- [feat]: implement lifecycle callbacks for hydration and template events (863023+radium-v@users.noreply.github.com)
|
|
14
|
+
|
|
7
15
|
## 2.7.0
|
|
8
16
|
|
|
9
|
-
Wed, 20 Aug 2025 20:
|
|
17
|
+
Wed, 20 Aug 2025 20:57:02 GMT
|
|
10
18
|
|
|
11
19
|
### Minor changes
|
|
12
20
|
|
|
@@ -206,6 +206,24 @@ export declare class StyleElementStrategy implements StyleStrategy {
|
|
|
206
206
|
}
|
|
207
207
|
export declare const deferHydrationAttribute = "defer-hydration";
|
|
208
208
|
export declare const needsHydrationAttribute = "needs-hydration";
|
|
209
|
+
/**
|
|
210
|
+
* Lifecycle callbacks for element hydration events
|
|
211
|
+
* @public
|
|
212
|
+
*/
|
|
213
|
+
export interface HydrationControllerCallbacks {
|
|
214
|
+
/**
|
|
215
|
+
* Called before hydration has started
|
|
216
|
+
*/
|
|
217
|
+
elementWillHydrate?(name: string): void;
|
|
218
|
+
/**
|
|
219
|
+
* Called after hydration has finished
|
|
220
|
+
*/
|
|
221
|
+
elementDidHydrate?(name: string): void;
|
|
222
|
+
/**
|
|
223
|
+
* Called after all elements have completed hydration
|
|
224
|
+
*/
|
|
225
|
+
hydrationComplete?(): void;
|
|
226
|
+
}
|
|
209
227
|
/**
|
|
210
228
|
* An ElementController capable of hydrating FAST elements from
|
|
211
229
|
* Declarative Shadow DOM.
|
|
@@ -220,7 +238,19 @@ export declare class HydratableElementController<TElement extends HTMLElement =
|
|
|
220
238
|
*/
|
|
221
239
|
protected needsHydration?: boolean;
|
|
222
240
|
private static hydrationObserver;
|
|
241
|
+
/**
|
|
242
|
+
* Lifecycle callbacks for hydration events
|
|
243
|
+
*/
|
|
244
|
+
private static lifecycleCallbacks?;
|
|
245
|
+
/**
|
|
246
|
+
* Configure lifecycle callbacks for hydration events
|
|
247
|
+
*/
|
|
248
|
+
static config(callbacks: HydrationControllerCallbacks): typeof HydratableElementController;
|
|
223
249
|
private static hydrationObserverHandler;
|
|
250
|
+
/**
|
|
251
|
+
* Checks if all elements have completed hydration and dispatches event if complete
|
|
252
|
+
*/
|
|
253
|
+
private static checkHydrationComplete;
|
|
224
254
|
static forCustomElement(element: HTMLElement, override?: boolean): ElementController<HTMLElement>;
|
|
225
255
|
connect(): void;
|
|
226
256
|
disconnect(): void;
|
|
@@ -22,10 +22,31 @@ export interface ShadowRootOptions extends ShadowRootInit {
|
|
|
22
22
|
registry?: CustomElementRegistry;
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
25
|
+
* Values for the `templateOptions` property.
|
|
26
26
|
* @alpha
|
|
27
27
|
*/
|
|
28
|
-
export declare
|
|
28
|
+
export declare const TemplateOptions: {
|
|
29
|
+
readonly deferAndHydrate: "defer-and-hydrate";
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Type for the `TemplateOptions` const enum.
|
|
33
|
+
* @alpha
|
|
34
|
+
*/
|
|
35
|
+
export declare type TemplateOptions = (typeof TemplateOptions)[keyof typeof TemplateOptions];
|
|
36
|
+
/**
|
|
37
|
+
* Lifecycle callbacks for template events.
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
export interface TemplateLifecycleCallbacks {
|
|
41
|
+
/**
|
|
42
|
+
* Called after the template has been assigned to the definition
|
|
43
|
+
*/
|
|
44
|
+
templateDidUpdate?(name: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Called after the custom element has been defined
|
|
47
|
+
*/
|
|
48
|
+
elementDidDefine?(name: string): void;
|
|
49
|
+
}
|
|
29
50
|
/**
|
|
30
51
|
* Represents metadata configuration for a custom element.
|
|
31
52
|
* @public
|
|
@@ -69,6 +90,10 @@ export interface PartialFASTElementDefinition {
|
|
|
69
90
|
* If not provided, defaults to the global registry.
|
|
70
91
|
*/
|
|
71
92
|
readonly registry?: CustomElementRegistry;
|
|
93
|
+
/**
|
|
94
|
+
* Lifecycle callbacks for template events.
|
|
95
|
+
*/
|
|
96
|
+
readonly lifecycleCallbacks?: TemplateLifecycleCallbacks;
|
|
72
97
|
}
|
|
73
98
|
/**
|
|
74
99
|
* Defines metadata for a FASTElement.
|
|
@@ -125,6 +150,10 @@ export declare class FASTElementDefinition<TType extends Constructable<HTMLEleme
|
|
|
125
150
|
* The registry to register this component in by default.
|
|
126
151
|
*/
|
|
127
152
|
readonly registry: CustomElementRegistry;
|
|
153
|
+
/**
|
|
154
|
+
* Lifecycle callbacks for template events.
|
|
155
|
+
*/
|
|
156
|
+
readonly lifecycleCallbacks?: TemplateLifecycleCallbacks;
|
|
128
157
|
/**
|
|
129
158
|
* The definition has been registered to the FAST element registry.
|
|
130
159
|
*/
|
package/dist/dts/index.d.ts
CHANGED
|
@@ -29,6 +29,6 @@ export { ElementView, HTMLView, SyntheticView, View, HydratableView, HydrationBi
|
|
|
29
29
|
export { elements, ElementsFilter, NodeBehaviorOptions, NodeObservationDirective, } from "./templating/node-observation.js";
|
|
30
30
|
export { render, RenderBehavior, RenderDirective } from "./templating/render.js";
|
|
31
31
|
export { customElement, FASTElement } from "./components/fast-element.js";
|
|
32
|
-
export { FASTElementDefinition, PartialFASTElementDefinition, ShadowRootOptions, fastElementRegistry, TemplateOptions, TypeRegistry, } from "./components/fast-definitions.js";
|
|
32
|
+
export { FASTElementDefinition, PartialFASTElementDefinition, ShadowRootOptions, fastElementRegistry, TemplateOptions, TypeRegistry, type TemplateLifecycleCallbacks, } from "./components/fast-definitions.js";
|
|
33
33
|
export { attr, AttributeConfiguration, AttributeDefinition, AttributeMode, booleanConverter, DecoratorAttributeConfiguration, nullableBooleanConverter, nullableNumberConverter, ValueConverter, } from "./components/attributes.js";
|
|
34
|
-
export { ElementController, ElementControllerStrategy, HydratableElementController, } from "./components/element-controller.js";
|
|
34
|
+
export { ElementController, ElementControllerStrategy, HydratableElementController, type HydrationControllerCallbacks, } from "./components/element-controller.js";
|
|
@@ -4,7 +4,7 @@ import { ExecutionContext, Observable, SourceLifetime, } from "../observation/ob
|
|
|
4
4
|
import { FAST, makeSerializationNoop } from "../platform.js";
|
|
5
5
|
import { ElementStyles } from "../styles/element-styles.js";
|
|
6
6
|
import { UnobservableMutationObserver } from "../utilities.js";
|
|
7
|
-
import { FASTElementDefinition } from "./fast-definitions.js";
|
|
7
|
+
import { FASTElementDefinition, TemplateOptions, } from "./fast-definitions.js";
|
|
8
8
|
import { HydrationMarkup, isHydratable } from "./hydration.js";
|
|
9
9
|
const defaultEventOptions = {
|
|
10
10
|
bubbles: true,
|
|
@@ -591,24 +591,39 @@ export const needsHydrationAttribute = "needs-hydration";
|
|
|
591
591
|
* @beta
|
|
592
592
|
*/
|
|
593
593
|
export class HydratableElementController extends ElementController {
|
|
594
|
+
/**
|
|
595
|
+
* Configure lifecycle callbacks for hydration events
|
|
596
|
+
*/
|
|
597
|
+
static config(callbacks) {
|
|
598
|
+
HydratableElementController.lifecycleCallbacks = callbacks;
|
|
599
|
+
return this;
|
|
600
|
+
}
|
|
594
601
|
static hydrationObserverHandler(records) {
|
|
595
602
|
for (const record of records) {
|
|
596
603
|
HydratableElementController.hydrationObserver.unobserve(record.target);
|
|
597
604
|
record.target.$fastController.connect();
|
|
598
605
|
}
|
|
599
606
|
}
|
|
607
|
+
/**
|
|
608
|
+
* Checks if all elements have completed hydration and dispatches event if complete
|
|
609
|
+
*/
|
|
610
|
+
static checkHydrationComplete() {
|
|
611
|
+
var _a, _b;
|
|
612
|
+
if (!document.querySelector(`[${needsHydrationAttribute}]`)) {
|
|
613
|
+
(_b = (_a = HydratableElementController.lifecycleCallbacks) === null || _a === void 0 ? void 0 : _a.hydrationComplete) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
600
616
|
static forCustomElement(element, override) {
|
|
601
617
|
const definition = FASTElementDefinition.getForInstance(element);
|
|
602
|
-
if (definition
|
|
603
|
-
definition.templateOptions === "defer-and-hydrate" &&
|
|
618
|
+
if ((definition === null || definition === void 0 ? void 0 : definition.templateOptions) === TemplateOptions.deferAndHydrate &&
|
|
604
619
|
!definition.template) {
|
|
605
|
-
element.
|
|
606
|
-
element.
|
|
620
|
+
element.toggleAttribute(deferHydrationAttribute, true);
|
|
621
|
+
element.toggleAttribute(needsHydrationAttribute, true);
|
|
607
622
|
}
|
|
608
623
|
return super.forCustomElement(element, override);
|
|
609
624
|
}
|
|
610
625
|
connect() {
|
|
611
|
-
var _a, _b;
|
|
626
|
+
var _a, _b, _c, _d, _e, _f;
|
|
612
627
|
// Initialize needsHydration on first connect
|
|
613
628
|
if (this.needsHydration === undefined) {
|
|
614
629
|
this.needsHydration =
|
|
@@ -633,11 +648,13 @@ export class HydratableElementController extends ElementController {
|
|
|
633
648
|
if (this.stage !== 3 /* Stages.disconnected */) {
|
|
634
649
|
return;
|
|
635
650
|
}
|
|
651
|
+
// Callback: Before hydration has started
|
|
652
|
+
(_b = (_a = HydratableElementController.lifecycleCallbacks) === null || _a === void 0 ? void 0 : _a.elementWillHydrate) === null || _b === void 0 ? void 0 : _b.call(_a, this.definition.name);
|
|
636
653
|
this.stage = 0 /* Stages.connecting */;
|
|
637
654
|
this.bindObservables();
|
|
638
655
|
this.connectBehaviors();
|
|
639
656
|
const element = this.source;
|
|
640
|
-
const host = (
|
|
657
|
+
const host = (_c = getShadowRoot(element)) !== null && _c !== void 0 ? _c : element;
|
|
641
658
|
if (this.template) {
|
|
642
659
|
if (isHydratable(this.template)) {
|
|
643
660
|
let firstChild = host.firstChild;
|
|
@@ -654,7 +671,7 @@ export class HydratableElementController extends ElementController {
|
|
|
654
671
|
}
|
|
655
672
|
}
|
|
656
673
|
this.view = this.template.hydrate(firstChild, lastChild, element);
|
|
657
|
-
(
|
|
674
|
+
(_d = this.view) === null || _d === void 0 ? void 0 : _d.bind(this.source);
|
|
658
675
|
}
|
|
659
676
|
else {
|
|
660
677
|
this.renderTemplate(this.template);
|
|
@@ -665,6 +682,10 @@ export class HydratableElementController extends ElementController {
|
|
|
665
682
|
this.source.removeAttribute(needsHydrationAttribute);
|
|
666
683
|
this.needsInitialization = this.needsHydration = false;
|
|
667
684
|
Observable.notify(this, isConnectedPropertyName);
|
|
685
|
+
// Callback: After hydration has finished
|
|
686
|
+
(_f = (_e = HydratableElementController.lifecycleCallbacks) === null || _e === void 0 ? void 0 : _e.elementDidHydrate) === null || _f === void 0 ? void 0 : _f.call(_e, this.definition.name);
|
|
687
|
+
// Check if hydration is complete after this element is hydrated
|
|
688
|
+
HydratableElementController.checkHydrationComplete();
|
|
668
689
|
}
|
|
669
690
|
disconnect() {
|
|
670
691
|
super.disconnect();
|
|
@@ -21,6 +21,13 @@ const fastElementBaseTypes = new Set();
|
|
|
21
21
|
* @internal
|
|
22
22
|
*/
|
|
23
23
|
export const fastElementRegistry = FAST.getById(KernelServiceId.elementRegistry, () => createTypeRegistry());
|
|
24
|
+
/**
|
|
25
|
+
* Values for the `templateOptions` property.
|
|
26
|
+
* @alpha
|
|
27
|
+
*/
|
|
28
|
+
export const TemplateOptions = {
|
|
29
|
+
deferAndHydrate: "defer-and-hydrate",
|
|
30
|
+
};
|
|
24
31
|
/**
|
|
25
32
|
* Defines metadata for a FASTElement.
|
|
26
33
|
* @public
|
|
@@ -84,10 +91,12 @@ export class FASTElementDefinition {
|
|
|
84
91
|
* This operation is idempotent per registry.
|
|
85
92
|
*/
|
|
86
93
|
define(registry = this.registry) {
|
|
94
|
+
var _b, _c;
|
|
87
95
|
const type = this.type;
|
|
88
96
|
if (!registry.get(this.name)) {
|
|
89
97
|
this.platformDefined = true;
|
|
90
98
|
registry.define(this.name, type, this.elementOptions);
|
|
99
|
+
(_c = (_b = this.lifecycleCallbacks) === null || _b === void 0 ? void 0 : _b.elementDidDefine) === null || _c === void 0 ? void 0 : _c.call(_b, this.name);
|
|
91
100
|
}
|
|
92
101
|
return this;
|
|
93
102
|
}
|
|
@@ -128,15 +137,13 @@ export class FASTElementDefinition {
|
|
|
128
137
|
}, nameOrDef));
|
|
129
138
|
}
|
|
130
139
|
const definition = new FASTElementDefinition(type, nameOrDef);
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
resolve(definition);
|
|
139
|
-
});
|
|
140
|
+
Observable.getNotifier(definition).subscribe({
|
|
141
|
+
handleChange: () => {
|
|
142
|
+
var _b, _c;
|
|
143
|
+
(_c = (_b = definition.lifecycleCallbacks) === null || _b === void 0 ? void 0 : _b.templateDidUpdate) === null || _c === void 0 ? void 0 : _c.call(_b, definition.name);
|
|
144
|
+
resolve(definition);
|
|
145
|
+
},
|
|
146
|
+
}, "template");
|
|
140
147
|
});
|
|
141
148
|
}
|
|
142
149
|
}
|
|
@@ -165,9 +172,7 @@ FASTElementDefinition.registerAsync = (name) => __awaiter(void 0, void 0, void 0
|
|
|
165
172
|
if (FASTElementDefinition.isRegistered[name]) {
|
|
166
173
|
resolve(FASTElementDefinition.isRegistered[name]);
|
|
167
174
|
}
|
|
168
|
-
Observable.getNotifier(FASTElementDefinition.isRegistered).subscribe({
|
|
169
|
-
handleChange: () => resolve(FASTElementDefinition.isRegistered[name]),
|
|
170
|
-
}, name);
|
|
175
|
+
Observable.getNotifier(FASTElementDefinition.isRegistered).subscribe({ handleChange: () => resolve(FASTElementDefinition.isRegistered[name]) }, name);
|
|
171
176
|
});
|
|
172
177
|
});
|
|
173
178
|
Observable.defineProperty(FASTElementDefinition.prototype, "template");
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
1
10
|
import { isFunction } from "../interfaces.js";
|
|
2
11
|
import { ElementController } from "./element-controller.js";
|
|
3
12
|
import { FASTElementDefinition, } from "./fast-definitions.js";
|
|
@@ -32,21 +41,11 @@ function compose(type, nameOrDef) {
|
|
|
32
41
|
return FASTElementDefinition.compose(this, type);
|
|
33
42
|
}
|
|
34
43
|
function defineAsync(type, nameOrDef) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
FASTElementDefinition.composeAsync(type, nameOrDef).
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}).then(value => {
|
|
41
|
-
return value.define().type;
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
return new Promise(resolve => {
|
|
45
|
-
FASTElementDefinition.composeAsync(this, type).then(value => {
|
|
46
|
-
resolve(value);
|
|
47
|
-
});
|
|
48
|
-
}).then(value => {
|
|
49
|
-
return value.define().type;
|
|
44
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
45
|
+
if (isFunction(type)) {
|
|
46
|
+
return (yield FASTElementDefinition.composeAsync(type, nameOrDef)).define().type;
|
|
47
|
+
}
|
|
48
|
+
return (yield FASTElementDefinition.composeAsync(this, type)).define().type;
|
|
50
49
|
});
|
|
51
50
|
}
|
|
52
51
|
function define(type, nameOrDef) {
|
package/dist/esm/index.js
CHANGED
|
@@ -34,6 +34,6 @@ export { elements, NodeObservationDirective, } from "./templating/node-observati
|
|
|
34
34
|
export { render, RenderBehavior, RenderDirective } from "./templating/render.js";
|
|
35
35
|
// Components
|
|
36
36
|
export { customElement, FASTElement } from "./components/fast-element.js";
|
|
37
|
-
export { FASTElementDefinition, fastElementRegistry, } from "./components/fast-definitions.js";
|
|
37
|
+
export { FASTElementDefinition, fastElementRegistry, TemplateOptions, } from "./components/fast-definitions.js";
|
|
38
38
|
export { attr, AttributeConfiguration, AttributeDefinition, booleanConverter, nullableBooleanConverter, nullableNumberConverter, } from "./components/attributes.js";
|
|
39
39
|
export { ElementController, HydratableElementController, } from "./components/element-controller.js";
|
|
@@ -360,7 +360,7 @@ export class HydrationView extends DefaultExecutionContext {
|
|
|
360
360
|
fragment.appendChild(end);
|
|
361
361
|
}
|
|
362
362
|
bind(source, context = this) {
|
|
363
|
-
var _b
|
|
363
|
+
var _b;
|
|
364
364
|
if (this.hydrationStage !== HydrationStage.hydrated) {
|
|
365
365
|
this._hydrationStage = HydrationStage.hydrating;
|
|
366
366
|
}
|
|
@@ -404,7 +404,28 @@ export class HydrationView extends DefaultExecutionContext {
|
|
|
404
404
|
if (typeof templateString !== "string") {
|
|
405
405
|
templateString = templateString.innerHTML;
|
|
406
406
|
}
|
|
407
|
-
|
|
407
|
+
const hostElement = ((_b = this.firstChild) === null || _b === void 0 ? void 0 : _b.getRootNode())
|
|
408
|
+
.host;
|
|
409
|
+
const hostName = (hostElement === null || hostElement === void 0 ? void 0 : hostElement.nodeName) || "unknown";
|
|
410
|
+
const factoryInfo = factory;
|
|
411
|
+
// Build detailed error message
|
|
412
|
+
const details = [
|
|
413
|
+
`HydrationView was unable to successfully target bindings inside "<${hostName.toLowerCase()}>".`,
|
|
414
|
+
`\nMismatch Details:`,
|
|
415
|
+
` - Expected target node ID: "${factory.targetNodeId}"`,
|
|
416
|
+
` - Available target IDs: [${Object.keys(this.targets).join(", ") || "none"}]`,
|
|
417
|
+
];
|
|
418
|
+
if (factory.targetTagName) {
|
|
419
|
+
details.push(` - Expected tag name: "${factory.targetTagName}"`);
|
|
420
|
+
}
|
|
421
|
+
if (factoryInfo.sourceAspect) {
|
|
422
|
+
details.push(` - Source aspect: "${factoryInfo.sourceAspect}"`);
|
|
423
|
+
}
|
|
424
|
+
if (factoryInfo.aspectType !== undefined) {
|
|
425
|
+
details.push(` - Aspect type: ${factoryInfo.aspectType}`);
|
|
426
|
+
}
|
|
427
|
+
details.push(`\nThis usually means:`, ` 1. The server-rendered HTML doesn't match the client template`, ` 2. The hydration markers are missing or corrupted`, ` 3. The DOM structure was modified before hydration`, `\nTemplate: ${templateString.slice(0, 200)}${templateString.length > 200 ? "..." : ""}`);
|
|
428
|
+
throw new HydrationBindingError(details.join("\n"), factory, createRangeForNodes(this.firstChild, this.lastChild).cloneContents(), templateString);
|
|
408
429
|
}
|
|
409
430
|
}
|
|
410
431
|
}
|