Skip to content

Commit

Permalink
Merge pull request #7 from basementstudio/jb/improve-css-unmounting
Browse files Browse the repository at this point in the history
improve css unmounting
  • Loading branch information
julianbenegas authored Mar 15, 2023
2 parents 2b72b8b + ca809ff commit e4146f9
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 63 deletions.
5 changes: 5 additions & 0 deletions .changeset/odd-poems-relax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@bsmnt/page-transition": patch
---

improve css unmounting
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import * as React from "react";

export const useNextCssRemovalPrevention = (options?: {
disabled?: boolean;
}) => {
React.useEffect(() => {
if (options?.disabled) return;
// Remove data-n-p attribute from all link nodes.
// This prevents Next.js from removing server rendered stylesheets.
document.querySelectorAll("head > link[data-n-p]").forEach((linkNode) => {
linkNode.removeAttribute("data-n-p");
});

const mutationHandler = (mutations: MutationRecord[]) => {
mutations.forEach(({ target, addedNodes }: MutationRecord) => {
if (target.nodeName === "HEAD") {
// Add data-n-href-perm attribute to all style nodes with attribute data-n-href,
// and remove data-n-href and media attributes from those nodes.
// This prevents Next.js from removing or disabling dynamic stylesheets.
addedNodes.forEach((node) => {
const el = node as Element;
if (el.nodeName === "STYLE" && el.hasAttribute("data-n-href")) {
const href = el.getAttribute("data-n-href");
if (href) {
el.setAttribute("data-n-href-perm", href);
el.removeAttribute("data-n-href");
el.removeAttribute("media");
}
}
});

// Remove all stylesheets that we don't need anymore
// (all except the two that were most recently added).
const styleNodes = document.querySelectorAll(
"head > style[data-n-href-perm]"
);
const requiredHrefs = new Set<string>();
for (let i = styleNodes.length - 1; i >= 0; i--) {
const el = styleNodes[i];
if (!el) break;
if (requiredHrefs.size < 2) {
const href = el.getAttribute("data-n-href-perm");
if (href) {
if (requiredHrefs.has(href)) {
el.parentNode!.removeChild(el);
} else {
requiredHrefs.add(href);
}
}
} else {
el.parentNode!.removeChild(el);
}
}
}
});
};

// Observe changes to the head element and its descendents.
const observer = new MutationObserver(mutationHandler);
observer.observe(document.head, { childList: true, subtree: true });

return () => {
// Disconnect the observer when the component unmounts.
observer.disconnect();
};
}, [options?.disabled]);
};
11 changes: 3 additions & 8 deletions packages/page-transition/src/provider.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as React from "react";
import type { NextRouter } from "next/router";

import { savePageStyles } from "./save-page-styles";
import { useIsoLayoutEffect } from "./hooks/use-iso-layout-effect";
import { useNextCssRemovalPrevention } from "./hooks/use-next-css-removal-prevention";

type TransitionCallback = (newPathname: string) => Promise<void | (() => void)>;
type TransitionOptions = { kill?: boolean };
Expand Down Expand Up @@ -121,13 +121,8 @@ const TransitionLayout = React.memo(
oldPathnameRef.current = window.location.pathname;
}, []);

// if unsafeCssPreservation is present, we make the next.js hack to save the page's styles
// see https://github.com/vercel/next.js/issues/17464
React.useEffect(() => {
if (status === "idle" && unsafeCssPreservation) {
savePageStyles();
}
}, [unsafeCssPreservation, status]);
// credits https://github.com/vercel/next.js/issues/17464#issuecomment-1447335147
useNextCssRemovalPrevention({ disabled: !unsafeCssPreservation });

React.useEffect(() => {
if (!nextRouter) return;
Expand Down
55 changes: 0 additions & 55 deletions packages/page-transition/src/save-page-styles.ts

This file was deleted.

0 comments on commit e4146f9

Please sign in to comment.