Как настроить реакцию шлема при рендеринге на стороне сервера? - PullRequest
1 голос
/ 24 марта 2020

Я пытался настроить ответный шлем с рендерингом на стороне сервера. Я следовал за документами и некоторыми постами в блоге о том, как настроить реагирующий шлем с SSR, но не смог добиться желаемых результатов. Вот фрагмент кода того, как я рендерим приложение:

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>
  `
}

Когда я запускаю приведенный выше код, я получаю сообщение об ошибке «невозможно использовать оператор импорта вне модуля». Можно ли использовать синтаксис es5 и es6 одновременно? Или есть лучший способ настроить React-шлем?

Это мой файл конфигурации 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"
  ]
}

1 Ответ

0 голосов
/ 25 марта 2020

Вам нужно обернуть свой сервер, используя @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")

сервер. 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)
...