react-pdf icon indicating copy to clipboard operation
react-pdf copied to clipboard

compat with react 19

Open joacub opened this issue 1 year ago • 22 comments

React pdf is not compatible with react 19, will you make the library compat with this version ?

joacub avatar May 19 '24 00:05 joacub

👀

joacub avatar May 23 '24 06:05 joacub

Anything @eps1lon you can suggest? I have been poking around in the react-reconciler but it has drifted and largely undocumented.

ZipBrandon avatar May 30 '24 14:05 ZipBrandon

react-three-fiber also had to update its reconciler implementation. One of the breaking changes that was hard to track down was around commitUpdate which is no longer called with an updatePayload.

Where is the code for the reconciler implementation? Maybe something stands out to me. But no promises for now since we're not using that library at Vercel.

eps1lon avatar May 30 '24 15:05 eps1lon

@eps1lon Here is where @diegomura creates the reconciler. When I updated the deps on my fork, I couldn't get the document to be created from the updateContainer call here

ZipBrandon avatar May 30 '24 20:05 ZipBrandon

Some advances ?

joacub avatar Jun 03 '24 04:06 joacub

FWIW I have patched my version to use React 18. I only use the node version of the renderer so having a version of [email protected] that is only used for that suits my purpose.

I'm aliasing react-18 with "react-18": "npm:react@^18.3.1" in my package.json.

This uses a patch I made with patch-package where the renderer code thenimport React from "react-18".

I had to use the escape hatch of "use no memo" in my components to opt-out the compiler.

I use the pragma /** @jsxImportSource react-18 */ at the top of all files that are associated with the PDF rendering so it goes through the correct createElement().

That being said, this is just duct tape to get by until we have true React 19 compatability.

ZipBrandon avatar Jun 04 '24 00:06 ZipBrandon

That's a very interesting aproach @ZipBrandon but I feel like vercel and react will need to come up with a better solution than this since any 3rd party lib you might be using that is not updated will simply prevent you from upgrading to next 15 and react 19.

What is the suggested path here @eps1lon ? I've spent the time migrating to next 15, loved the wait everything felt until one of our agents told me the pdf generation page was buggered so had to revert to latest stable next

cipriancaba avatar Jun 04 '24 06:06 cipriancaba

Hi @ZipBrandon , do you mind sharing the patch you used to make this work?

cipriancaba avatar Jun 05 '24 06:06 cipriancaba

I don't see what else we can do. This is just inherent to breaking changes in a library.

What is the suggested path here @eps1lon ?

The suggested path for libraries to ensure compatibility during the alpha period which we announced on the 25th of April. But we also encourage libraries to ensure continuous compatibility by regularly testing Canary.

But we also spent resources at Vercel to ensure the libraries are compatible we use:

  • https://github.com/uiwjs/react-codemirror/pull/655
  • https://github.com/recharts/recharts/pull/4542
  • https://github.com/timlrx/contentlayer2/pull/19
  • https://github.com/tailwindlabs/headlessui/pull/3254
  • https://github.com/resend/react-email/pull/1463
  • https://github.com/vercel/styled-jsx/pull/846
  • https://github.com/resend/react-email/pull/1462
  • https://github.com/pmndrs/react-three-fiber/pull/3256
  • https://github.com/testing-library/react-testing-library/pull/1294

or helped these libraries when upgrading:

  • https://github.com/radix-ui/primitives/pull/2934
  • https://github.com/tailwindlabs/headlessui/pull/3253
  • https://github.com/pmndrs/react-three-fiber/pull/3224#issuecomment-2077317026

This is a community effort though so we need all the help we can get

eps1lon avatar Jun 05 '24 08:06 eps1lon

Thanks for the reply @eps1lon and your efforts are obviously much appreciated

I've been tracking your issue here https://github.com/eps1lon/react/issues/10

I guess when I meant suggested path I meant more like this is literally a blocker for any kind of upgrade to react 19 / next 15. Is there potential for a more generic temporary fix (maybe similar to what @ZipBrandon suggested) until react 19 is fully adopted by lib authors? In every real life project there's this obscure library that you absolutely have to use and then if that blocks your entire upgrade path, you're basically stuck.

cipriancaba avatar Jun 05 '24 09:06 cipriancaba

@cipriancaba Sure! Here's the the gist of the patch for @react-pdf/renderer https://gist.github.com/ZipBrandon/b6c3848a400feff9741d739b7544d4fe. This is only for rendering on the Node side. I didn't do anything for browser rendering.

Caveats to remember:

  • "react-18": "npm:react@^18.3.1", in your package.json deps.
  • /** @jsxImportSource react-18 */ at the top of any of your files that are React components that are being rendered in the PDF. You should not have React 19 and React 18 components in the same file.
  • Import anything you need in those components from React from "react-18" package.
  • If using the React Compiler, opt-out in the PDF components with "use no memo"

ZipBrandon avatar Jun 05 '24 17:06 ZipBrandon

I've done some investigations and the library is incompatible with react-reconciler 0.27.0 and later (React 19 requires ^0.31.0).

The library expect reconciler.createContainer to mutate the document property of the container.

https://github.com/diegomura/react-pdf/blob/f64f3bd26c9ac1cdb0d894d4621cf2f985c8a64b/packages/renderer/src/index.js#L26-L28

which is then accessed here

https://github.com/diegomura/react-pdf/blob/f64f3bd26c9ac1cdb0d894d4621cf2f985c8a64b/packages/renderer/src/index.js#L37-L38

In 0.27.0 the container.document is always null

I've tried finding workarounds, but I'm not familiar with the internals of the reconciler. @eps1lon thankful for any pointers!

Edit:

~Seems like newer version of the reconciler forces the container to be immutable, or that it clones the object passed into createContainer. The mutation part is done in appendChildToContainer~

https://github.com/diegomura/react-pdf/blob/f64f3bd26c9ac1cdb0d894d4621cf2f985c8a64b/packages/renderer/src/renderer.js#L103-L109

Edit 2:

Okay so looks like updateContainer now schedules an update instead of doing it sync. And library code relies on the sync behavior.

  const updateContainer = (doc, callback) => {
    renderer.updateContainer(doc, mountNode, null, callback);
  };

  if (initialValue) updateContainer(initialValue);

  setTimeout(() => {
    console.log(container);
	// container.document is set now
  }, 0);

alexandernanberg avatar Jun 12 '24 12:06 alexandernanberg

Got it working in #2783.

If you want to try it out early you can:

  1. Install @alexandernanberg/react-pdf-renderer
  2. Replace all references of @react-pdf/renderer with alexandernanberg/react-pdf-renderer

alexandernanberg avatar Jun 12 '24 14:06 alexandernanberg

@alexandernanberg thanks for this!

Tried @alexandernanberg/react-pdf-renderer out just now and it works in some circumstances!

However, it is hanging with our Express app which uses:

  • custom fonts (this seems to be the problem)
    • Font.register() with src set to an https:// URL of a WOFF font
    • StyleSheet.create() with fontFamily set to a custom font which uses Font.register()
  • (await renderToStream()).pipe(response)

We do also have this pragma, not sure if that's relevant:

/** @jsxRuntime automatic @jsxImportSource react */

karlhorky avatar Jun 12 '24 18:06 karlhorky

@karlhorky Custom fonts and stylesheets work for me, although I'm using Next.js.

I suspect that I broke something in this commit ed62fa6 (#2783). I'll see if I can revert those changes

alexandernanberg avatar Jun 13 '24 06:06 alexandernanberg

Custom fonts and stylesheets work for me

Interesting, are you also using the same configuration?

  • Font.register() with src of:
    • https:// URL
    • WOFF font
  • StyleSheet.create() with fontFamily

If you could post an example of your code, then that would be helpful to track down working / not working configurations.

I'll see if I can revert those changes

Thanks!

karlhorky avatar Jun 13 '24 07:06 karlhorky

Only .ttf fonts are supported AFAIK https://react-pdf.org/fonts

Example
import {
  Document,
  Font,
  Page,
  StyleSheet,
  View,
  renderToStream,
} from "@alexandernanberg/react-pdf-renderer";

const fontFamily = {
  sans: "Inter",
};

Font.register({
  family: fontFamily.sans,
  fonts: [
    {
      src: "https://storage.googleapis.com/.../fonts/Inter-Regular.ttf",
      fontWeight: "normal",
    },
  ],
});

export function renderCertificate() {
  return renderToStream(<Certificate />);
}

export function Certificate() {
  return (
    <Document>
      <Page style={styles.page}>
        <View style={styles.container}></View>
      </Page>
    </Document>
  );
}

const styles = StyleSheet.create({
  text: {
    fontFamily: fontFamily.sans,
    fontWeight: "normal",
    fontSize: 14,
  },
});

alexandernanberg avatar Jun 13 '24 08:06 alexandernanberg

Only .ttf fonts are supported AFAIK

WOFF fonts are also supported, this is just undocumented. I've opened a PR to document that here:

  • https://github.com/diegomura/react-pdf-site/pull/133

karlhorky avatar Jun 13 '24 08:06 karlhorky

Interesting, WOFF is not the problem after all, this .woff font works from Google Fonts (Inter font):

Font.register({
  family: 'Inter',
  format: 'woff',
  src: 'https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuGKYAZ9hjp-Ek-_EeA.woff',
});

All fonts on Google Fonts seem to work.

It seems to be a problem with my own font files (both TTF and WOFF) being unusable in some way. Maybe something in some dependency is being more strict with certain font files.

karlhorky avatar Jun 13 '24 09:06 karlhorky

Ohh looks like this hanging behavior is a known problem with custom fonts and react-pdf and fontkit (caused by the transitive dependency [email protected]):

  • https://github.com/diegomura/react-pdf/issues/2675
  • https://github.com/foliojs/fontkit/issues/331

Downgrading to [email protected] as mentioned in the issues above resolves the issue.


Thus, I can confirm that @alexandernanberg/[email protected] is working with React 19. 🙌 🎉

karlhorky avatar Jun 13 '24 10:06 karlhorky

I'm using it now too! Thanks so much @alexandernanberg!

ZipBrandon avatar Jun 13 '24 13:06 ZipBrandon

Hello,

while trying with @alexandernanberg/react-pdf-renderer package, I can't get the PDF rendering to work, I still get the following error:

⨯ ..\node_modules\react-reconciler\cjs\react-reconciler.development.js (15700:59) @ module.exports
⨯ TypeError: Cannot read properties of undefined (reading 'S')
    at Results (./app/(frontend)/results/page.tsx:41:107)
digest: "3784830825"
  15698 |         _currentRenderer2: null
  15699 |       },
> 15700 |       prevOnStartTransitionFinish = ReactSharedInternals.S;
        |                                                           ^
  15701 |     ReactSharedInternals.S = function (transition, returnValue) {
  15702 |       "object" === typeof returnValue &&
  15703 |         null !== returnValue &&

Is it maybe because there was an update of the beta version of react 19?

timothylp avatar Jul 24 '24 13:07 timothylp

@alexandernanberg can you fix this bugs in your forked repo? https://github.com/diegomura/react-pdf/pull/2878/files

mamlzy avatar Oct 23 '24 02:10 mamlzy

I've rebased on main and released a new 4.0.0-canary-3 version of @alexandernanberg/react-pdf-renderer. Haven't had time to test much yet so let me know if it's working as expected

alexandernanberg avatar Oct 23 '24 07:10 alexandernanberg

Thank you @alexandernanberg , for responding to my request. Now i go back to Next.js 14, which uses React 18. There is so much unsupported libraries in react 19, and your forked repo probably only work on react 18 right?, maybe I'll try it later on Next.js 15!

mamlzy avatar Oct 23 '24 07:10 mamlzy

@mamlzy I think there are a few misconceptions here:

karlhorky avatar Oct 23 '24 09:10 karlhorky

@karlhorky i'm using next 15 app router not pages router so it will uses react 19, am i correct?

mamlzy avatar Oct 23 '24 10:10 mamlzy

Hello,

while trying with @alexandernanberg/react-pdf-renderer package, I can't get the PDF rendering to work, I still get the following error:

⨯ ..\node_modules\react-reconciler\cjs\react-reconciler.development.js (15700:59) @ module.exports
⨯ TypeError: Cannot read properties of undefined (reading 'S')
    at Results (./app/(frontend)/results/page.tsx:41:107)
digest: "3784830825"
  15698 |         _currentRenderer2: null
  15699 |       },
> 15700 |       prevOnStartTransitionFinish = ReactSharedInternals.S;
        |                                                           ^
  15701 |     ReactSharedInternals.S = function (transition, returnValue) {
  15702 |       "object" === typeof returnValue &&
  15703 |         null !== returnValue &&

Is it maybe because there was an update of the beta version of react 19?

Any update on this? I'm still experiencing this on @alexandernanberg/[email protected].

Jussinevavuori avatar Oct 25 '24 03:10 Jussinevavuori

@Jussinevavuori Are you on Next.js 15 and React RC? My guess it's something with multiple or incorrect version of React

alexandernanberg avatar Oct 25 '24 05:10 alexandernanberg

@alexandernanberg My React versions are listed below

"dependencies": {
  "react": "19.0.0-rc-69d4b800-20241021",
  "react-dom": "19.0.0-rc-69d4b800-20241021",
  "next": "15.0.1"
},
"devDependencies": {
  "@types/react": "npm:[email protected]",
  "@types/react-dom": "npm:[email protected]"
}

Jussinevavuori avatar Oct 25 '24 05:10 Jussinevavuori