1

我正在尝试使用@loadable/component.

我目前的情况:这就是我在我的网站上为机器人实现 SSR 的方式。由于它仅适用于机器人,因此我不使用hydrate. 基本上,我index.html为普通用户发送带有 JS 包的脚本标签的 ,或者我为机器人发送一个完全呈现的 HTML 页面,而无需hydrate.

我的目标:我想@loadable/component总是从我的服务器返回 SSR 页面,并hydrate用来附加我的 JS 包。并以此实现代码拆分。

这是我目前构建应用程序的方式(伪代码):

1. webpack BUILD FOR entry { app: "src/index.tsx" } AND OUTPUT BUNDLES TO MY /public FOLDER
2. babel TRANSPILE WHOLE `/src` FOLDER AND OUTPUT FILES TO MY /dist_app FOLDER

它基本上是 2 个构建,其中一个是使用 webpack 进行捆绑,另一个基本上是将文件srcdistApp.

这就是我的服务器所做的(伪代码)

1. CHECK IF USER IS ROBOT (FROM THE USER AGENT STRING)
2. IF REGULAR USER
     res.send("public/index.html");   // SEND REGULAR index.html WITH JS BUNDLES GENERATED BY WEBPACK
   IF ROBOT
     const App = require("./dist_app/App");          // THIS IS THE src/App COMPONENT TRANSPILED BY BABEL
     const ssrHtml = ReactDOM.renderToString(<App/>);
     // ADD <head> <helmet> <styles> ETC
     res.send(ssrHtml);

上述步骤适用于我的初始要求(ssr 仅适用于机器人)。

但是我加@loadable/component了实现分码+SSR之后,上面的设置就不行了。

因为现在我有dynamic imports一些路线。例如:

const AsyncPage = loadable(() => import("@app/pages/PageContainer"));

所以我的renderToString(<App/>)电话大部分都是空的,因为它没有加载那些AsyncPages.

可加载组件的文档上:服务器端渲染他们有一个关于如何实现这一点的示例存储库。

但是他们的例子有点复杂,似乎他们webpack在服务器内部使用。我将在下面发布他们在他们的服务器上所做的事情。

问题

我真的必须使用webpack捆绑我的应用程序的服务器代码才能@loadable/component像他们在示例中显示的那样用于 SSR 吗?我不能只使用某种babel插件将其转换dynamic imports为常规require调用吗?这样我就可以像以前那样渲染它了?

很奇怪,他们使用webpack-dev-middleware. 就像这个例子应该只用于开发。有人知道带有生产示例的回购吗?

import path from 'path'
import express from 'express'
import React from 'react'
import { renderToString } from 'react-dom/server'
import { ChunkExtractor } from '@loadable/server'

const app = express()

app.use(express.static(path.join(__dirname, '../../public')))

if (process.env.NODE_ENV !== 'production') {
  /* eslint-disable global-require, import/no-extraneous-dependencies */
  const { default: webpackConfig } = require('../../webpack.config.babel')
  const webpackDevMiddleware = require('webpack-dev-middleware')
  const webpack = require('webpack')
  /* eslint-enable global-require, import/no-extraneous-dependencies */

  const compiler = webpack(webpackConfig)

  app.use(
    webpackDevMiddleware(compiler, {
      logLevel: 'silent',
      publicPath: '/dist/web',
      writeToDisk(filePath) {
        return /dist\/node\//.test(filePath) || /loadable-stats/.test(filePath)
      },
    }),
  )
}

const nodeStats = path.resolve(
  __dirname,
  '../../public/dist/node/loadable-stats.json',
)

const webStats = path.resolve(
  __dirname,
  '../../public/dist/web/loadable-stats.json',
)

app.get('*', (req, res) => {
  const nodeExtractor = new ChunkExtractor({ statsFile: nodeStats })
  const { default: App } = nodeExtractor.requireEntrypoint()

  const webExtractor = new ChunkExtractor({ statsFile: webStats })
  const jsx = webExtractor.collectChunks(<App />)

  const html = renderToString(jsx)

  res.set('content-type', 'text/html')
  res.send(`
      <!DOCTYPE html>
      <html>
        <head>
        ${webExtractor.getLinkTags()}
        ${webExtractor.getStyleTags()}
        </head>
        <body>
          <div id="main">${html}</div>
          ${webExtractor.getScriptTags()}
        </body>
      </html>
    `)
})

// eslint-disable-next-line no-console
app.listen(9000, () => console.log('Server started http://localhost:9000'))
4

0 回答 0