alien-dom
Version:
Next-generation JSX client renderer with observable data primitives, immediate DOM references, and more.
77 lines (74 loc) • 2.58 kB
JavaScript
import { definePrivateSymbol, setComponentRenderHook, hasPrivate, getPrivate, kAlienRenderFunc, setPrivate, isArray, isFunction, ref, depsHaveChanged, attachRef } from './chunk-UI5LBDJV.mjs';
// hmr.ts
var kAlienComponentKey = definePrivateSymbol("componentKey");
var componentRegistry = {};
var usedBeforeRegister = /* @__PURE__ */ new WeakSet();
function hmrRegister(key, tag, hash, deps) {
if (usedBeforeRegister.has(tag)) {
const name = tag.displayName || tag.name || "<anonymous>";
return console.error(
`[HMR] Component "${name}" cannot be immediately used within the same module it was defined in. Either use "queueMicrotask" or import the component from another module.`
);
}
let [renderRef, oldHash, oldDeps] = componentRegistry[key] || [];
const needsUpdateCheck = renderRef != null;
renderRef ||= ref(tag);
const componentData = [renderRef, hash, deps];
queueMicrotask(() => {
componentData[2] = deps = deps.map(
(dep) => dep && (getPrivate(dep, kAlienComponentKey) ?? dep)
);
if (needsUpdateCheck) {
const needsHotUpdate = oldHash != null && oldHash !== hash || oldDeps != null && depsHaveChanged(deps, oldDeps);
if (needsHotUpdate) {
renderRef.value = tag;
}
}
});
setPrivate(tag, kAlienComponentKey, key);
componentRegistry[key] = componentData;
attachRef(tag, kAlienRenderFunc, renderRef);
}
setComponentRenderHook((component) => {
if (!hasPrivate(component.tag, kAlienComponentKey)) {
usedBeforeRegister.add(component.tag);
return component.tag;
}
const render = getPrivate(component.tag, kAlienRenderFunc);
const prevRender = getPrivate(component, kAlienRenderFunc);
let isHotUpdate;
if (render !== prevRender) {
setPrivate(component, kAlienRenderFunc, render);
if (prevRender) {
isHotUpdate = true;
component.memos?.forEach((memo, key, memos) => {
if (memo && memo.constructor.name === "NestedTag")
return;
memos.delete(key);
});
component.hooks.forEach((hook, index, hooks) => {
if (hook?.dispose) {
if (isArray(hook.deps) && !hook.deps.length) {
return;
}
if (isFunction(hook.dispose)) {
hook.dispose({ isHotReload: true });
}
hooks[index] = void 0;
}
});
}
}
return (props) => {
try {
return render(props);
} catch (e) {
if (isHotUpdate) {
component.truncate(0);
component.scheduleUpdate();
}
throw e;
}
};
});
export { hmrRegister };