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 #85 from WordPress/support-css-in-client-side-tran…
Browse files Browse the repository at this point in the history
…sitions

🎨 Support CSS in client-side transitions
  • Loading branch information
luisherranz authored Oct 19, 2022
2 parents 67fcaed + 59bb46c commit f947cac
Showing 1 changed file with 40 additions and 10 deletions.
50 changes: 40 additions & 10 deletions src/runtime/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { createRootFragment } from './utils';
let rootFragment;

// The cache of visited and prefetched pages.
export const pages = new Map();
const pages = new Map();
const stylesheets = new Map();

// Helper to remove domain and hash from the URL. We are only interesting in
// caching the path and the query.
Expand All @@ -15,11 +16,37 @@ const cleanUrl = (url) => {
return u.pathname + u.search;
};

// Fetch styles of a new page.
const fetchHead = async (head) => {
const sheets = await Promise.all(
[].map.call(head.querySelectorAll("link[rel='stylesheet']"), (link) => {
const href = link.getAttribute('href');
if (!stylesheets.has(href))
stylesheets.set(
href,
fetch(href).then((r) => r.text())
);
return stylesheets.get(href);
})
);
const stylesFromSheets = sheets.map((sheet) => {
const style = document.createElement('style');
style.textContent = sheet;
return style;
});
return [
head.querySelector('title'),
...head.querySelectorAll('style'),
...stylesFromSheets,
];
};

// Fetch a new page and convert it to a static virtual DOM.
const fetchPage = async (url) => {
const html = await window.fetch(url).then((res) => res.text());
const html = await window.fetch(url).then((r) => r.text());
const dom = new window.DOMParser().parseFromString(html, 'text/html');
return toVdom(dom.body);
const head = await fetchHead(dom.head);
return { head, body: toVdom(dom.body) };
};

// Prefetch a page. We store the promise to avoid triggering a second fetch for
Expand All @@ -35,8 +62,9 @@ export const prefetch = (url) => {
export const navigate = async (href) => {
const url = cleanUrl(href);
prefetch(url);
const vdom = await pages.get(url);
render(vdom, rootFragment);
const { body, head } = await pages.get(url);
document.head.replaceChildren(...head);
render(body, rootFragment);
window.history.pushState({ wp: { clientNavigation: true } }, '', href);
};

Expand All @@ -45,8 +73,9 @@ export const navigate = async (href) => {
window.addEventListener('popstate', async () => {
const url = cleanUrl(window.location); // Remove hash.
if (pages.has(url)) {
const vdom = await pages.get(url);
render(vdom, rootFragment);
const { body, head } = await pages.get(url);
document.head.replaceChildren(...head);
render(body, rootFragment);
} else {
window.location.reload();
}
Expand All @@ -59,7 +88,8 @@ export const init = async () => {
// Create the root fragment to hydrate everything.
rootFragment = createRootFragment(document.documentElement, document.body);

const vdom = toVdom(document.body);
pages.set(url, Promise.resolve(vdom));
hydrate(vdom, rootFragment);
const body = toVdom(document.body);
hydrate(body, rootFragment);
const head = await fetchHead(document.head);
pages.set(url, Promise.resolve({ body, head }));
};

0 comments on commit f947cac

Please sign in to comment.