Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat no ssr cache #6258

Merged
merged 3 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/violet-islands-sniff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@modern-js/runtime': minor
'@modern-js/server-core': minor
---

feat: support <NoSSRCache> Component, only use ssr.mode='string'

feat: 支持 <NoSSRCache> 组件, 仅在 ssr.mode 为 'string'的时候生效
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
title: NoSSRCache
---
# NoSSRCache

With the NoSSRCache component, Modern.js does not cache the server-side rendering (SSR) results of the current page.

:::note
This component is currently only available if `ssr.mode` is `string`.
:::

## Usage

```tsx
import { NoSSRCache } from '@modern-js/runtime/ssr';

export default () => {
return (
<div>
<NoSSRCache />
...
</div>
);
}
```

## Example

In the following code, after using `useLoaderData` to fetch data, the current page is cached or not based on the data fetched. For this case, use `NoSSRCache`:

```tsx
import { useLoaderData } from '@modern-js/runtim/router';
import { NoSSRCache } from '@modern-js/runtime/ssr';

function User() {
const { data } = useLoaderData();
return (
<div>
{ !data ? <NoSSRCache /> : null }
...
</div>
);
}
```

## Scene

This can be used if you need to decide whether the current page needs to cache the server-side rendering (SSR) results based on the current page fetching the data (e.g., whether the request was successful or whether a field exists in the returned result).
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
title: NoSSRCache
---
# NoSSRCache

使用了 NoSSRCache 组件后,Modern.js 不会将当前页面的服务器端渲染(SSR)结果进行缓存。

:::note
该组件目前仅在 `ssr.mode` 为 `string` 的情况可以使用。
:::

## 使用姿势

```tsx
import { NoSSRCache } from '@modern-js/runtime/ssr';

export default () => {
return (
<div>
<NoSSRCache />
...
</div>
);
}
```

## 示例

下列代码中,使用 `useLoaderData` 获取数据后,根据请求数据的结果决定是否缓存当前页面的服务端渲染结果。针对这种情况可以使用 `NoSSRCache` 组件:

```tsx
import { useLoaderData } from '@modern-js/runtim/router';
import { NoSSRCache } from '@modern-js/runtime/ssr';

function User() {
const { data } = useLoaderData();
return (
<div>
{ !data ? <NoSSRCache /> : null }
...
</div>
);
}
```

## 使用场景

如果需要根据当前页面获取数据的情况(比如是否请求成功或者返回结果中是否存在某个字段),决定是否需要将当前页面的服务端渲染(SSR)结果进行缓存,则可以使用这种方式来解决。
2 changes: 1 addition & 1 deletion packages/runtime/plugin-runtime/src/core/server/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Plugin } from '../plugin';

// react component
export { PreRender, NoSSR } from './react';
export { PreRender, NoSSR, NoSSRCache } from './react';

export const ssr = (_config: any): Plugin => ({
name: '@modern-js/plugin-ssr',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { PreRender } from './prerender';
export { NoSSR } from './nossr';
export { NoSSRCache } from './no-ssr-cache';
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import { Helmet } from '../../../../exports/head';

export const NoSSRCache = () => {
return (
<Helmet>
<meta name="no-ssr-cache" />
</Helmet>
);
};
6 changes: 4 additions & 2 deletions packages/server/core/src/plugins/render/ssrCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ interface CacheStruct {
}

const ZERO_RENDER_LEVEL = /"renderLevel":0/;
const NO_SSR_CACHE = /<meta\s+[^>]*name=["']no-ssr-cache["'][^>]*>/i;

export type CacheStatus = 'hit' | 'stale' | 'expired' | 'miss';

Expand Down Expand Up @@ -53,8 +54,9 @@ async function processCache({
const push = () =>
reader.read().then(({ done, value }) => {
if (done) {
const match = ZERO_RENDER_LEVEL.test(html);
// We should not cache the html, if we can match the html is downgrading.
const match = ZERO_RENDER_LEVEL.test(html) || NO_SSR_CACHE.test(html);
// case 1: We should not cache the html, if we can match the html is downgrading.
// case 2: We should not cache the html, if the user's code contains <NoSSRCache>.
if (match) {
writer.close();
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Outlet } from '@modern-js/runtime/router';
import { NoSSRCache } from '@modern-js/runtime/ssr';

export default function Layout() {
return (
<div>
No SSR Cache layout
<NoSSRCache />
{<Outlet />}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Outlet } from '@modern-js/runtime/router';

export default function Page() {
return (
<div>
No SSR Cache
<Outlet />
</div>
);
}
15 changes: 15 additions & 0 deletions tests/integration/ssr/tests/base.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,19 @@ describe('Traditional SSR', () => {
const { headers } = response;
expect(Boolean(headers['x-render-cache'])).toBeTruthy();
});

test('no ssr cache', async () => {
await page.goto(`http://localhost:${appPort}/no-ssr-cache`, {
waitUntil: ['networkidle0'],
});
const content = await page.content();
const result = content.match(/count:(\d+)/)![0];

// twice visit, because the no-ssr-cache, the count is different.
await page.goto(`http://localhost:${appPort}/no-ssr-cache`, {
waitUntil: ['networkidle0'],
});
const content1 = await page.content();
expect(content1).not.toMatch(result);
});
});
Loading