├── .eslintrc ├── .gitignore ├── README.md ├── config ├── env.js ├── jest │ ├── cssTransform.js │ └── fileTransform.js ├── paths.js ├── polyfills.js ├── webpack.config.dev.js └── webpack.config.generate.js ├── example └── invoice.js ├── package-lock.json ├── package.json ├── public ├── favicon.ico └── index.html ├── scripts ├── build.js ├── start.js └── test.js ├── server ├── createPDF.js └── template.html └── src ├── Invoice.css ├── Invoice.js ├── elements ├── Address │ ├── Address.css │ ├── Address.js │ └── Block.js ├── Header │ ├── Header.css │ ├── Header.js │ └── logo.png └── List │ ├── List.css │ └── List.js ├── global.css ├── index.js └── vendor └── normalize.css /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "react-app" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # generated output 10 | /build 11 | 12 | # compiled files 13 | /lib 14 | 15 | # ignore the yarn lockfile as this is a demo repository 16 | yarn.lock 17 | 18 | # misc 19 | .DS_Store 20 | .env 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This project is no longer being maintained 2 | 3 | 4 | --- 5 | # Generating PDFs with React 6 | This is an example project you can use to generate PDFs with React. Start by checking the related talk slides [here](http://bit.ly/react-emails-pdf). 7 | 8 | > If you want to generate emails using React, check the [react-emails](https://github.com/lang-ai/react-emails) repo. 9 | 10 | ### Example 11 | 12 | To provide an example as starting point, this project generates a demo invoice. 13 | 14 | To generate the example: 15 | 16 | ``` 17 | $ npm install 18 | $ npm run build 19 | $ node example/invoice.js 20 | ``` 21 | 22 | The result PDF will be saved in the `/build/` directory. Here is how it looks like: 23 | 24 | ![PDF Preview](https://s3-eu-west-1.amazonaws.com/langai-public/github/invoice.png) 25 | 26 | 27 | ### Development 28 | 29 | This project was bootstrapped with [Create React App][react-create-app]. 30 | See the development guide [here][react-create-app-guide]. 31 | 32 | 33 | ### Creating the PDF 34 | 35 | To create the PDF, simply import the function (you may want to use it as a module) and call it with the 36 | data. It returns a promise that resolves when the generated PDF path. 37 | 38 | ```js 39 | // In case you use it as a module 40 | // const createPDF = require('react-pdfs-example'); 41 | 42 | const createPDF = require('../server/createPDF'); 43 | 44 | const data = { 45 | date: new Date().toISOString(), 46 | number: 32149, 47 | recipient: { 48 | displayName: 'John White', 49 | addressLine: 'CEO at Carddesign.con\nLondon, United Kingdom', 50 | }, 51 | // more data... 52 | }; 53 | 54 | createPDF(data) 55 | .then((path) => { 56 | // PDF has been generated with the config from the function 57 | // generatePDF() inside server/createPDF.js. 58 | // Returns the generated PDF path. 59 | }); 60 | ``` 61 | 62 | - - - - - - - - - - 63 | 64 | [![LangAI](https://s3-eu-west-1.amazonaws.com/langai-public/github/logo-small.png)][langai] 65 | 66 | **Built with ❤️ by Lang.ai** 67 | 68 | [langai]: https://building.lang.ai/ 69 | [react-create-app]: https://github.com/facebookincubator/create-react-app 70 | [react-create-app-guide]: https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md 71 | 72 | -------------------------------------------------------------------------------- /config/env.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be 4 | // injected into the application via DefinePlugin in Webpack configuration. 5 | 6 | var REACT_APP = /^REACT_APP_/i; 7 | 8 | function getClientEnvironment(publicUrl) { 9 | var raw = Object 10 | .keys(process.env) 11 | .filter(key => REACT_APP.test(key)) 12 | .reduce((env, key) => { 13 | env[key] = process.env[key]; 14 | return env; 15 | }, { 16 | // Useful for determining whether we’re running in production mode. 17 | // Most importantly, it switches React into the correct mode. 18 | 'NODE_ENV': process.env.NODE_ENV || 'development', 19 | // Useful for resolving the correct path to static assets in `public`. 20 | // For example, . 21 | // This should only be used as an escape hatch. Normally you would put 22 | // images into the `src` and `import` them in code to get their paths. 23 | 'PUBLIC_URL': publicUrl 24 | }); 25 | // Stringify all values so we can feed into Webpack DefinePlugin 26 | var stringified = { 27 | 'process.env': Object 28 | .keys(raw) 29 | .reduce((env, key) => { 30 | env[key] = JSON.stringify(raw[key]); 31 | return env; 32 | }, {}) 33 | }; 34 | 35 | return { raw, stringified }; 36 | } 37 | 38 | module.exports = getClientEnvironment; 39 | -------------------------------------------------------------------------------- /config/jest/cssTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // This is a custom Jest transformer turning style imports into empty objects. 4 | // http://facebook.github.io/jest/docs/tutorial-webpack.html 5 | 6 | module.exports = { 7 | process() { 8 | return 'module.exports = {};'; 9 | }, 10 | getCacheKey() { 11 | // The output is always the same. 12 | return 'cssTransform'; 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /config/jest/fileTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | 5 | // This is a custom Jest transformer turning file imports into filenames. 6 | // http://facebook.github.io/jest/docs/tutorial-webpack.html 7 | 8 | module.exports = { 9 | process(src, filename) { 10 | return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';'; 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /config/paths.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var fs = require('fs'); 5 | var url = require('url'); 6 | 7 | // Make sure any symlinks in the project folder are resolved: 8 | // https://github.com/facebookincubator/create-react-app/issues/637 9 | var appDirectory = fs.realpathSync(process.cwd()); 10 | function resolveApp(relativePath) { 11 | return path.resolve(appDirectory, relativePath); 12 | } 13 | 14 | // We support resolving modules according to `NODE_PATH`. 15 | // This lets you use absolute paths in imports inside large monorepos: 16 | // https://github.com/facebookincubator/create-react-app/issues/253. 17 | 18 | // It works similar to `NODE_PATH` in Node itself: 19 | // https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders 20 | 21 | // We will export `nodePaths` as an array of absolute paths. 22 | // It will then be used by Webpack configs. 23 | // Jest doesn’t need this because it already handles `NODE_PATH` out of the box. 24 | 25 | // Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored. 26 | // Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims. 27 | // https://github.com/facebookincubator/create-react-app/issues/1023#issuecomment-265344421 28 | 29 | var nodePaths = (process.env.NODE_PATH || '') 30 | .split(process.platform === 'win32' ? ';' : ':') 31 | .filter(Boolean) 32 | .filter(folder => !path.isAbsolute(folder)) 33 | .map(resolveApp); 34 | 35 | var envPublicUrl = process.env.PUBLIC_URL; 36 | 37 | function ensureSlash(path, needsSlash) { 38 | var hasSlash = path.endsWith('/'); 39 | if (hasSlash && !needsSlash) { 40 | return path.substr(path, path.length - 1); 41 | } else if (!hasSlash && needsSlash) { 42 | return path + '/'; 43 | } else { 44 | return path; 45 | } 46 | } 47 | 48 | function getPublicUrl(appPackageJson) { 49 | return envPublicUrl || require(appPackageJson).homepage; 50 | } 51 | 52 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer 53 | // "public path" at which the app is served. 54 | // Webpack needs to know it to put the right