Bootstrap

NextJs - antd5 降级兼容方案

前言

目前antd5对于SSR的兼容还有各方面都是很不错的,比如性能、UI设计等,不过,我们作为开发人员,在使用antd5作为UI组件库的时候,还需要考虑版本兼容问题,这里就说明下NextJs中如何进行antd5的降级。

和本篇内容有关的前序文章:NextJs - SSR渲染解决antd首屏加载CSS样式的闪烁问题

官方的:参考文档

一. 降级解决方案

降级主要针对两个方向:

  • 静态组件:messageModal等组件
  • 非静态组件:Row、这类常规的组件。

antd 中可以直接 message.xxx,Modal.xxx,notification.xxx 静态方法调用展示对应的UI这类弹出类的组件,是脱离了root节点之外插入的,因此他们在低版本的浏览器下可能会不生效,例如Modal.info函数,在chrome87版本就会不生效

1.1 解决 message 等通知静态方法的样式丢失问题

创建组件:MyContainer,参考:官网解决方式


import { App } from 'antd';
import type { MessageInstance } from 'antd/es/message/interface';
import type { ModalStaticFunctions } from 'antd/es/modal/confirm';
import type { NotificationInstance } from 'antd/es/notification/interface';

let message: MessageInstance;
let notification: NotificationInstance;
let modal: Omit<ModalStaticFunctions, 'warn'>;

export default function MyContainer({ children }: { children: React.ReactNode }) {
    const staticFunction = App.useApp();

    message = staticFunction.message;
    modal = staticFunction.modal;
    notification = staticFunction.notification;

    return children;
}

export { message, modal, notification };

1.1 解决非静态的样式兼容

我们创建组件:RootStyleRegistry

'use client';
import { createCache, extractStyle, legacyLogicalPropertiesTransformer, StyleProvider } from '@ant-design/cssinjs';
import { App } from 'antd';
import { useServerInsertedHTML } from 'next/navigation';
import { useState } from 'react';

import MyContainer from '.MyContainer';

export const RootStyleRegistry = ({ children }: { children: React.ReactNode }) => {
    const [cache] = useState(() => createCache());

    useServerInsertedHTML(() => {
        return (
            <script
                dangerouslySetInnerHTML={{
                    __html: `</script>${extractStyle(cache)}<script>`,
                }}
            />
        );
    });

    return (
        <StyleProvider cache={cache} hashPriority="high" transformers={[legacyLogicalPropertiesTransformer]}>
            <App>
                <MyContainer>{children}</MyContainer>
            </App>
        </StyleProvider>
    );
};

核心就两个部分:

  • hashPriority="high" transformers={[legacyLogicalPropertiesTransformer]},只要加上这两个属性,就可以解决大部分的组件兼容问题。
  • 用我们自己定义的MyContainer组件,包裹所有的页面组件,同时用App组件包裹。这部分则是解决弹出类组件的样式问题。

最后我们在根Layout中,进行包裹即可完成Nextjs中对于antd5的降级处理:

import { RootStyleRegistry } from './RootStyleRegistry'
export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) {
  return (
    <html lang="en">
      <body>
        <RootStyleRegistry>
          {children}
        </RootStyleRegistry>
      </body>
    </html>
  );
}
;