xmlhttprequestrolluppolyfillsreact-pdfreact-pdfrenderer

@react-pdf/renderer can't use fonts when building for node


I am trying to build an app that uses react-pdf/renderer. I will send a pdf response from node js express server. The fonts I use in react-pdf/renderer (.ttf) seems like are fetched via XMLHttpRequest (inside the library). In the final build I can see that it uses XMLHttpRequest. When I try to execute this in node js it crashes because of that, it does not exist. How I can convert it into node-fetch or something else to make it work? Do I need to polyfill that? And how? I use rollup

The fonts are registered with the standard way Font.register() with external url

ts config:

{
    "compilerOptions": {
    "baseUrl": "src/",
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "moduleResolution": "Bundler",
    "allowImportingTsExtensions": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": true,
    "jsx": "react-jsx",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedSideEffectImports": true
  },
  "include": ["src"]
}

rollup base config:

import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import typescript from "@rollup/plugin-typescript";
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
import { babel } from '@rollup/plugin-babel';
import json from '@rollup/plugin-json';

export default {
  plugins: [
    peerDepsExternal(),
    resolve({
      browser: true,
      preferBuiltins: false,
    }),
    // resolve(),
    commonjs(),
    babel({
      babelHelpers: 'bundled',
      exclude: /node_modules/,
      presets: ["@babel/preset-react", "@babel/preset-typescript"],
    }),
    typescript({
      tsconfig: "./tsconfig.json",
      outputToFilesystem: true,
    }),
    json(),
  ],
};

rollup config:

import terser from '@rollup/plugin-terser';
import baseConfig from './rollup.base.config.js';

export default [
  {
    input: 'src/index.ts',
    output: [
      {
        file: 'dist/module.js',
        format: 'cjs',
        sourcemap: true,
      },
    ],
    external: ['react', 'react-dom'],
    preserveModules: true,
    plugins: [
      ...baseConfig.plugins,
      terser(),
    ],
  },
];

I can build it with "rollup -c".

In node server I just do:

await renderToStream(
    t(data)   // t is something that is imported from the build
  );

It works without the fonts.

How I can fix the XMLHttpRequest problem?


Solution

  • The way I resolved the issue:

    Actually it wasn't a XMLHttpRequest issue.

    It turns out that renderToStream needs those font registrations as well. Registering them only in the build was not enough. If I register the fonts in node server, I can omit the registration in the build.

    The Font that is used in the build is different than the Font that is used in node server.

    If I use PDFViewer to render in browser, then I need to register the fonts there. But If I am making a build for node js that will use renderToStream, then I must register them in node, instead of the build.