vitejs / vite

Next generation frontend tooling. It's fast!
http://vite.dev
MIT License
68.65k stars 6.2k forks source link

react-pdf is not compatible without shims #3405

Closed thekevinbrown closed 3 years ago

thekevinbrown commented 3 years ago

Describe the bug

When trying to use React PDF in a Vite React project, we get:

Uncaught ReferenceError: global is not defined
    at node_modules/blob/index.js (index.js:5)
    at __require (chunk-KVFJW2XH.js?v=ce5c473e:12)
    at node_modules/blob-stream/index.js (index.js:3)
    at __require (chunk-KVFJW2XH.js?v=ce5c473e:12)
    at asyncToGenerator.js:32

It's from the blob NPM library, but what's really strange is the code in .vite/@react-pdf_renderer.js on line 554 is:

var BlobBuilder = global.BlobBuilder || global.WebKitBlobBuilder || global.MSBlobBuilder || global.MozBlobBuilder;

But the module definitely does not get packaged with references to global: https://unpkg.com/blob@0.1.0/main.js

We'd like to understand where the global is coming from, then be able to fix and/or work around this so that we can use React PDF in our project.

Also noteworthy is that when we try to use Document, Page, or other exports that the TypeScript types say should be there, we get:

Uncaught SyntaxError: The requested module '/node_modules/.vite/@react-pdf_renderer.js?v=ce5c473e' does not provide an export named 'Document'

It really makes me wonder if we're somehow selecting a server version of React PDF, but I can't see how or where that's happening in the monorepo imports that are going on.

Reproduction

https://github.com/thekevinbrown/vite-react-pdf-reproduction

System Info

Output of npx envinfo --system --npmPackages vite,@vitejs/plugin-vue --binaries --browsers:

  System:
    OS: macOS 11.2.3
    CPU: (8) arm64 Apple M1
    Memory: 541.69 MB / 16.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 15.11.0 - ~/.nvm/versions/node/v15.11.0/bin/node
    Yarn: 1.22.5 - ~/.yarn/bin/yarn
    npm: 7.6.0 - ~/.nvm/versions/node/v15.11.0/bin/npm
  Browsers:
    Brave Browser: 90.1.23.75
    Chrome: 90.0.4430.212
    Firefox: 88.0
    Safari: 14.0.3
  npmPackages:
    vite: ^2.3.0 => 2.3.2 

Used package manager: yarn

Logs

$ vite --debug
  vite:config bundled config file loaded in 33ms +0ms
  vite:config using resolved config: {
  vite:config   plugins: [
  vite:config     'vite:pre-alias',
  vite:config     'alias',
  vite:config     'react-refresh',
  vite:config     'vite:dynamic-import-polyfill',
  vite:config     'vite:resolve',
  vite:config     'vite:html',
  vite:config     'vite:css',
  vite:config     'vite:esbuild',
  vite:config     'vite:json',
  vite:config     'vite:wasm',
  vite:config     'vite:worker',
  vite:config     'vite:asset',
  vite:config     'vite:define',
  vite:config     'vite:css-post',
  vite:config     'vite:client-inject',
  vite:config     'vite:import-analysis'
  vite:config   ],
  vite:config   server: {
  vite:config     fsServe: {
  vite:config       root: '/Users/kevin/development/vite-react-pdf-reproduction',
  vite:config       strict: false
  vite:config     }
  vite:config   },
  vite:config   configFile: '/Users/kevin/development/vite-react-pdf-reproduction/vite.config.ts',
  vite:config   configFileDependencies: [ 'vite.config.ts' ],
  vite:config   inlineConfig: {
  vite:config     root: undefined,
  vite:config     base: undefined,
  vite:config     mode: undefined,
  vite:config     configFile: undefined,
  vite:config     logLevel: undefined,
  vite:config     clearScreen: undefined,
  vite:config     server: { fsServe: [Object] }
  vite:config   },
  vite:config   root: '/Users/kevin/development/vite-react-pdf-reproduction',
  vite:config   base: '/',
  vite:config   resolve: { dedupe: undefined, alias: [ [Object] ] },
  vite:config   publicDir: '/Users/kevin/development/vite-react-pdf-reproduction/public',
  vite:config   cacheDir: '/Users/kevin/development/vite-react-pdf-reproduction/node_modules/.vite',
  vite:config   command: 'serve',
  vite:config   mode: 'development',
  vite:config   isProduction: false,
  vite:config   build: {
  vite:config     target: [ 'es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1' ],
  vite:config     outDir: 'dist',
  vite:config     assetsDir: 'assets',
  vite:config     assetsInlineLimit: 4096,
  vite:config     cssCodeSplit: true,
  vite:config     sourcemap: false,
  vite:config     rollupOptions: {},
  vite:config     commonjsOptions: { include: [Array], extensions: [Array] },
  vite:config     minify: 'terser',
  vite:config     terserOptions: {},
  vite:config     cleanCssOptions: {},
  vite:config     write: true,
  vite:config     emptyOutDir: null,
  vite:config     manifest: false,
  vite:config     lib: false,
  vite:config     ssr: false,
  vite:config     ssrManifest: false,
  vite:config     brotliSize: true,
  vite:config     chunkSizeWarningLimit: 500,
  vite:config     watch: null
  vite:config   },
  vite:config   env: { BASE_URL: '/', MODE: 'development', DEV: true, PROD: false },
  vite:config   assetsInclude: [Function: assetsInclude],
  vite:config   logger: {
  vite:config     hasWarned: false,
  vite:config     info: [Function: info],
  vite:config     warn: [Function: warn],
  vite:config     warnOnce: [Function: warnOnce],
  vite:config     error: [Function: error],
  vite:config     clearScreen: [Function: clearScreen]
  vite:config   },
  vite:config   createResolver: [Function: createResolver],
  vite:config   optimizeDeps: { esbuildOptions: { keepNames: undefined } }
  vite:config } +2ms
  vite:deps Hash is consistent. Skipping. Use --force to override. +0ms

  vite v2.3.2 dev server running at:

  > Local: http://localhost:3000/
  > Network: use `--host` to expose

  ready in 139ms.

  vite:time 1ms   / +0ms
  vite:spa-fallback Rewriting GET / to /index.html +0ms
  vite:time 19ms  /index.html +36ms
  vite:resolve 1ms   /Users/kevin/development/vite-react-pdf-reproduction/node_modules/vite/dist/client/client -> /Users/kevin/development/vite-react-pdf-reproduction/node_modules/vite/dist/client/client.js +0ms
  vite:resolve 2ms   /@vite/client -> /Users/kevin/development/vite-react-pdf-reproduction/node_modules/vite/dist/client/client.js +0ms
  vite:resolve 0ms   /src/main.tsx -> /Users/kevin/development/vite-react-pdf-reproduction/src/main.tsx +2ms
  vite:load 2ms   [fs] /@vite/client +0ms
  vite:resolve 1ms   ./env -> /Users/kevin/development/vite-react-pdf-reproduction/node_modules/vite/dist/client/env.js +9ms
  vite:resolve 0ms   /node_modules/vite/dist/client/env.js -> /Users/kevin/development/vite-react-pdf-reproduction/node_modules/vite/dist/client/env.js +0ms
  vite:transform 7ms   /@vite/client +0ms
  vite:time 14ms  /@vite/client +45ms
  vite:load 10ms  [fs] /src/main.tsx +9ms
  vite:load 0ms   [plugin] /@react-refresh +140ms
  vite:rewrite 1ms   [no imports] /@react-refresh +0ms
  vite:transform 1ms   /@react-refresh +141ms
  vite:time 1ms   /@react-refresh +141ms
  vite:resolve 0ms   react -> /Users/kevin/development/vite-react-pdf-reproduction/node_modules/.vite/react.js?v=ce5c473e&es-interop +146ms
  vite:resolve 0ms   /node_modules/.vite/react.js?v=ce5c473e&es-interop -> /Users/kevin/development/vite-react-pdf-reproduction/node_modules/.vite/react.js?v=ce5c473e&es-interop +0ms
  vite:resolve 0ms   react-dom -> /Users/kevin/development/vite-react-pdf-reproduction/node_modules/.vite/react-dom.js?v=ce5c473e&es-interop +2ms
  vite:resolve 0ms   /node_modules/.vite/react-dom.js?v=ce5c473e&es-interop -> /Users/kevin/development/vite-react-pdf-reproduction/node_modules/.vite/react-dom.js?v=ce5c473e&es-interop +0ms
  vite:resolve 0ms   ./App -> /Users/kevin/development/vite-react-pdf-reproduction/src/App.tsx +0ms
  vite:resolve 0ms   /src/App.tsx -> /Users/kevin/development/vite-react-pdf-reproduction/src/App.tsx +0ms
  vite:resolve 0ms   /node_modules/.vite/react.js?v=ce5c473e -> /Users/kevin/development/vite-react-pdf-reproduction/node_modules/.vite/react.js?v=ce5c473e +0ms
  vite:resolve 0ms   /node_modules/.vite/react-dom.js?v=ce5c473e -> /Users/kevin/development/vite-react-pdf-reproduction/node_modules/.vite/react-dom.js?v=ce5c473e +0ms
  vite:transform 147ms /src/main.tsx +6ms
  vite:time 158ms /src/main.tsx +7ms
  vite:load 0ms   [fs] /node_modules/vite/dist/client/env.js +8ms
  vite:rewrite 0ms   [no imports] node_modules/vite/dist/client/env.js +8ms
  vite:transform 0ms   /node_modules/vite/dist/client/env.js +2ms
  vite:time 1ms   /node_modules/vite/dist/client/env.js +1ms
  vite:load 1ms   [fs] /src/App.tsx +8ms
  vite:resolve 0ms   @react-pdf/renderer -> /Users/kevin/development/vite-react-pdf-reproduction/node_modules/.vite/@react-pdf_renderer.js?v=ce5c473e +16ms
  vite:resolve 0ms   /node_modules/.vite/@react-pdf_renderer.js?v=ce5c473e -> /Users/kevin/development/vite-react-pdf-reproduction/node_modules/.vite/@react-pdf_renderer.js?v=ce5c473e +0ms
  vite:hmr [self-accepts] src/App.tsx +0ms
  vite:transform 8ms   /src/App.tsx +15ms
  vite:time 10ms  /src/App.tsx +16ms
  vite:time 2ms   /src/favicon.svg +163ms
  vite:spa-fallback Rewriting GET / to /index.html +7s
  vite:time 4ms   /index.html +6s
  vite:cache [304] /@vite/client +0ms
  vite:time 2ms   /@vite/client +38ms
  vite:cache [304] /src/main.tsx +1ms
  vite:time 1ms   /src/main.tsx +2ms
  vite:cache [304] /@react-refresh +15ms
  vite:time 0ms   /@react-refresh +14ms
  vite:cache [304] /node_modules/vite/dist/client/env.js +2ms
  vite:time 1ms   /node_modules/vite/dist/client/env.js +2ms
  vite:cache [304] /src/App.tsx +3ms
  vite:time 1ms   /src/App.tsx +3ms
  vite:time 1ms   /src/favicon.svg +161ms

Before submitting the issue, please make sure you do the following

Niputi commented 3 years ago

could you try following this comment https://github.com/vitejs/vite/issues/2618#issuecomment-820919951

thekevinbrown commented 3 years ago

@Niputi when I do that, I then get none of the expected exports from the library, e.g.

Uncaught SyntaxError: The requested module '/node_modules/.vite/@react-pdf_renderer.js?v=ce5c473e' does not provide an export named 'PDFRenderer'

or what I'm actually after:

Uncaught SyntaxError: The requested module '/node_modules/.vite/@react-pdf_renderer.js?v=ce5c473e' does not provide an export named 'Document'
Niputi commented 3 years ago

It looks like the file 'react-pdf.browser.es.js' does not provide a export for 'Document'.

I tried using the plugin-cdn by following this guide with the following config

cdn('skypack', {
  '@react-pdf/renderer': '^2.0.12'
})

by doing this I got this error message

Uncaught SyntaxError: The requested module '/-/restructure@v0.5.4-1x0iZnKm3JkZFlHtuxoO/dist=es2020,mode=imports/unoptimized/src/utils.js' does not provide an export named 'PropertyDescriptor'

It seems like esm version of @react-pdf_renderer is broken by including node specific code and not including all necessary exports. you should make a bug report the library

nihalgonsalves commented 3 years ago

Looks like it isn't compatible with Webpack 5 either: https://github.com/diegomura/react-pdf/issues/1029

Another issue, as @Niputi pointed out, seems to be that the export * from '@react-pdf/primitives' does not seem to be preserved in react-pdf's es bundle: https://github.com/diegomura/react-pdf/blob/235dc0a/packages/renderer/src/dom.js#L171

Combining the shims from the linked issue, a shim for EventEmitter, and using the default export, I was able to get it to work:

nihalgonsalves commented 3 years ago

Closing this since it isn't something Vite can fix.

thekevinbrown commented 3 years ago

That is amazing, thank you so much for your help!

thekevinbrown commented 3 years ago

Ok, I'm incredibly stuck. This workaround works fine in dev but not in production. This is because the script in index.html gets pulled into the index bundle, but the shims are required for vendor. Vendor is preloaded, so it loads before the shims.

Here's what I've tried:

Does anyone know how I can get these shims injected at the top of the vendor bundle, referencing the correct browserify packages?

Edit: I also tried:

export default function inject() {
  return {
    name: "inject-react-pdf-shims",
    enforce: "pre",

    transform(code, id) {
      if (/@react-pdf_renderer/.test(id)) {
        return {
          code: `
import process from "process";
import { Buffer } from "buffer";
import EventEmitter from "events";

window.global = window;
window.Buffer = Buffer;
window.process = process;
window.EventEmitter = EventEmitter;
${code}
`,
        };
      }
    },
  };
}

but no dice either:

Uncaught SyntaxError: The requested module '/node_modules/buffer/index.js?v=08612583' does not provide an export named 'Buffer'

It's CJS, so I don't know how to import it there.

thekevinbrown commented 3 years ago

Alrighty, finally found a set of shims and workarounds that make it work, both in Vite Dev and Production builds.

So, if you're coming here from Google, you do the following in your Vite project:

$ yarn add --dev vite-plugin-shim-react-pdf

Then in vite.config.js:

import { defineConfig } from "vite";
import reactRefresh from "@vitejs/plugin-react-refresh";
import shimReactPdf from "vite-plugin-shim-react-pdf";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [reactRefresh(), shimReactPdf()],
});

The you'll also need to use the default import because of the missing exports. E.g.

Instead of:

import { Text, View, StyleSheet } from "@react-pdf/renderer";

You have to do:

import pdf from "@react-pdf/renderer";
const { Text, View, StyleSheet } = pdf;

React PDF also didn't have a development project you could use to test changes, so I made a really rough one out of the examples: https://github.com/TechInSite/react-pdf-development-harness

Cslove commented 3 years ago

@thekevinbrown thank you so much!! meet same problem. and your vite plugin solved my issue! by the way, it should yarn add vite-plugin-shim-react-pdf -D, thanks again!

thekevinbrown commented 3 years ago

Thanks @Cslove, you're right. I updated the instructions above to add --dev to the command

github-actions[bot] commented 3 years ago

This issue has been locked since it has been closed for more than 14 days.

If you have found a concrete bug or regression related to it, please open a new bug report with a reproduction against the latest Vite version. If you have any other comments you should join the chat at Vite Land or create a new discussion.