How to use react-pdf with Experience Builder developer edition

2672
9
Jump to solution
04-13-2022 09:46 AM
Labels (1)
Ming
by
Occasional 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
Occasional 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
New Contributor III

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
New Contributor III

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
Occasional 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
New Contributor III

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
Occasional 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
New Contributor III

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
Occasional Contributor

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

0 Kudos
Ming
by
Occasional 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
New Contributor III

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