Select to view content in your preferred language

How to use react-pdf with Experience Builder developer edition

3311
9
Jump to solution
04-13-2022 09:46 AM
Ming
by
Frequent Contributor

Working with Experience Builder developer edition v1.6. Try to use react-pdf in customized widget to generate pdf file with the react component.

But when install the react-pdf as instructed in following link, got a lot errors. 

https://github.com/diegomura/react-pdf

Question is how to add following configuration into current webpack.config.js file under folder client?

Configuration:

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"),
    }
  },
  plugins: [
    new webpack.ProvidePlugin({
      Buffer: ["buffer", "Buffer"],
      process: "process/browser",
    }),
  ]

Content of webpack.config.js under folder client:

const extensionsConfig = require('./webpack/webpack-extensions.config');

if(extensionsConfig.length === 0){
console.warn('You have to have at least one widget/theme.');
return;
}
module.exports = extensionsConfig;

 

Tags (1)
0 Kudos
1 Solution

Accepted Solutions
Ming
by
Frequent Contributor

Thank you very much @Junshan_Liu  and @ShaunLangley . Finally installed it successfully, and here is the steps:

1. Open Command Prompt, go to Experience Builder folder /client, run following commands:

npm install @react-pdf/renderer -S
npm install process browserify-zlib stream-browserify util buffer assert -S
npm install iconv-lite -S
npm install https-browserify -S
npm install url -S
npm install stream-http -S

2. Open file webpack-extensions.common.js under /client/wepack, modify function getWidgetsWebpackConfig, add following part to "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"),
https: require.resolve("https-browserify"),
url: require.resolve("url/"),
http: require.resolve("stream-http")

add following part to plguins:

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

Here is the one works after modification:

function getWidgetsWebpackConfig(entries, toBeCopiedFiles, toBeCleanFiles) {
  return {
    entry: entries,
    output: {
      filename: '[name].js',
      path: webpackCommon.outputPath,
      libraryTarget: "system",
      publicPath: '',
      chunkFilename: (pathData, assetInfo) => {
        return `${pathData.chunk.runtime}/${pathData.chunk.hash}.js`
      }
    },
    devtool: webpackCommon.sourceMapOption,
    resolve: {
      alias: webpackCommon.moduleAlias,
      extensions: webpackCommon.extensions,
      mainFields: webpackCommon.resolveMainFields,
      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"),
        https: require.resolve("https-browserify"),
        url: require.resolve("url/"),
        http: require.resolve("stream-http")
      }
    },
    module: {
      rules: webpackCommon.getModuleRules(path.resolve(__dirname, '../tsconfig/tsconfig-widgets.json'))
    },
    plugins: webpackCommon.getPlugins('widgets', toBeCopiedFiles, toBeCleanFiles).concat(
      [        
        new webpack.ProvidePlugin({
          Buffer: ["buffer", "Buffer"],
          process: "process/browser",
        }),
      ]
    ),
    externals: [
      webpackCommon.externalFunction
    ],
    stats: webpackCommon.stats,
    devServer: webpackCommon.devServer,
  };
}
 
3. Open file webpack.common under folder /client/wepack, add 'browser' to exports.resolveMainFields and here is the one works after modification:
exports.resolveMainFields = ['browser', 'module', 'main'];
----------------------
That's all, hope it can help, good luck!

View solution in original post

9 Replies
ShaunLangley
Occasional Contributor

The solution is quite involved.  In short, you need to use craco on top of webpack to get this to work.

here is my (working) configuration:

webpack.config.js

const webpack = require('webpack')
const path = require('path')

module.exports = {
	entry: './src/index.js',
	mode: 'development',
	module: {
		rules: [
			{
				test: /\.(js|jsx)$/,
				exclude: /(node_modules)/,
				loader: 'babel-loader',
				options: { presets: ['@babel/env', '@babel/preset-react'] },
			},
			{
				test: /\.(css)$/,
				use: ['style-loader', 'css-loader'],
			},
			{
				test: /\.scss$/,
				use: ['sass-loader'],
			},
		],
	},
	resolve: {
		extensions: ['*', '.js', '.jsx'],
		fallback: {
			module: 'empty',
			dgram: 'empty',
			dns: 'mock',
			fs: 'empty',
			http2: 'empty',
			net: 'empty',
			tls: 'empty',
			child_process: 'empty',
			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'),
		},
	},
	output: {
		path: path.resolve(__dirname, 'dist/'),
		publicPath: '/dist/',
		filename: 'bundle.js',
	},
	devServer: {
		static: path.join(__dirname, 'public/'),
		port: 3000,
		compress: true,
		historyApiFallback: true,
		hot: true,
	},
	plugins: [
		new webpack.ProvidePlugin({
			Buffer: ['buffer', 'Buffer'],
			process: 'process/browser',
		}),
	],
}

 

craco.config.js

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

module.exports = {
  webpack: {
    plugins: {
      add: [
        new NodePolyfillPlugin({
          excludeAliases: ["console"],
        }),
      ],
    },
  },
};

 

package.json dependencies (not all relevant to your case)

  "dependencies": {
    "@babel/cli": "^7.17.6",
    "@babel/core": "^7.17.8",
    "@babel/preset-env": "^7.16.11",
    "@babel/preset-react": "^7.16.7",
    "@craco/craco": "^6.4.3",
    "@devbookhq/splitter": "^1.3.2",
    "@material-ui/core": "^4.12.3",
    "@react-pdf/renderer": "^2.1.1",
    "@testing-library/jest-dom": "^5.14.1",
    "@testing-library/react": "^12.0.0",
    "@testing-library/user-event": "^13.2.1",
    "ag-grid-community": "^27.1.0",
    "ag-grid-react": "^27.1.0",
    "assert": "^2.0.0",
    "babel-loader": "^8.2.4",
    "bootstrap": "^5.1.3",
    "browserify-zlib": "^0.2.0",
    "buffer": "^6.0.3",
    "craco": "^0.0.3",
    "css-loader": "^6.7.1",
    "firebase": "^9.6.10",
    "node-polyfill-webpack-plugin": "^1.1.4",
    "process": "^0.11.10",
    "react": "^17.0.2",
    "react-apexcharts": "^1.4.0",
    "react-bootstrap": "^2.2.2",
    "react-dom": "^17.0.2",
    "react-hook-form": "^7.28.1",
    "react-icons": "^4.3.1",
    "react-router-dom": "^6.2.2",
    "react-scripts": "^5.0.0",
    "react-table": "^7.7.0",
    "sass": "^1.49.9",
    "sass-loader": "^12.6.0",
    "stream-browserify": "^3.0.0",
    "style-loader": "^3.3.1",
    "styled-components": "^5.3.5",
    "util": "^0.12.4",
    "web-vitals": "^2.1.4",
    "webpack": "^5.71.0",
    "webpack-cli": "^4.9.2",
    "webpack-dev-server": "^4.7.4"
  },
0 Kudos
ShaunLangley
Occasional Contributor

you might consider html2pdf as a better alternative.  I found it a bit easier to setup but of course not as flexible to use.  So there's a tradeoff there

 

0 Kudos
Ming
by
Frequent Contributor

Thank you very much for the help. Let me try react-pdf first, if still failed to setup, then switch to html2pdf :).

For the config "entry: './src/index.js'" in the webpack.config.js, the file index.js is you manually created? I mean by default the Experience Builder doesn't have that file, correct? 

0 Kudos
ShaunLangley
Occasional Contributor

you'll have to merge the webpack config code.  I didn't implement my solution in the context of exb.  Post your code if you can't get it to work and we can troubleshoot

 

0 Kudos
Ming
by
Frequent Contributor

Hello @JunshanLiu, can you please help on this? How to merge following part 

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"),
    }
  },
  plugins: [
    new webpack.ProvidePlugin({
      Buffer: ["buffer", "Buffer"],
      process: "process/browser",
    }),
  ]

to default ArcGIS Experience builder webpack.config.js that has following content?:

const extensionsConfig = require('./webpack/webpack-extensions.config');

if(extensionsConfig.length === 0){
console.warn('You have to have at least one widget/theme.');
return;
}
module.exports = extensionsConfig;

0 Kudos
ShaunLangley
Occasional Contributor

you'll probably have to edit webpack-extensions.config.  I'm going to try on my end but post something if you get it working.

0 Kudos
Junshan_Liu
Frequent Contributor

Hi, You can edit the "getWidgetsWebpackConfig" method in "webpack-extensions.common.js"

0 Kudos
Ming
by
Frequent Contributor

Thank you very much @Junshan_Liu  and @ShaunLangley . Finally installed it successfully, and here is the steps:

1. Open Command Prompt, go to Experience Builder folder /client, run following commands:

npm install @react-pdf/renderer -S
npm install process browserify-zlib stream-browserify util buffer assert -S
npm install iconv-lite -S
npm install https-browserify -S
npm install url -S
npm install stream-http -S

2. Open file webpack-extensions.common.js under /client/wepack, modify function getWidgetsWebpackConfig, add following part to "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"),
https: require.resolve("https-browserify"),
url: require.resolve("url/"),
http: require.resolve("stream-http")

add following part to plguins:

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

Here is the one works after modification:

function getWidgetsWebpackConfig(entries, toBeCopiedFiles, toBeCleanFiles) {
  return {
    entry: entries,
    output: {
      filename: '[name].js',
      path: webpackCommon.outputPath,
      libraryTarget: "system",
      publicPath: '',
      chunkFilename: (pathData, assetInfo) => {
        return `${pathData.chunk.runtime}/${pathData.chunk.hash}.js`
      }
    },
    devtool: webpackCommon.sourceMapOption,
    resolve: {
      alias: webpackCommon.moduleAlias,
      extensions: webpackCommon.extensions,
      mainFields: webpackCommon.resolveMainFields,
      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"),
        https: require.resolve("https-browserify"),
        url: require.resolve("url/"),
        http: require.resolve("stream-http")
      }
    },
    module: {
      rules: webpackCommon.getModuleRules(path.resolve(__dirname, '../tsconfig/tsconfig-widgets.json'))
    },
    plugins: webpackCommon.getPlugins('widgets', toBeCopiedFiles, toBeCleanFiles).concat(
      [        
        new webpack.ProvidePlugin({
          Buffer: ["buffer", "Buffer"],
          process: "process/browser",
        }),
      ]
    ),
    externals: [
      webpackCommon.externalFunction
    ],
    stats: webpackCommon.stats,
    devServer: webpackCommon.devServer,
  };
}
 
3. Open file webpack.common under folder /client/wepack, add 'browser' to exports.resolveMainFields and here is the one works after modification:
exports.resolveMainFields = ['browser', 'module', 'main'];
----------------------
That's all, hope it can help, good luck!
ShaunLangley
Occasional Contributor

Nice work!  Thanks for letting us know how you solved it.