Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Next.js hydration issue #80

Closed
4 tasks done
nguyenvukhang opened this issue Dec 22, 2022 · 13 comments
Closed
4 tasks done

Next.js hydration issue #80

nguyenvukhang opened this issue Dec 22, 2022 · 13 comments
Labels
👀 no/external This makes more sense somewhere else 👎 phase/no Post cannot or will not be acted on

Comments

@nguyenvukhang
Copy link

nguyenvukhang commented Dec 22, 2022

Initial checklist

Affected packages and versions

remark-math, rehype-mathjax, all latest versions

Link to runnable example

No response

Steps to reproduce

yarn create next-app
yarn add @next/mdx @mdx-js/loader @mdx-js/react remark-math rehype-mathjax

create a next.config.mjs with the contents:

import mdx from "@next/mdx";
import remarkMath from "remark-math";
import rehypeMathJax from "rehype-mathjax";

const withMDX = mdx({
  extension: /\.mdx?$/,
  options: {
    remarkPlugins: [remarkMath],
    rehypePlugins: [rehypeMathJax],
  },
});

export default withMDX({
  reactStrictMode: true,
  pageExtensions: ["tsx", "jsx", "mdx"],
});

Expected behavior

Should render without errors.

Actual behavior

Renders correctly, but with the error
Error: Text content does not match server-rendered HTML.

Runtime

Node v16

Package manager

yarn 1

OS

macOS

Build and bundle tools

Next.js (bug is seen on both v13 and v12)

@github-actions github-actions bot added 👋 phase/new Post is being triaged automatically 🤞 phase/open Post is being triaged manually and removed 👋 phase/new Post is being triaged automatically labels Dec 22, 2022
@nguyenvukhang nguyenvukhang changed the title Next JS 13 hydration issue Next.js hydration issue Dec 22, 2022
@nguyenvukhang
Copy link
Author

nguyenvukhang commented Dec 22, 2022

This error disappears when commenting out lines 113-115 in https://github.com/remarkjs/remark-math/blob/7e82f934e77d62b7366825633bc7f1d5d5e5a861/packages/rehype-mathjax/lib/create-plugin.js

      if (found && renderer.styleSheet) {
        context.children.push(renderer.styleSheet())
      }

Though it's still unclear where the root cause is

@wooorm
Copy link
Member

wooorm commented Dec 22, 2022

well, the root cause is that there is different handling on the server (JSDOM) and a browser (depending on which one your users use). Not sure it can be change,d but feel free to investigate it.

@hkhanna

This comment was marked as resolved.

@wooorm

This comment was marked as resolved.

@hkhanna

This comment was marked as resolved.

@wooorm

This comment was marked as resolved.

dylanhu7 added a commit to dylanhu7/remark-math that referenced this issue Feb 10, 2023
@fullykubed
Copy link

Can confirm this issue still exists with Next.js 14

@fullykubed

This comment was marked as resolved.

@sweetim

This comment was marked as spam.

@wooorm
Copy link
Member

wooorm commented Sep 20, 2024

This is a problem with Next or React, as it can be reproduced without all these packages, with a reasonable example.
Replacing page.tsx, or a similar Next app page, with:

export default function Home() {
  return (
    <div>
      <main>
        <style>[title="a"] &#x7b; color: violet &#x7d;</style>
        <div title="a">Hi!</div>
      </main>
    </div>
  );
}

While this works (the div becomes violet), it yields the react warning:

Warning: Text content did not match. Server: "a[b=&quot;c&quot;] { color: red }" Client: "a[b="c"] { color: red }"
    at style
    at main
    at div
    at Home (Server)

And then the Next error:

Uncaught Error: Text content does not match server-rendered HTML.
See more info here: https://nextjs.org/docs/messages/react-hydration-error

Please raise this with Next/React. Thanks

@wooorm wooorm closed this as not planned Won't fix, can't repro, duplicate, stale Sep 20, 2024

This comment has been minimized.

@wooorm wooorm added the 👀 no/external This makes more sense somewhere else label Sep 20, 2024
@github-actions github-actions bot added 👎 phase/no Post cannot or will not be acted on and removed 🤞 phase/open Post is being triaged manually labels Sep 20, 2024
@alexharri
Copy link

For anyone else encountering this, I'm working around the issue like so:

import { SerializeOptions } from "next-mdx-remote/dist/types";

async function rehypeMathjax() {
  const plugin = (await import("rehype-mathjax/svg")).default({ svg: { scale: 1 } });
  return () => (tree: import("hast").Root) => {
    plugin(tree);

    // If the last added child in the tree is a stylesheet containing 'mjx-container',
    // remove it. It causes Next.js hydration errors.
    //
    // Workaround for https://github.com/remarkjs/remark-math/issues/80.
    const lastChild = tree.children[tree.children.length - 1];
    if (lastChild.type === "element" && lastChild.tagName === "style") {
      const content = lastChild.children[0];

      // Make sure that this is a Mathjax related stylesheet before removing it.
      const isMathjaxStylesheet =
        content.type === "text" && content.value.includes("mjx-container");
      if (isMathjaxStylesheet) {
        tree.children.pop(); // Remove!
      }
    }
  };
}

export const getMdxOptions = async (): Promise<SerializeOptions["mdxOptions"]> => ({
  remarkPlugins: [(await import("remark-math")).default],
  rehypePlugins: [await rehypeMathjax()],
});

On the library side, it would be nice if it was possible to disable the stylesheet injection via an option like injectStylesheet: false.

@wooorm
Copy link
Member

wooorm commented Oct 6, 2024

Please see my comment before yours. It would be nice if you raise this in the correct place? Which I believe to be next, so that it can be solved. Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
👀 no/external This makes more sense somewhere else 👎 phase/no Post cannot or will not be acted on
Development

No branches or pull requests

6 participants