如何使用服务器端渲染设置 react-helmet?
How setup react-helmet with Server Side Rendering?
我一直在尝试使用服务器端渲染设置 react-helmet。我遵循了有关如何使用 SSR 设置 react-helmet 的文档和一些博客文章,但无法产生预期的结果。这是我如何呈现应用程序的代码片段:
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './src/App';
const express = require('express');
const app = express();
app.get('*', (req, res) => {
const app = renderToString(<App />);
const helmet = Helmet.renderStatic();
res.send(formatHTML(app, helmet));
})
function formatHTML(appStr, helmet) {
return `
<!DOCTYPE html>
<html lang="en">
<head>
${helmet.title.toString()}
${helmet.meta.toString()}
</head>
<body>
<div id="root">
${ appStr }
</div>
<script src="./bundle.js"></script>
</body>
</html>
`
}
当我运行上面的代码时,我得到一个错误'cannot use import statement outside a module'。是否可以同时使用 es5 和 es6 语法?或者有没有更好的方法来设置 React-helmet?
这是我的babel配置文件
{
"presets": [
[
"@babel/preset-env",
{
"modules": false
}
],
"@babel/preset-react",
"@babel/preset-flow"
],
"env": {
"development": {
"only": [
"app",
"internals/scripts"
],
"plugins": [
"@babel/plugin-transform-react-jsx-source"
]
},
"production": {
"only": [
"app"
],
"plugins": [
"transform-react-remove-prop-types",
"@babel/plugin-transform-react-constant-elements",
"@babel/plugin-transform-react-inline-elements"
]
},
"test": {
"plugins": [
"@babel/plugin-transform-modules-commonjs",
"dynamic-import-node"
]
}
},
"compact": true,
"plugins": [
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-syntax-import-meta",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-json-strings",
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
],
"@babel/plugin-proposal-function-sent",
"@babel/plugin-proposal-export-namespace-from",
"@babel/plugin-proposal-numeric-separator",
"@babel/plugin-proposal-throw-expressions",
"@babel/plugin-proposal-export-default-from",
"@babel/plugin-proposal-logical-assignment-operators",
"@babel/plugin-proposal-optional-chaining",
[
"@babel/plugin-proposal-pipeline-operator",
{
"proposal": "minimal"
}
],
"@babel/plugin-proposal-nullish-coalescing-operator",
"@babel/plugin-proposal-do-expressions",
"@babel/plugin-proposal-function-bind",
"lodash"
]
}
您需要使用 @babel/register
包装您的服务器。
这就是我在不弹出的情况下处理我的 TypeScript CRA 项目的方式。
注意: 我使用此方法将元数据注入 index.html
与渲染整个应用程序(我使用的某些组件不能很好地与 SSR 配合使用)。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<div id="root"></div>
</body>
</html>
index.js
"use strict"
require("ignore-styles")
require("@babel/register")({
ignore: [/(node_modules)/],
presets: [
"@babel/preset-env",
"@babel/preset-react",
"@babel/preset-typescript",
],
extensions: [".tsx"],
cache: false,
})
require("./server")
server.js(节选)
const indexPath = path.join(__dirname, "build/index.html")
const middleware = async (req, res, next) => {
let context = {}
let html = renderToString(
React.createElement(StaticRouter, {
location: req.url,
context: context,
})
)
const helmet = Helmet.renderStatic()
if (context.url) {
res.redirect(context.url)
} else if (!fs.existsSync(indexPath)) {
next("Site is updating... please reload page in a few minutes.")
} else {
let index = fs.readFileSync(indexPath, "utf8")
let status = 200
if (typeof context.status === "number") {
status = context.status
}
return res.status(status).send(
index
.replace('<div id="root"></div>', `<div id="root">${html}</div>`)
.replace("</head>", `${helmet.meta.toString()}</head>`)
.replace("</head>", `${helmet.title.toString()}</head>`)
.replace("</head>", `${helmet.script.toString()}</head>`)
)
}
}
server.get("/", middleware)
server.use(express.static(path.join(__dirname, "build")))
server.get("*", middleware)
我一直在尝试使用服务器端渲染设置 react-helmet。我遵循了有关如何使用 SSR 设置 react-helmet 的文档和一些博客文章,但无法产生预期的结果。这是我如何呈现应用程序的代码片段:
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './src/App';
const express = require('express');
const app = express();
app.get('*', (req, res) => {
const app = renderToString(<App />);
const helmet = Helmet.renderStatic();
res.send(formatHTML(app, helmet));
})
function formatHTML(appStr, helmet) {
return `
<!DOCTYPE html>
<html lang="en">
<head>
${helmet.title.toString()}
${helmet.meta.toString()}
</head>
<body>
<div id="root">
${ appStr }
</div>
<script src="./bundle.js"></script>
</body>
</html>
`
}
当我运行上面的代码时,我得到一个错误'cannot use import statement outside a module'。是否可以同时使用 es5 和 es6 语法?或者有没有更好的方法来设置 React-helmet?
这是我的babel配置文件
{
"presets": [
[
"@babel/preset-env",
{
"modules": false
}
],
"@babel/preset-react",
"@babel/preset-flow"
],
"env": {
"development": {
"only": [
"app",
"internals/scripts"
],
"plugins": [
"@babel/plugin-transform-react-jsx-source"
]
},
"production": {
"only": [
"app"
],
"plugins": [
"transform-react-remove-prop-types",
"@babel/plugin-transform-react-constant-elements",
"@babel/plugin-transform-react-inline-elements"
]
},
"test": {
"plugins": [
"@babel/plugin-transform-modules-commonjs",
"dynamic-import-node"
]
}
},
"compact": true,
"plugins": [
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-syntax-import-meta",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-json-strings",
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
],
"@babel/plugin-proposal-function-sent",
"@babel/plugin-proposal-export-namespace-from",
"@babel/plugin-proposal-numeric-separator",
"@babel/plugin-proposal-throw-expressions",
"@babel/plugin-proposal-export-default-from",
"@babel/plugin-proposal-logical-assignment-operators",
"@babel/plugin-proposal-optional-chaining",
[
"@babel/plugin-proposal-pipeline-operator",
{
"proposal": "minimal"
}
],
"@babel/plugin-proposal-nullish-coalescing-operator",
"@babel/plugin-proposal-do-expressions",
"@babel/plugin-proposal-function-bind",
"lodash"
]
}
您需要使用 @babel/register
包装您的服务器。
这就是我在不弹出的情况下处理我的 TypeScript CRA 项目的方式。
注意: 我使用此方法将元数据注入 index.html
与渲染整个应用程序(我使用的某些组件不能很好地与 SSR 配合使用)。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<div id="root"></div>
</body>
</html>
index.js
"use strict"
require("ignore-styles")
require("@babel/register")({
ignore: [/(node_modules)/],
presets: [
"@babel/preset-env",
"@babel/preset-react",
"@babel/preset-typescript",
],
extensions: [".tsx"],
cache: false,
})
require("./server")
server.js(节选)
const indexPath = path.join(__dirname, "build/index.html")
const middleware = async (req, res, next) => {
let context = {}
let html = renderToString(
React.createElement(StaticRouter, {
location: req.url,
context: context,
})
)
const helmet = Helmet.renderStatic()
if (context.url) {
res.redirect(context.url)
} else if (!fs.existsSync(indexPath)) {
next("Site is updating... please reload page in a few minutes.")
} else {
let index = fs.readFileSync(indexPath, "utf8")
let status = 200
if (typeof context.status === "number") {
status = context.status
}
return res.status(status).send(
index
.replace('<div id="root"></div>', `<div id="root">${html}</div>`)
.replace("</head>", `${helmet.meta.toString()}</head>`)
.replace("</head>", `${helmet.title.toString()}</head>`)
.replace("</head>", `${helmet.script.toString()}</head>`)
)
}
}
server.get("/", middleware)
server.use(express.static(path.join(__dirname, "build")))
server.get("*", middleware)