Skip to content
This repository has been archived by the owner on Jul 28, 2023. It is now read-only.

Commit

Permalink
Merge pull request #14 from luisherranz/try/implement-hydration-techn…
Browse files Browse the repository at this point in the history
…iques

Implement different hydration techniques
  • Loading branch information
michalczaplinski authored May 13, 2022
2 parents 56d5c46 + 2e56199 commit 1562088
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 9 deletions.
10 changes: 5 additions & 5 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ Feel free to inspect the code, open issues, submit PRs, ask questions...
- [ ] Avoid bundling unnecessary code (like the Save serializer or lodash) in the Frontend.
- [ ] Pattern to export different code depending on the context (Edit, Save, or Frontend).
- [ ] Bundle Preact (compat) instead of React in the Frontend (up for discussion).
- [ ] Implement different hydration techniques:
- [ ] Load
- [ ] Idle
- [ ] View
- [ ] Media
- [x] Implement different hydration techniques:https://github.com/luisherranz/block-hydration-experiments/pull/14.
- [x] Load
- [x] Idle
- [x] View
- [x] Media
- [ ] Change hydration technique based on block attributes.
- [ ] Experiment ways to not hydrate the entire block, only the "client components".
11 changes: 9 additions & 2 deletions src/gutenberg-packages/frontend.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,19 @@ class GutenbergBlock extends HTMLElement {
setTimeout(() => {
const blockType = this.getAttribute("data-gutenberg-block-type");
const attributes = JSON.parse(
this.getAttribute("data-gutenberg-attributes"),
this.getAttribute("data-gutenberg-attributes")
);
const blockProps = JSON.parse(
this.getAttribute("data-gutenberg-block-props"),
this.getAttribute("data-gutenberg-block-props")
);
const innerBlocks = this.querySelector("template.gutenberg-inner-blocks");
const Comp = blockTypes.get(blockType);
const technique = this.getAttribute("data-gutenberg-hydrate");
const media = this.getAttribute("data-gutenberg-media");
const hydrationOptions = {
technique,
media,
};
hydrate(
<EnvContext.Provider value="frontend">
<Comp
Expand All @@ -47,6 +53,7 @@ class GutenbergBlock extends HTMLElement {
/>
</EnvContext.Provider>,
this,
hydrationOptions
);
});
}
Expand Down
4 changes: 3 additions & 1 deletion src/gutenberg-packages/wordpress-blocks.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { InnerBlocks, useBlockProps } from "@wordpress/block-editor";
import { registerBlockType as gutenbergRegisterBlockType } from "@wordpress/blocks";

const save = (name, Comp) =>
const save =
(name, Comp) =>
({ attributes }) => {
const blockProps = useBlockProps.save();
return (
<gutenberg-interactive-block
data-gutenberg-block-type={name}
data-gutenberg-attributes={JSON.stringify(attributes)}
data-gutenberg-block-props={JSON.stringify(blockProps)}
data-gutenberg-hydrate="idle"
>
<Comp blockProps={blockProps} attributes={attributes}>
<gutenberg-inner-blocks>
Expand Down
46 changes: 45 additions & 1 deletion src/gutenberg-packages/wordpress-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
useEffect as useReactEffect,
useState as useReactState,
} from "@wordpress/element";
export { hydrate } from "react-dom";
import { hydrate as ReactHydrate } from "react-dom";

export const EnvContext = createContext(null);

Expand Down Expand Up @@ -34,3 +34,47 @@ export const useState = (init) =>

export const useEffect = (...args) =>
useBlockEnvironment() !== "save" ? useReactEffect(...args) : noop;

export const hydrate = (container, element, hydrationOptions) => {
const { technique, media } = hydrationOptions || {};
const cb = () => {
ReactHydrate(container, element);
};
switch (technique) {
case "media":
if (media) {
const mql = matchMedia(media);
if (mql.matches) {
cb();
} else {
mql.addEventListener("change", cb, { once: true });
}
}
break;
// Hydrate the element when is visible in the viewport.
// https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
case "view":
const io = new IntersectionObserver((entries) => {
for (const entry of entries) {
if (!entry.isIntersecting) continue;
// As soon as we hydrate, disconnect this IntersectionObserver.
io.disconnect();
cb();
break; // break loop on first match
}
});
io.observe(element.children[0]);
break;
case "idle":
// Safari does not support requestIdleCalback, we use a timeout instead. https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback
if ("requestIdleCallback" in window) {
window.requestIdleCallback(cb);
} else {
setTimeout(cb, 200);
}
break;
// Hydrate this component immediately.
default:
cb();
}
};

0 comments on commit 1562088

Please sign in to comment.