在 express js 服务器上使用 @react-pdf/renderer
Using @react-pdf/renderer on an express js server
我有一个 react
网络应用程序,我希望它必须呈现 pdf 并在按下按钮时通过电子邮件发送。为了测试起见,当在反应前端按下按钮时,它会向我的 expressjs 后端发送请求并尝试通过 @react-pdf/renderer
.
生成静态 pdf
我对 ES 模块和 CommonJS 没有清楚的了解,但我的服务器使用的是 CommonJS,所以我将 "type": "module"
添加到服务器的 package.json
并更新了 [=18] 中的导入=].但是,编译器在 server.js
和 materials.js
中抱怨 SyntaxError: Unexpected token '<'
(取决于设置)。我做错了什么?
(下面的代码已被清理为匿名)
编辑
Here 是在 Node
上使用 react-pdf/renderer 的示例
server.js:
// const express = require('express');
// const cors = require('cors');
// const fs = require('fs')
// const react = require('react')
// const reactpdf = require('@react-pdf/renderer');
// const materials = require('./pdf/src/materials');
import express from 'express';
import cors from 'cors';
import fs from 'fs';
import react from 'react';
import ReactPDF from '@react-pdf/renderer';
import MaterialsList from './materials.js';
const app = express();
const port = 5000;
app.use(cors())
app.use(express.urlencoded());
app.use(express.json());
app.listen(port, function () {
console.log(`server running on http://localhost:${port}`);
})
app.post('/sendmaterials', cors(), function (req, res) {
// const pdf = req.body;
// console.log(pdf);
// reactpdf.render(pdf, `${__dirname}/trial.pdf`);
reactpdf.render(<MaterialsList />, `${__dirname}/trial.pdf`);
// fs.writeFile('trial.pdf', pdf, (err) => {
// // throws an error, you could also catch it here
// if (err) throw err;
// // success case, the file was saved
// console.log('PDF saved!');
// });
})
package.json:
{
"name": "app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"dependencies": {
"@react-pdf/renderer": "^1.6.13",
"concurrently": "^5.3.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"firebase": "^9.0.0-beta.1",
"nodemon": "^2.0.6",
"react": "^17.0.2"
},
"devDependencies": {
"husky": "^5.1.3",
"lint-staged": "^10.5.4",
"prettier": "^2.2.1",
"pretty-quick": "^3.1.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "concurrently \"nodemon server.js\" \"cd frontend && yarn start\"",
"init": "concurrently \"yarn\" \"cd frontend && yarn\"",
"install-initial": "concurrently \"yarn install\" \"cd frontend && yarn install\"",
"start-frontend": "cd frontend && yarn start",
"start-server": "nodemon server.js",
"pretty-quick": "pretty-quick",
"prepare": "husky install"
},
"husky": {
"hooks": {
"pre-commit": "pretty-quick --staged"
}
},
"lint-staged": {
"linters": {
"src/**/*.{js,css}": [
"prettier --write",
"git add"
]
}
}
}
materials.js:
import React from 'react';
import {
Document,
Page,
Text,
View,
StyleSheet,
Image,
// Font,
} from '@react-pdf/renderer';
import Logo from './images/img.png'
// import Trebuchet from './fonts/Trebuchet/trebuchet-ms.ttf'
// Font.register({
// family: 'Trebuchet MS',
// src: Trebuchet,
// })
// Create styles
const styles = StyleSheet.create({
page: {
padding: 30,
},
container: {
marginTop: 20,
marginBottom: 20,
flex: 0,
flexDirection: 'row',
'@media max-width: 400': {
flexDirection: 'column',
},
},
image: {
marginTop: 20,
},
mainTitle: {
// fontFamily: 'Trebuchet MS',
paddingLeft: 15,
fontWeight: 'bold',
color: "#000000",
fontSize: 19,
},
title: {
// fontFamily: 'Trebuchet MS',
fontWeight: 'bold',
color: "#000000",
fontSize: 16,
textDecoration: 'underline',
},
regGrey: {
// fontFamily: 'Trebuchet MS',
color: "#8d8d8d",
fontSize: 12,
},
regBlack: {
// fontFamily: 'Trebuchet MS',
color: "#101010",
fontSize: 12,
marginBottom: 15,
},
column: {
flexDirection: 'column',
width: 180,
paddingLeft: 15,
paddingRight: 15,
'@media max-width: 400': {
width: '100%',
paddingRight: 0,
},
'@media orientation: landscape': {
width: 200,
},
},
table: {
width: '100%',
alignContent: 'center',
borderWidth: 0,
display: 'flex',
flexDirection: 'column',
paddingTop: 10,
},
header: {
backgroundColor: "#4c4c4c",
fontWeight: 'bold',
color: "#fdfdfd",
flexWrap: 'wrap'
},
tableRow:{
display: 'flex',
flexDirection: 'row',
},
lightRow:{
display: 'flex',
flexDirection: 'row',
backgroundColor: "#cfcfcf",
},
darkRow:{
display: 'flex',
flexDirection: 'row',
backgroundColor: "#aeaeae",
},
cell: {
fontColor: "#101010",
// fontFamily: 'Trebuchet MS',
fontSize: 12,
borderWidth: 0,
display: 'flex',
justifyContent: 'center',
alignContent: 'center',
textAlign: 'center',
flexWrap: 'wrap'
},
});
// Create table object
const Table = ({header, alternate, children, col}) => (
<View style={styles.table}>
{children.map((row, ind) =>
<View key={ind} style={[styles.tableRow,
header && ind === 0 ? styles.header: {},
alternate && ind % 2 === 0 && ind !== 0 ? styles.lightRow: {},
alternate && ind % 2 !== 0 && ind !== 0 ? styles.darkRow: {},
]}>
{row.map((cell, j) =>
<View key={j} style={[styles.cell, {width:col[j], height: 40}]}>
{
typeof(cell) === 'string' || typeof(cell) === 'number' ?
<Text>{cell}</Text> : cell
}
</View>
)}
</View>
)}
</View>
)
// Create Document Component
const MaterialsList = () => (
<Document>
<Page style={styles.page}>
<View style={styles.container}>
<View style={styles.column}>
<Text style={styles.title}>
Steels
</Text>
<Table
col={['60%', '40%']}
header
alternate
children={[
['Item', 'Quantity'],
['Steel', '10'],
['U Channel', '10'],
['Gate Insert', '10'],
]} />
</View>
</View>
</Page>
</Document>
);
export default MaterialsList
问题出在 package.json
文件中,我缺少 babel 库和配置文件。我有一个 example repo showing the correct setup and a link to the discussion on the react-pdf/renderer github discussion.
我有一个 react
网络应用程序,我希望它必须呈现 pdf 并在按下按钮时通过电子邮件发送。为了测试起见,当在反应前端按下按钮时,它会向我的 expressjs 后端发送请求并尝试通过 @react-pdf/renderer
.
我对 ES 模块和 CommonJS 没有清楚的了解,但我的服务器使用的是 CommonJS,所以我将 "type": "module"
添加到服务器的 package.json
并更新了 [=18] 中的导入=].但是,编译器在 server.js
和 materials.js
中抱怨 SyntaxError: Unexpected token '<'
(取决于设置)。我做错了什么?
(下面的代码已被清理为匿名)
编辑 Here 是在 Node
上使用 react-pdf/renderer 的示例server.js:
// const express = require('express');
// const cors = require('cors');
// const fs = require('fs')
// const react = require('react')
// const reactpdf = require('@react-pdf/renderer');
// const materials = require('./pdf/src/materials');
import express from 'express';
import cors from 'cors';
import fs from 'fs';
import react from 'react';
import ReactPDF from '@react-pdf/renderer';
import MaterialsList from './materials.js';
const app = express();
const port = 5000;
app.use(cors())
app.use(express.urlencoded());
app.use(express.json());
app.listen(port, function () {
console.log(`server running on http://localhost:${port}`);
})
app.post('/sendmaterials', cors(), function (req, res) {
// const pdf = req.body;
// console.log(pdf);
// reactpdf.render(pdf, `${__dirname}/trial.pdf`);
reactpdf.render(<MaterialsList />, `${__dirname}/trial.pdf`);
// fs.writeFile('trial.pdf', pdf, (err) => {
// // throws an error, you could also catch it here
// if (err) throw err;
// // success case, the file was saved
// console.log('PDF saved!');
// });
})
package.json:
{
"name": "app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"dependencies": {
"@react-pdf/renderer": "^1.6.13",
"concurrently": "^5.3.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"firebase": "^9.0.0-beta.1",
"nodemon": "^2.0.6",
"react": "^17.0.2"
},
"devDependencies": {
"husky": "^5.1.3",
"lint-staged": "^10.5.4",
"prettier": "^2.2.1",
"pretty-quick": "^3.1.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "concurrently \"nodemon server.js\" \"cd frontend && yarn start\"",
"init": "concurrently \"yarn\" \"cd frontend && yarn\"",
"install-initial": "concurrently \"yarn install\" \"cd frontend && yarn install\"",
"start-frontend": "cd frontend && yarn start",
"start-server": "nodemon server.js",
"pretty-quick": "pretty-quick",
"prepare": "husky install"
},
"husky": {
"hooks": {
"pre-commit": "pretty-quick --staged"
}
},
"lint-staged": {
"linters": {
"src/**/*.{js,css}": [
"prettier --write",
"git add"
]
}
}
}
materials.js:
import React from 'react';
import {
Document,
Page,
Text,
View,
StyleSheet,
Image,
// Font,
} from '@react-pdf/renderer';
import Logo from './images/img.png'
// import Trebuchet from './fonts/Trebuchet/trebuchet-ms.ttf'
// Font.register({
// family: 'Trebuchet MS',
// src: Trebuchet,
// })
// Create styles
const styles = StyleSheet.create({
page: {
padding: 30,
},
container: {
marginTop: 20,
marginBottom: 20,
flex: 0,
flexDirection: 'row',
'@media max-width: 400': {
flexDirection: 'column',
},
},
image: {
marginTop: 20,
},
mainTitle: {
// fontFamily: 'Trebuchet MS',
paddingLeft: 15,
fontWeight: 'bold',
color: "#000000",
fontSize: 19,
},
title: {
// fontFamily: 'Trebuchet MS',
fontWeight: 'bold',
color: "#000000",
fontSize: 16,
textDecoration: 'underline',
},
regGrey: {
// fontFamily: 'Trebuchet MS',
color: "#8d8d8d",
fontSize: 12,
},
regBlack: {
// fontFamily: 'Trebuchet MS',
color: "#101010",
fontSize: 12,
marginBottom: 15,
},
column: {
flexDirection: 'column',
width: 180,
paddingLeft: 15,
paddingRight: 15,
'@media max-width: 400': {
width: '100%',
paddingRight: 0,
},
'@media orientation: landscape': {
width: 200,
},
},
table: {
width: '100%',
alignContent: 'center',
borderWidth: 0,
display: 'flex',
flexDirection: 'column',
paddingTop: 10,
},
header: {
backgroundColor: "#4c4c4c",
fontWeight: 'bold',
color: "#fdfdfd",
flexWrap: 'wrap'
},
tableRow:{
display: 'flex',
flexDirection: 'row',
},
lightRow:{
display: 'flex',
flexDirection: 'row',
backgroundColor: "#cfcfcf",
},
darkRow:{
display: 'flex',
flexDirection: 'row',
backgroundColor: "#aeaeae",
},
cell: {
fontColor: "#101010",
// fontFamily: 'Trebuchet MS',
fontSize: 12,
borderWidth: 0,
display: 'flex',
justifyContent: 'center',
alignContent: 'center',
textAlign: 'center',
flexWrap: 'wrap'
},
});
// Create table object
const Table = ({header, alternate, children, col}) => (
<View style={styles.table}>
{children.map((row, ind) =>
<View key={ind} style={[styles.tableRow,
header && ind === 0 ? styles.header: {},
alternate && ind % 2 === 0 && ind !== 0 ? styles.lightRow: {},
alternate && ind % 2 !== 0 && ind !== 0 ? styles.darkRow: {},
]}>
{row.map((cell, j) =>
<View key={j} style={[styles.cell, {width:col[j], height: 40}]}>
{
typeof(cell) === 'string' || typeof(cell) === 'number' ?
<Text>{cell}</Text> : cell
}
</View>
)}
</View>
)}
</View>
)
// Create Document Component
const MaterialsList = () => (
<Document>
<Page style={styles.page}>
<View style={styles.container}>
<View style={styles.column}>
<Text style={styles.title}>
Steels
</Text>
<Table
col={['60%', '40%']}
header
alternate
children={[
['Item', 'Quantity'],
['Steel', '10'],
['U Channel', '10'],
['Gate Insert', '10'],
]} />
</View>
</View>
</Page>
</Document>
);
export default MaterialsList
问题出在 package.json
文件中,我缺少 babel 库和配置文件。我有一个 example repo showing the correct setup and a link to the discussion on the react-pdf/renderer github discussion.