Adding react-pdf to Create React App with Craco
Tags: webpack, pdf, craco, react
Published: 2023-06-15 07:19:53

## Introduction

As of the current date (2023-06-15), adding `react-pdf` to a Create React App (CRA) project by default is not possible due to the upgraded Webpack version in CRA to Webpack 5. However, we can use Craco, a tool that allows us to modify the Webpack configuration without ejecting from CRA, to safely integrate `react-pdf` into our project.

To understand why we need to use Craco and how it helps us overcome the limitations, you can refer to this comment on GitHub: [react-pdf issue #1029](https://github.com/diegomura/react-pdf/issues/1029#issuecomment-855304150).

## Steps

### Step 1: Initialize the project
Initialize the project by running the following command in your terminal:
```sh
npm init react-app react-pdf-cra
```
or
```sh
yarn create react-app react-pdf-cra
```

Then navigate to the project directory:

```sh
cd react-pdf-cra
```

### Step 2: Add the required dependencies
Install the required dependencies by running the following command:
```sh
npm install @react-pdf/renderer browserify-fs node-polyfill-webpack-plugin process webpack pako assert browserify-zlib buffer process stream-browserify util
```
or
```sh
yarn add @react-pdf/renderer browserify-fs node-polyfill-webpack-plugin process webpack pako assert browserify-zlib buffer process stream-browserify util
```

The dependencies include:

- `@react-pdf/renderer`: The main library for creating PDFs using React components.
- `browserify-fs`: A browserify-compatible version of the Node.js `fs` module.
- `node-polyfill-webpack-plugin`: A Webpack plugin that provides polyfills for Node.js core modules.
- `process`: A browser-compatible version of the Node.js `process` object.
- `webpack`: The Webpack module bundler.
- `pako`: A zlib implementation in JavaScript.
- `assert`: The Node.js `assert` module.
- `browserify-zlib`: A browserify-compatible version of the Node.js `zlib` module.
- `buffer`: A browserify-compatible version of the Node.js `buffer` module.
- `stream-browserify`: A browserify-compatible version of the Node.js `stream` module.
- `util`: The Node.js `util` module.

For the development dependency, install:

```sh
npm install -D @craco/craco
```
or
```sh
yarn add -D @craco/craco
```

### Step 3: Initialize Craco

Replace the `package.json` scripts with:

```json
"scripts": {
  "start": "craco start",
  "build": "craco build",
  "test": "craco test",
  "eject": "craco eject"
}
```

Create a `craco.config.js` file in the project's root directory:

```sh
touch craco.config.js
```

Inside the `craco.config.js` file, add the following configuration:

```javascript
const webpack = require("webpack");
const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");

module.exports = {
  webpack: {
    configure: {
      resolve: {
        fallback: {
          process: require.resolve("process/browser"),
          zlib: require.resolve('@react-pdf/zlib'),
          stream: require.resolve("stream-browserify"),
          util: require.resolve("util"),
          buffer: require.resolve("buffer"),
          asset: require.resolve("assert"),
          fs: require.resolve('browserify-fs'),
        },
      },
      plugins: [
        new webpack.ProvidePlugin({
          Buffer: ["buffer",

 "Buffer"],
          process: "process/browser.js",
        }),
        new NodePolyfillPlugin(),
      ],
    },
  },
};
```

### Step 4: Modify the App component

Replace the contents of `./src/App.js` with the following code:

```javascript
import "./App.css";
import React from "react";
import { Page, Text, View, Document, StyleSheet } from "@react-pdf/renderer";

// Create styles
const styles = StyleSheet.create({
  page: {
    flexDirection: "row",
    backgroundColor: "#E4E4E4",
  },
  section: {
    margin: 10,
    padding: 10,
    flexGrow: 1,
  },
});

function App() {
  return (
    <div className="App">
      <Document>
        <Page size="A4" style={styles.page}>
          <View style={styles.section}>
            <Text>Section #1</Text>
          </View>
          <View style={styles.section}>
            <Text>Section #2</Text>
          </View>
        </Page>
      </Document>
    </div>
  );
}

export default App;
```

### Step 5: Run the application
Start the application by running the following command:
```sh
npm start
```
or
```sh
yarn start
```

The application should now be running, and you should see the PDF displayed.

## Conclusion

In conclusion, by using Craco and modifying the Webpack configuration, we can integrate `react-pdf` into a Create React App project without the need to eject. This allows us to leverage the power of React components to create PDFs within our application.

Certainly! Here's the updated version with the Troubleshooting section added:

## Troubleshooting

If you encounter an error message like `Module not found: Error: ...... You attempted to import which falls outside of the project src/ directory. Relative imports outside of src/ are not supported.`, you can try the following steps to resolve it:

1. Open the `craco.config.js` file.

2. Replace the existing content with the following code:

    ```javascript
    const webpack = require("webpack");
    const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");

    const baseConfig = {
      webpack: {
        configure: {
          resolve: {
            fallback: {
              process: require.resolve("process/browser"),
              zlib: require.resolve('@react-pdf/zlib'),
              stream: require.resolve("stream-browserify"),
              util: require.resolve("util"),
              buffer: require.resolve("buffer"),
              asset: require.resolve("assert"),
              fs: require.resolve('browserify-fs'),
            },
          },
          plugins: [
            new webpack.ProvidePlugin({
              Buffer: ["buffer", "Buffer"],
              process: "process/browser.js",
            }),
            new NodePolyfillPlugin(),
          ],
        },
      },
    };

    const additionalConfig = {
      webpack: {
        configure: webpackConfig => {
          const scopePluginIndex = webpackConfig.resolve.plugins.findIndex(
            ({ constructor }) => constructor && constructor.name === 'ModuleScopePlugin'
          );
          webpackConfig.resolve.plugins.splice(scopePluginIndex, 1);
          return webpackConfig;
        },
      },
    };

    module.exports = {
      ...baseConfig,
      ...additionalConfig,
    };
    ```

3. Save the changes to the `craco.config.js` file.

By applying these modifications to the configuration, the error related to module imports outside of the `src/` directory should be resolved.

## Sources

- [react-pdf issue #1029](https://github.com/diegomura/react-pdf/issues/1029)
- [react-pdf issue #1029 comment](https://github.com/diegomura/react-pdf/issues/1029#issuecomment-1481503463)
- [Stack Overflow: Hosted images with react-pdf](https://stackoverflow.com/questions/63729455/hosted-images-with-react-pdf/72744600#72744600)
- [GitHub: web-starter-kit issue #112](https://github.com/google/web-starter-kit/issues/112#issuecomment-62977833)