Skip to content

Commit

Permalink
✨ feat: support App Router (#112)
Browse files Browse the repository at this point in the history
* ✨ feat: support app router

* 🔖 chore(release): v3.5.0-beta.1 [skip ci]


Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
  • Loading branch information
arvinxx and semantic-release-bot committed Sep 22, 2023
2 parents 94172c5 + a056e39 commit ca7e44f
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 6 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

# [3.5.0-beta.1](https://github.com/ant-design/antd-style/compare/v3.4.7...v3.5.0-beta.1) (2023-09-22)

### ✨ Features

- Support app router ([cf1d267](https://github.com/ant-design/antd-style/commit/cf1d267))

## [3.4.7](https://github.com/ant-design/antd-style/compare/v3.4.6...v3.4.7) (2023-09-20)

### 🐛 Bug Fixes
Expand Down
64 changes: 61 additions & 3 deletions docs/guide/ssr.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ SSR(Server-side rendering)是指在服务器端将动态生成的 HTML 直

## 在 Next.js 中集成

### Page Router

在 Next.js 的服务端渲染中,需要在组件的 getInitialProps 方法中使用 extractStaticStyle 提取静态样式,并将其添加到页面的 head 中。 具体使用示例如下:

```tsx | pure
Expand Down Expand Up @@ -61,7 +63,7 @@ class MyDocument extends Document {
export default MyDocument;
```

### 1. 引入并包裹 StyleProvider 组件,并将其包裹在需要提取静态样式的组件外层:
#### 1. 引入并包裹 StyleProvider 组件,并将其包裹在需要提取静态样式的组件外层:

将 enhanceApp 参数传入 renderPage 方法。enhanceApp 是一个函数,用于对 App 组件进行增强,这里我们将 App 组件包裹在 StyleProvider 组件中,以便提取静态样式。

Expand All @@ -80,7 +82,7 @@ const page = await ctx.renderPage({

其中,`cache` 字段挂载的是 `@ant-design/cssinjs` 的 cache 对象。

### 2. 使用 `extractStaticStyle` 方法提取静态样式
#### 2. 使用 `extractStaticStyle` 方法提取静态样式

调用 renderPage 方法得到渲染后的页面内容,并使用 `extractStaticStyle` 方法提取出其中的静态样式。

Expand All @@ -99,7 +101,7 @@ const styleArr = extractStaticStyle(page.html);
| ids | `string[]` | 样式应用的元素 ID 数组 |
| tag | `string` | 带有 `<style>` 标签的 css 字符串 |

### 3. 将提取出的样式添加到页面的 head 中
#### 3. 将提取出的样式添加到页面的 head 中

由于 Nextjs 中需要直接插入 `<style>` 样式元素,我们从 `extractStaticStyle` 获得的样式对象数组中,取出 `style` 样式元素,将其添加到页面的 head 中即可。

Expand All @@ -111,6 +113,62 @@ return {
};
```

### App Router

:::info
需要 antd-style v3.5.0 以上版本
:::

[App Router](https://nextjs.org/docs/app) 是 Next.js 在 13.4 版本中正式完备的应用模式。 antd-style 也支持了这种模式。 接入方式如下:

创建一个 `StyleRegistry.tsx` 组件,用于收集提取静态样式并插入到 html 中:

```tsx | pure
'use client';

import { StyleProvider, extractStaticStyle } from 'antd-style';
import { useServerInsertedHTML } from 'next/navigation';
import { PropsWithChildren, useRef } from 'react';

const StyleRegistry = ({ children }: PropsWithChildren) => {
const isInsert = useRef(false);

useServerInsertedHTML(() => {
// 避免多次渲染时重复插入样式
// refs: https://github.com/vercel/next.js/discussions/49354#discussioncomment-6279917
if (isInsert.current) return;

isInsert.current = true;

const styles = extractStaticStyle().map((item) => item.style);

return <>{styles}</>;
});

return <StyleProvider cache={extractStaticStyle.cache}>{children}</StyleProvider>;
};

export default StyleRegistry;
```

`app/layout.tsx` 中引入该组件:

```tsx | pure
import StyleRegistry from './StyleRegistry';

const RootLayout = ({ children }: PropsWithChildren) => (
<html lang="en">
<body>
<StyleRegistry>{children}</StyleRegistry>
</body>
</html>
);
```

:::warning
由于 Next.js 的 App Router 缺少获取 html 的钩子, `extractStaticStyle` 无法分析出当前应用中使用的样式,因此 App Router 引入的样式体积会比 Page Router 大一些。
:::

## 与 dumi 集成

在本示例中,将抽取样式到 css 静态文件,然后在 html 中引入。
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "antd-style",
"version": "3.4.7",
"version": "3.5.0-beta.1",
"description": "a css-in-js solution for application combine with antd v5 token system and emotion",
"keywords": [
"antd",
Expand Down
16 changes: 14 additions & 2 deletions src/functions/extractStaticStyle.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { createCache, extractStyle } from '@ant-design/cssinjs';
import CacheEntity from '@ant-design/cssinjs/es/Cache';
import { EmotionCache } from '@emotion/css/create-instance';
import { version } from 'antd';

const createExtractCriticalWithoutHtml = (cache: EmotionCache) => ({
ids: Object.keys(cache.inserted),
css: Object.values(cache.inserted)
.filter((i) => typeof i === 'string')
.join(''),
});

/**
* 表示一个样式项
*/
Expand Down Expand Up @@ -41,12 +49,13 @@ interface ExtractStyleOptions {
*/
antdCache?: CacheEntity;
}

/**
* Extract Static style
* @param html html page string
* @param options
*/
export const extractStaticStyle = (html: string, options?: ExtractStyleOptions): StyleItem[] => {
export const extractStaticStyle = (html?: string, options?: ExtractStyleOptions): StyleItem[] => {
const shouldExtreactAntdStyle =
typeof options?.includeAntd !== 'undefined' ? options.includeAntd : true;

Expand Down Expand Up @@ -74,7 +83,10 @@ export const extractStaticStyle = (html: string, options?: ExtractStyleOptions):
const styles = global.__ANTD_STYLE_CACHE_MANAGER_FOR_SSR__.getCacheList().map((cache) => {
const createEmotionServer = require('@emotion/server/create-instance').default;

const result = createEmotionServer(cache).extractCritical(html);
const result: { ids: string[]; css: string } = !html
? createExtractCriticalWithoutHtml(cache)
: createEmotionServer(cache).extractCritical(html);

if (!result.css) return null;

const { css, ids } = result;
Expand Down

0 comments on commit ca7e44f

Please sign in to comment.