@adobe-commerce/elsie 2.1.0-beta.5 → 2.1.0-beta.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/CHANGELOG.md +10 -0
- package/package.json +2 -2
- package/src/lib/aem/assets.ts +9 -18
- package/src/lib/slot.tsx +3 -56
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @adobe-commerce/elsie
|
|
2
2
|
|
|
3
|
+
## 2.1.0-beta.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 406a36d: Restore the existing Slot implementation and temporarily downgrade
|
|
8
|
+
Preact from 10.29 to 10.28.4, the latest pre-10.29 release, to avoid
|
|
9
|
+
intermittent `insertBefore` crashes in AEM Asset image Slots while the
|
|
10
|
+
underlying DOM graft and render-root ownership changes are developed and
|
|
11
|
+
validated separately.
|
|
12
|
+
|
|
3
13
|
## 2.1.0-beta.5
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe-commerce/elsie",
|
|
3
|
-
"version": "2.1.0-beta.
|
|
3
|
+
"version": "2.1.0-beta.6",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
5
5
|
"description": "Domain Package SDK",
|
|
6
6
|
"engines": {
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"identity-obj-proxy": "^3.0.0",
|
|
88
88
|
"jest": "^30.4.2",
|
|
89
89
|
"jest-environment-jsdom": "^30.0.0",
|
|
90
|
-
"preact": "~10.
|
|
90
|
+
"preact": "~10.28.4",
|
|
91
91
|
"preact-i18n": "2.4.0-preactx",
|
|
92
92
|
"preact-render-to-string": "^5.1.4",
|
|
93
93
|
"prettier": "^3.8.4",
|
package/src/lib/aem/assets.ts
CHANGED
|
@@ -238,7 +238,7 @@ export function tryGenerateAemAssetsOptimizedUrl(
|
|
|
238
238
|
|
|
239
239
|
/** Creates a slot that renders an AEM Assets image. */
|
|
240
240
|
export function makeAemAssetsImageSlot(config: AemAssetsImageSlotConfig) {
|
|
241
|
-
return
|
|
241
|
+
return (ctx: RenderContext) => {
|
|
242
242
|
const { wrapper, alias, params, imageProps } = config;
|
|
243
243
|
|
|
244
244
|
if (!imageProps.src) {
|
|
@@ -274,25 +274,17 @@ export function makeAemAssetsImageSlot(config: AemAssetsImageSlotConfig) {
|
|
|
274
274
|
params: imageComponentParams,
|
|
275
275
|
};
|
|
276
276
|
|
|
277
|
-
|
|
278
|
-
// rendering into `container` before handing it to `ctx.replaceWith`.
|
|
279
|
-
// Slot grafts `container` into the DOM via an imperative `ref` callback
|
|
280
|
-
// that Preact's own diffing doesn't track (see docs/slot-dom-graft-race.md)
|
|
281
|
-
// -- handing it over before it has content means it gets grafted empty,
|
|
282
|
-
// then mutated again later outside Preact's bookkeeping, which is what
|
|
283
|
-
// was corrupting Preact's internal DOM pointers and causing sporadic
|
|
284
|
-
// `insertBefore` crashes after the preact 10.29 bump.
|
|
285
|
-
await UI.render(Image, imageComponentProps)(container);
|
|
277
|
+
UI.render(Image, imageComponentProps)(container);
|
|
286
278
|
ctx.replaceWith(container);
|
|
287
279
|
};
|
|
288
280
|
}
|
|
289
281
|
|
|
290
|
-
export
|
|
282
|
+
export function tryRenderAemAssetsImage(
|
|
291
283
|
ctx: RenderContext,
|
|
292
284
|
config: AemAssetsImageSlotConfig,
|
|
293
|
-
):
|
|
285
|
+
): void {
|
|
294
286
|
// Renders an equivalent of the default image.
|
|
295
|
-
|
|
287
|
+
function renderDefaultImage(): void {
|
|
296
288
|
const container = config.wrapper ?? document.createElement('div');
|
|
297
289
|
const { imageProps, params } = config;
|
|
298
290
|
const imageComponentProps: ImageProps = {
|
|
@@ -301,8 +293,7 @@ export async function tryRenderAemAssetsImage(
|
|
|
301
293
|
height: params.height,
|
|
302
294
|
};
|
|
303
295
|
|
|
304
|
-
|
|
305
|
-
await UI.render(Image, imageComponentProps)(container);
|
|
296
|
+
UI.render(Image, imageComponentProps)(container);
|
|
306
297
|
ctx.replaceWith(container);
|
|
307
298
|
}
|
|
308
299
|
|
|
@@ -310,7 +301,7 @@ export async function tryRenderAemAssetsImage(
|
|
|
310
301
|
|
|
311
302
|
if (!assetsEnabled) {
|
|
312
303
|
// No-op, render the default image.
|
|
313
|
-
|
|
304
|
+
renderDefaultImage();
|
|
314
305
|
return;
|
|
315
306
|
}
|
|
316
307
|
|
|
@@ -324,9 +315,9 @@ export async function tryRenderAemAssetsImage(
|
|
|
324
315
|
|
|
325
316
|
if (!isAemAssetsUrl(assetsUrl)) {
|
|
326
317
|
// Not an AEM Assets URL, so render the default image.
|
|
327
|
-
|
|
318
|
+
renderDefaultImage();
|
|
328
319
|
return;
|
|
329
320
|
}
|
|
330
321
|
|
|
331
|
-
|
|
322
|
+
makeAemAssetsImageSlot(config)(ctx);
|
|
332
323
|
}
|
package/src/lib/slot.tsx
CHANGED
|
@@ -146,21 +146,9 @@ export function useSlot<K, V extends HTMLElement>(
|
|
|
146
146
|
});
|
|
147
147
|
};
|
|
148
148
|
|
|
149
|
-
const handleLifeCycleRenderRef = useRef<() => Promise<void>>();
|
|
150
|
-
|
|
151
149
|
const _registerMethod = useCallback((cb: Function) => {
|
|
152
150
|
if (typeof cb === 'function') {
|
|
153
151
|
methodsRef.current.push(cb);
|
|
154
|
-
|
|
155
|
-
// If the slot already finished its normal init-triggered render pass
|
|
156
|
-
// (status is back to 'ready'), nothing else will flush this method.
|
|
157
|
-
// This happens when an async `slot` callback doesn't `return`/`await`
|
|
158
|
-
// its own async work before calling replaceWith/appendChild/etc. --
|
|
159
|
-
// `handleLifeCycleInit` moves on before this method gets registered.
|
|
160
|
-
// Flush it ourselves rather than silently dropping it.
|
|
161
|
-
if (status.current === 'ready') {
|
|
162
|
-
handleLifeCycleRenderRef.current?.();
|
|
163
|
-
}
|
|
164
152
|
} else {
|
|
165
153
|
console.warn('Skipped: Invalid _registerMethod', cb);
|
|
166
154
|
}
|
|
@@ -169,59 +157,20 @@ export function useSlot<K, V extends HTMLElement>(
|
|
|
169
157
|
// @ts-ignore
|
|
170
158
|
context._registerMethod = _registerMethod;
|
|
171
159
|
|
|
172
|
-
// `onRender`-style registered methods are replayed on every
|
|
173
|
-
// `handleLifeCycleRender` pass (see `_registerMethod`/`methodsRef` above),
|
|
174
|
-
// and `handleLifeCycleRender` always resets `children` to the fallback
|
|
175
|
-
// before replaying them -- so `replaceWith`/`appendChild`/`prependChild`
|
|
176
|
-
// must genuinely re-apply their VNode on every replay, not just once.
|
|
177
|
-
// Without caching, each replay would call `createElement` fresh, handing
|
|
178
|
-
// Preact a brand new VNode (and new `ref` identity) for content that's
|
|
179
|
-
// already grafted, forcing it to detach/reattach the `ref` for no reason.
|
|
180
|
-
// Caching per `elem` means repeat calls return the *same* VNode object;
|
|
181
|
-
// Preact's diff treats `oldVNode === newVNode` as an explicit "unchanged,
|
|
182
|
-
// skip" signal, so it never re-touches the grafted subtree. See
|
|
183
|
-
// docs/slot-dom-graft-race.md.
|
|
184
|
-
const htmlElementVNodeCache = useMemo(
|
|
185
|
-
() => new Map<HTMLElement, VNode<any>>(),
|
|
186
|
-
// `contentTag` isn't read by the factory -- it's a deliberate cache-bust
|
|
187
|
-
// key, so a `contentTag` change starts a fresh cache instead of handing
|
|
188
|
-
// out VNodes built for the old wrapper tag.
|
|
189
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
190
|
-
[contentTag],
|
|
191
|
-
);
|
|
192
|
-
|
|
193
160
|
const _htmlElementToVNode = useCallback(
|
|
194
161
|
(elem: HTMLElement) => {
|
|
195
|
-
|
|
196
|
-
if (cached) return cached;
|
|
197
|
-
|
|
198
|
-
const vnode = createElement(
|
|
162
|
+
return createElement(
|
|
199
163
|
contentTag,
|
|
200
164
|
{
|
|
201
165
|
'data-slot-html-element': elem.tagName.toLowerCase(),
|
|
202
166
|
ref: (refElem: HTMLElement | null): void => {
|
|
203
|
-
|
|
204
|
-
refElem.appendChild(elem);
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Preact calls `ref` with `null` when this specific VNode is
|
|
209
|
-
// detached -- either superseded by a different element at the
|
|
210
|
-
// same position (a later replaceWith/appendChild/prependChild
|
|
211
|
-
// call) or because the Slot unmounted entirely. Either way,
|
|
212
|
-
// `elem` is no longer part of the tree, so drop it from the
|
|
213
|
-
// cache now instead of holding onto it (and the DOM node it
|
|
214
|
-
// wraps) for the Slot's remaining lifetime.
|
|
215
|
-
htmlElementVNodeCache.delete(elem);
|
|
167
|
+
refElem?.appendChild(elem);
|
|
216
168
|
},
|
|
217
169
|
},
|
|
218
170
|
null,
|
|
219
171
|
);
|
|
220
|
-
|
|
221
|
-
htmlElementVNodeCache.set(elem, vnode);
|
|
222
|
-
return vnode;
|
|
223
172
|
},
|
|
224
|
-
[contentTag
|
|
173
|
+
[contentTag],
|
|
225
174
|
);
|
|
226
175
|
|
|
227
176
|
// @ts-ignore
|
|
@@ -388,8 +337,6 @@ export function useSlot<K, V extends HTMLElement>(
|
|
|
388
337
|
status.current = 'ready';
|
|
389
338
|
}, [children, context, name, props, render, state]);
|
|
390
339
|
|
|
391
|
-
handleLifeCycleRenderRef.current = handleLifeCycleRender;
|
|
392
|
-
|
|
393
340
|
// Initialization
|
|
394
341
|
const handleLifeCycleInit = useCallback(async () => {
|
|
395
342
|
if (!callback) return;
|