如何在NextJS中配置Loadable Components的服务端渲染(SSR)?
在Next.js中配置Loadable Components实现SSR的问题
背景
我们在构建新的Next.js应用时,需要使用Loadable Components。虽然知道Next.js原生支持dynamic import,但现有成熟代码库中大量使用Loadable Components,替换为原生dynamic import成本太高,不现实。
问题复现
我创建了示例场景来演示问题,核心代码如下(在pages/index.tsx中通过Loadable拆分Layout组件):
import * as React from 'react'; import Link from 'next/link'; import loadable from '@loadable/component'; const LayoutLoadable = loadable(() => import('../components/Layout')); const IndexPage = () => ( <LayoutLoadable title="Home | Next.js + TypeScript Example"> <h1>Hello Next.js 👋</h1> <p> <Link href="/about"> <a>About</a> </Link> </p> </LayoutLoadable> ); export default IndexPage;
运行命令:yarn && yarn dev(或等效npm命令)
访问http://localhost:3000/时,页面body仅包含根挂载div,SSR未正常工作:
<body> <div id="__next" data-reactroot=""></div> <script src="/_next/static/chunks/react-refresh.js?ts=1663916845500"></script> <script id="__NEXT_DATA__" type="application/json"> { "props": { "pageProps": {} }, "page": "/", "query": {}, "buildId": "development", "nextExport": true, "autoExport": true, "isFallback": false, "scriptLoader": [] } </script> </body>
不过客户端可以正常完成hydration并显示内容,说明客户端渲染逻辑是正常的。
如果改为普通导入Layout组件:
import * as React from 'react'; import Link from 'next/link'; import Layout from '../components/Layout'; const IndexPage = () => ( <Layout title="Home | Next.js + TypeScript Example"> <h1>Hello Next.js 👋</h1> <p> <Link href="/about"> <a>About</a> </Link> </p> </Layout> ); export default IndexPage;
则SSR正常工作,body包含完整渲染的HTML内容:
<body> <div id="__next" data-reactroot=""> <div> <header> <nav> <a href="/">Home</a> <!-- --><!-- --><a href="/about">About</a> <!-- --><!-- --><a href="/users">Users List</a> <!-- --><!-- -->| <a href="/api/users">Users API</a> </nav> </header> <h1>Hello Next.js 👋</h1> <p><a href="/about">About</a></p> <footer> <hr /> <span>I'm here to stay (Footer)</span> </footer> </div> </div> <script src="/_next/static/chunks/react-refresh.js?ts=1663917155976"></script> <script id="__NEXT_DATA__" type="application/json"> { "props": { "pageProps": {} }, "page": "/", "query": {}, "buildId": "development", "nextExport": true, "autoExport": true, "isFallback": false, "scriptLoader": [] } </script> </body>
已尝试的配置
我参考Loadable Components的SSR文档,在自定义_document.tsx中做了如下配置:
import Document, { Html, Head, Main, NextScript } from 'next/document'; import * as React from 'react'; import { ChunkExtractor } from '@loadable/server'; import path from 'path'; export default class AppDocument extends Document { render() { const statsFile = path.resolve('.next/loadable-stats.json'); const chunkExtractor = new ChunkExtractor({ statsFile, }); return chunkExtractor.collectChunks( <Html> <Head /> <body> <Main /> <NextScript /> </body> </Html> ); } }
但该配置未生效,推测原因是Next.js内部自行处理renderToString(jsx),导致无法在合适位置应用Loadable的SSR配置。
请问有没有人成功在Next.js中配置Loadable Components的SSR?我找不到正确的配置位置。
内容的提问来源于stack exchange,提问作者andrew_scfc
相关产品推荐
相关产品推荐

