diegomura / react-pdf

šŸ“„ Create PDF files using React
https://react-pdf.org
MIT License
14.94k stars 1.18k forks source link

react-pdf does not work with Vite 5 #2454

Closed nick-heard closed 9 months ago

nick-heard commented 11 months ago

Describe the bug After upgrading to Vite 5.0.4 and adding the vite-plugin-node-polyfills package (currently 0.17.0) I'm getting errors around both the zlib and stream libraries. This crashes the app

@react-pdf_renderer.js:10560 Uncaught TypeError: util2.inherits is not a function
    at node_modules/browserify-zlib/lib/index.js (@react-pdf_renderer.js:10560:11)
    at __require2 (chunk-KUO7MYJO.js?v=df593817:2132:50)
    at node_modules/node-fetch/lib/index.js (@react-pdf_renderer.js:10778:32)
    at __require2 (chunk-KUO7MYJO.js?v=df593817:2132:50)
    at node_modules/cross-fetch/dist/node-ponyfill.js (@react-pdf_renderer.js:11957:21)
    at __require2 (chunk-KUO7MYJO.js?v=df593817:2132:50)
    at node_modules/@react-pdf/font/lib/index.cjs.js (@react-pdf_renderer.js:30206:17)
    at __require2 (chunk-KUO7MYJO.js?v=df593817:2132:50)
    at node_modules/@react-pdf/renderer/lib/react-pdf.cjs.js (@react-pdf_renderer.js:114845:21)
    at __require2 (chunk-KUO7MYJO.js?v=df593817:2132:50)

If I omit the zlib library I can run the app locally but it crashes if I run a compiled build (this time around the stream library)

vendor-CHwzE-2h.js:160 Uncaught TypeError: util$5.inherits is not a function

I cannot omit the stream library because it's required for axios

This looks really similar to this bug https://github.com/vitejs/vite/issues/3405 but that shim library doesn't work with the new version of react-pdf

This is preventing me from updating Vite. If I remove react-pdf everything works as expected

To Reproduce Steps to reproduce the behavior including code snippet (if applies):

  1. Make react project with packages vite 5.0.4, vite-plugin-node-polyfills 0.17.0 &react-pdf` 3.1.14
  2. Import react-pdf somewhere in project
  3. Run local server npx vite

You can make use of react-pdf REPL to share the snippet

Expected behavior App should run, react-pdf should render pdfs

Desktop (please complete the following information):

guilhermecomum commented 10 months ago

Same issue here =\

JoJa1101 commented 10 months ago

Same here, Error still exists.

@react-pdf_renderer.js Uncaught ReferenceError: global is not defined at node_modules/node-fetch/lib/index.js (@react-pdf_renderer.js?v=39489c63:3027:20) at require2 (chunk-GFT2G5UO.js?v=300aa6a6:18:50) at node_modules/cross-fetch/dist/node-ponyfill.js (@react-pdf_renderer.js?v=39489c63:3829:21) at require2 (chunk-GFT2G5UO.js?v=300aa6a6:18:50) at node_modules/@react-pdf/font/lib/index.cjs.js (@react-pdf_renderer.js?v=39489c63:22053:17) at require2 (chunk-GFT2G5UO.js?v=300aa6a6:18:50) at node_modules/@react-pdf/renderer/lib/react-pdf.cjs.js (@react-pdf_renderer.js?v=39489c63:84974:21) at require2 (chunk-GFT2G5UO.js?v=300aa6a6:18:50) at @react-pdf_renderer.js?v=39489c63:89525:16

diegomura commented 10 months ago

I used it with vite in this very same project without issues here

battlebrain commented 8 months ago

@JoJa1101 Were you able to solve that issue?

nick-heard commented 7 months ago

I was finally able to find time to look into this again. While I wasn't able to replicate this issue with the example pdf project I WAS able to get my project to build

First I had to remove this from our vite config

    resolve: {
      mainFields: [],
    },

I believe it was originally added to fix an issue with moment we were seeing. I replaced it with

  resolve: {
      alias: [
        {
          // Allow moment.js to be used as an ESM module
          find: /^moment$/,
          replacement: path.resolve(
            __dirname,
            './node_modules/moment/moment.js'
          ),
        },
      ],
    },

but this will definitely vary with whatever packages are being used

This fixed running the dev server issues (npx vite)

for the build and serve I needed to add the @babel/plugin-transform-react-jsx package and add it to the vite config

react({
        babel: {
          plugins: [
            ['@babel/plugin-transform-react-jsx', { runtime: 'automatic' }],
          ],
        },
      }),

Our final vite config looks like this

import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'
import viteTsconfigPaths from 'vite-tsconfig-paths'
import macrosPlugin from 'vite-plugin-babel-macros'
import EnvironmentPlugin from 'vite-plugin-environment'
import { sentryVitePlugin } from '@sentry/vite-plugin'
import path from 'path'
import { nodePolyfills } from 'vite-plugin-node-polyfills'

// Replaces all instances of `<%= key %>` with `value` in index.html file
const transformHtmlPlugin = (data: Record<string, string>) => ({
  name: 'transform-html',
  transformIndexHtml: {
    order: 'pre',
    handler: (html: string) =>
      html.replace(/<%=\s*(\w+)\s*%>/gi, (match, p1) => data[p1] || ''),
  },
})

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd())

  const isStagingOrProd = Boolean(
    env.VITE_ENV && ['staging', 'production'].includes(env.VITE_ENV)
  )

  return {
    plugins: [
      react({
        babel: {
          plugins: [
            ['@babel/plugin-transform-react-jsx', { runtime: 'automatic' }],
          ],
        },
      }),
      transformHtmlPlugin({ VITE_ENV: env.VITE_ENV }),
      viteTsconfigPaths(),
      macrosPlugin(),
      EnvironmentPlugin('all'),
      sentryVitePlugin({
         // private configs go here
      }),
      nodePolyfills({}),
    ],
    build: {
      outDir: 'build',
      sourcemap: false,
      rollupOptions: {
        maxParallelFileOps: 2,
        output: {
          sourcemap: false,
          manualChunks: (id) => {
            if (id.includes('node_modules')) {
              return 'vendor'
            }
          },
        },
      },
    },
    server: {
      port: 3000,
      host: true,
    },
    resolve: {
      alias: [
        {
          // Allow moment.js to be used as an ESM module
          find: /^moment$/,
          replacement: path.resolve(
            __dirname,
            './node_modules/moment/moment.js'
          ),
        },
      ],
    },
    optimizeDeps: {
      esbuildOptions: {
        // Node.js global to browser globalThis
        define: {
          global: 'globalThis',
        },
      },
    },
  }
})
bkaneb commented 2 months ago

Here is a functional example : https://stackblitz.com/edit/vite-react-ts-zbwjtr?file=src%2FApp.tsx