Как использовать stati c медиаресурсы, сгенерированные сборкой CRA npm в режиме SSR? - PullRequest
1 голос
/ 26 марта 2020

У меня есть стандартное приложение TypeScript React, созданное с использованием CRA.

Оно использует шлем для метаданных и стилевые компоненты для стиля.

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

Например, import sun from "../images/sun.jpg" отображается как [object Object] вместо data:image/jpeg;base64,... и import backgroundS from "../images/background-1280x720.jpg" как [object Object] вместо /static/media/background-1280x720.702f9ac6.jpg.

import sun from "../images/sun.jpg"

const ImageComponent = () => (
  <img src={sun} /> // In SSR mode, this is rendered as <img src="[object Object]">
)

Я только начинаю работать с React SSR, поэтому мне, вероятно, не хватает нескольких ключевых знаний, чтобы понять это. Я потратил более двух часов, пытаясь найти решение.

Что мне не хватает?

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

"use strict"

const dotenv = require("dotenv").config()
const express = require("express")
const path = require("path")
const fs = require("fs")
const renderToString = require("react-dom/server").renderToString
const React = require("react")
const Helmet = require("react-helmet").default
const ServerStyleSheet = require("styled-components").ServerStyleSheet
const StaticRouter = require("./src/routers/Static").default

const indexPath = path.join(__dirname, "build/index.html")

const server = express()

server.disable("x-powered-by")

const middleware = async (req, res, next) => {
  const sheet = new ServerStyleSheet()
  let context = {}
  let html = renderToString(
    sheet.collectStyles(
      React.createElement(StaticRouter, {
        location: req.url,
        context: context,
      })
    )
  )
  const helmet = Helmet.renderStatic()
  const styleTags = sheet.getStyleTags()
  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>`)
        .replace("</head>", `${styleTags}</head>`)
    )
  }
}

// This line is required by SSR
server.get("/", middleware)

server.use(express.static(path.join(__dirname, "build")))

server.get("*", middleware)

server.listen(process.env.PORT, function() {
  console.log(`Server listening on port ${process.env.PORT}`)
})

1 Ответ

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

Если вы знаете, как решить этот вопрос, пожалуйста, отправьте ответ!

При этом, возможно, это не решаемо, поэтому вот обходной путь.

Я закончил тем, что переместил свое изображение активы до public/static/media и использование абсолютных src путей для импорта и SSR работает после запуска npm build!

const ImageComponent = () => (
  <img src="/static/media/sun.jpg" />
)
...