Skip to content

antd 服务端渲染的一些细节

antd 服务端渲染有两种方案 (这两种方案全都只为了首屏渲染时页面不会闪动,仅此而已)

内联样式渲染问题

会将 css 直接生成在 style 标签中 然后挂载到 body 标签中。

单页面应用(SPA)中,这样倒是没有什么缺点,但是如果是多页面应用,那么就会有问题了。会导致 HTMl 变的极大并且每个页面引用的公共组件代码都是全量重复。

整体导出渲染问题

他的整体导出 应该理解为将 css 剥离单独成一个文件。同样也分两种方式

全量导出

会将 antd 样式提取到一个单独文件,此方法可以说是单页面 or 多页面最优解了。但是也有一个问题,体积太大了!!!以 "antd": "^5.8.6", 来说,导出文件大小可达 809kb。

引用 @ant-design/static-style-extract 示例代码,高亮部分代码是可以改动一下变成白名单,通过首屏展示的组件可以单独提取出来优化整体大小。另外不考虑定制主题情况下可以删除 antd.css 中的 where 选择器 来获取最大精简样式文件。

点击查看代码
tsx
import React from "react";
import { createCache, extractStyle as extStyle, StyleProvider } from "@ant-design/cssinjs";
import * as antd from "antd";
import { renderToString } from "react-dom/server";
import type { CustomRender } from "./interface";
const blackList: string[] = [
  "ConfigProvider",
  "Drawer",
  "Grid",
  "Modal",
  "Popconfirm",
  "Popover",
  "Tooltip",
  "Tour",
];

const defaultNode = () => (
  <>
    {Object.keys(antd)
      .filter((name) => !blackList.includes(name) && name[0] === name[0].toUpperCase())
      .map((compName) => {
        const Comp = antd[compName];
        if (compName === "Dropdown") {
          return (
            <Comp key={compName} menu={{ items: [] }}>
              <div />
            </Comp>
          );
        }
        return <Comp key={compName} />;
      })}
  </>
);

export function extractStyle(customTheme?: CustomRender): string {
  const cache = createCache();
  renderToString(
    <StyleProvider cache={cache}>
      {customTheme ? customTheme(defaultNode()) : defaultNode()}
    </StyleProvider>
  );

  // Grab style from cache
  const styleText = extStyle(cache, true);

  return styleText;
}

按需抽取

确实做到了按需抽取,但是有一个非常大的问题,和 内联样式渲染问题 一样, 如果加入了公共组件,那么公共样式会不停重复生成,并没有将公共部分样式代码单独提取到另一个公共样式文件。详情请看:#28

从各个方面来看都不如内联样式渲染

总结

  • 内联样式渲染,单页面引用可以考虑,类似 next.js 做多页面引用可以直接 pass
  • 整体导出渲染,两个解决方案都有利弊。在不考虑定制主题情况下 可以直接单独生成一套 antd.css 样式直接引用
  • antd css 是通过 [css-in-js] 来实现的。所有的样式都是通过 js 来控制,包括 css module (会给所有标签添加一个对应的 hash 来区分主题或者自定义样式)。服务端渲染的 css 仅仅只是为了首屏渲染不会闪屏(首屏渲染之后 antd 会在单独插入 hash style 替换原来生成好的 css 样式

小插曲

我本人是使用 antd + next.js 做服务端渲染的,然后打包服务器是每次都会清理 npm 重新安装依赖,但是我的 antd 依赖为 "antd": "^5.8.6", ^ 导致打包时候的 hash 和 生产环境的 hash 不同,引用了 css 之后还是会首屏渲染闪屏 hhhh... 然后就是愉快地看源码中

Site developed by Aomd.