diegomura / react-pdf

📄 Create PDF files using React
https://react-pdf.org
MIT License
14.72k stars 1.17k forks source link

NextJS + Chakra: inconsistently rendering imports & components or error 'is a web specific API' #1815

Open BaoPham92 opened 2 years ago

BaoPham92 commented 2 years ago

Description

I am running into issues rendering components stable and consistent the majority of the times without the error that would appear for a chakra-ui & NextJS build:

Error

Error: <LibraryComponent> is a web specific API. You're either using this component on Node, or your bundler is not loading react-pdf from the appropriate web build.

I followed the initial instructions exactly for webpack, only with slight variation due to NextJS's next.config.js file having built in webpack below:

const wp = require("webpack");

// @ts-check
/**
 * @type {import('next/dist/server/config').NextConfig}
 **/

// @ts-ignore

module.exports = {
  webpack: (config, options) => {
    config.resolve.fallback = {
      process: require.resolve("process/browser"),
      zlib: require.resolve("browserify-zlib"),
      stream: require.resolve("stream-browserify"),
      util: require.resolve("util"),
      buffer: require.resolve("buffer"),
      asset: require.resolve("assert"),
    };

    const setProvidePlugin = async () =>
      new wp.ProvidePlugin({
        Buffer: ["buffer", "Buffer"],
        process: "process/browser",
      });

    // * THIS METHOD SHOWS INSTANTIATED OBJ AFTER NEXT INSTANTIATES THEIR OBJS
    setProvidePlugin().then(
      (res) => (config.plugins = [...config.plugins, res])
    );

    return config;
  },
};

I initially did use the provided code:

new webpack.ProvidePlugin({
  Buffer: ["buffer", "Buffer"],
  process: "process/browser",
}),

as

config.plugins.push[
 new webpack.ProvidePlugin({
   Buffer: ["buffer", "Buffer"],
   process: "process/browser",
 })
]

but that at times did gave me at the start of running yarn dev issues with nextJS being able to compile the fallback manifest json.

here is the NextJS + Chakra _app.tsx:

import { ChakraProvider } from "@chakra-ui/react";
import { PDFViewer, PDFDownloadLink } from "@react-pdf/renderer";
import { AppProps } from "next/app";
import React from "react";
import "../../styles/general.css";
import theme from "../../styles/theme";

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <ChakraProvider resetCSS={true} theme={theme}>
      <PDFViewer>
        <Component {...pageProps} />
      </PDFViewer>
    </ChakraProvider>
  );
}

export default MyApp;

but if I changed the current return this weird setup, I'm able to render the some sub components of the library like Document or Text below:

  return (
    <ChakraProvider resetCSS={true} theme={theme}>
        {PDFViewer}
        <Component {...pageProps} />
    </ChakraProvider>
  );

Steps to reproduce

Base App with Chakra for NextJS:

import { ChakraProvider } from "@chakra-ui/react";
import { PDFViewer } from "@react-pdf/renderer";
import { AppProps } from "next/app";
import React from "react";
import "../../styles/general.css";
import theme from "../../styles/theme";

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <ChakraProvider resetCSS={true} theme={theme}>
      <PDFViewer>
        <Component {...pageProps} />
      </PDFViewer>
    </ChakraProvider>
  );
}

export default MyApp;

NextJS webpack config:

const wp = require("webpack");

// @ts-check
/**
 * @type {import('next/dist/server/config').NextConfig}
 **/

// @ts-ignore

module.exports = {
  webpack: (config, options) => {
    config.resolve.fallback = {
      process: require.resolve("process/browser"),
      zlib: require.resolve("browserify-zlib"),
      stream: require.resolve("stream-browserify"),
      util: require.resolve("util"),
      buffer: require.resolve("buffer"),
      asset: require.resolve("assert"),
    };

    const setProvidePlugin = async () =>
      new wp.ProvidePlugin({
        Buffer: ["buffer", "Buffer"],
        process: "process/browser",
      });

    // * THIS METHOD SHOWS INSTANTIATED OBJ AFTER NEXT INSTANTIATES THEIR OBJS
    setProvidePlugin().then(
      (res) => (config.plugins = [...config.plugins, res])
    );

    return config;
  },
};

Expected behavior

To render stable components without provided error.

Actual behavior

Giving provided error, at times renders the sub components such as Document or Text, but not components such as PDFViewer but instead would at the top level allow the app to render fine implementing {PDFViewer} for the file _app.tsx.

Environment

diegomura commented 2 years ago

Yes. We currently don't support isomorphic rendering in both server and client with the same code