GatsbyJS:如何在构建时同步加载组件,而在运行时异步加载组件?

时间:2019-03-26 10:21:04

标签: javascript reactjs gatsby

我有一个Gatsby网站,其中包含一个名为ArticleBody的React组件,该组件使用react-markdown将用Markdown编写的文章转换为React树。

由于这是一个昂贵的操作,并且组件有点大(出于SEO的原因),我想在构建时预渲染ArticleBody。但是,我也想在客户端中异步加载ArticleBody 。由于文章正文已经包含在HTML中,因此不必急于在客户端中加载和呈现Markdown组件,因此异步就可以了。

我该怎么做?几乎就像我想拥有两个不同的JS捆绑包一样:一个捆绑包为构建同步加载ArticleBody,而另一个捆绑包为客户端异步加载。在盖茨比有可能吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

您可以使用可加载组件代替不支持的 React.lazy。有一个 Gatsby 插件可以正确处理 SSR gatsby-plugin-loadable-components-ssr

自 Gatsby 3.x 以来,目前存在一个问题,但有一种方法可以在没有额外插件的情况下自行实现。请参阅问题 here 中的评论。还要添加其下方评论中提到的更改。

我还没有尝试过这个特定的实现,但它应该可以通过以下步骤工作:

npm install --save-dev @loadable/babel-plugin @loadable/server @loadable/webpack-plugin @loadable/component

gatsby-browser.js

import { loadableReady } from '@loadable/component'
import { hydrate } from 'react-dom'

export const replaceHydrateFunction = () => (element, container, callback) => {
  loadableReady(() => {
    hydrate(element, container, callback)
  })
}

gatsby-node.js

exports.onCreateWebpackConfig = ({ actions, stage }) => {
  if (
    stage === "build-javascript" ||
    stage === "develop" ||
    stage === "develop-html"
  ) {
    actions.setWebpackConfig({
      plugins: [
        new LoadablePlugin({
          filename:
            stage === "develop"
              ? `public/loadable-stats.json`
              : "loadable-stats.json",
          writeToDisk: true
        })
      ]
    });
  }
};

gatsby-ssr.js

import { ChunkExtractor } from '@loadable/server'
import path from 'path'

const extractor = new ChunkExtractor({
  // Read the stats file generated by webpack loadable plugin.
  statsFile: path.resolve('./public/loadable-stats.json'),
  entrypoints: [],
})

// extractor.collectChunks() will wrap the application in a ChunkExtractorManager
export const wrapRootElement = ({ element }) =>
  extractor.collectChunks(element)

export const onRenderBody = ({ setHeadComponents, setPostBodyComponents }) => {
  // Set link rel="preload" tags in the head to start the request asap. This will NOT parse the assets fetched
  setHeadComponents(extractor.getLinkElements())

  // Set script and style tags at the end of the document to parse the assets.
  setPostBodyComponents([...extractor.getScriptElements(), ...extractor.getStyleElements()])

  // Reset collected chunks after each page is rendered
  extractor.chunks = []
}

如果您启用了 DEV_SSR,则不应添加 stage === "develop-html"。否则,你很好。

希望这个问题评论的摘要可以帮助您入门。