Skip to content

Commit 969d24b

Browse files
CodFrmclaude
andcommitted
⚡ 优化列表页数据量:裁剪冗余字段,base64 icon 改为代理接口
- 新增 script-slim.ts,SSR 层裁剪 ScriptListItem 只保留渲染所需字段 - 搜索页和用户页 SSR 数据经裁剪后再传给客户端组件 - base64 data URI 图标替换为 /api/v2/scripts/:id/icon 代理 URL,避免内联大体积数据 - icon URL 附加 ?t=updatetime 参数实现缓存失效 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 16d4fbb commit 969d24b

3 files changed

Lines changed: 99 additions & 4 deletions

File tree

src/app/[locale]/search/page.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Row, Col } from 'antd';
22
import Sidebar from '@/components/Sidebar';
33
import ScriptList from '@/components/Scriptlist';
44
import { scriptService } from '@/lib/api/services/scripts';
5+
import { slimScriptList, slimScriptListForSidebar } from '@/lib/utils/script-slim';
56
import type { ScriptSearchRequest } from '../script-show-page/[id]/types';
67
import type { Metadata } from 'next';
78
import { getTranslations } from 'next-intl/server';
@@ -66,7 +67,7 @@ export default async function SearchPage({ searchParams }: SearchPageProps) {
6667
<Col xs={24} lg={18}>
6768
{/* 搜索区域 */}
6869
<ScriptList
69-
scripts={scripts.list}
70+
scripts={slimScriptList(scripts.list)}
7071
totalCount={scripts.total}
7172
initialFilters={apiParams}
7273
initialPage={apiParams.page || 1}
@@ -76,8 +77,8 @@ export default async function SearchPage({ searchParams }: SearchPageProps) {
7677
{/* 侧边栏 */}
7778
<Col xs={24} lg={6}>
7879
<Sidebar
79-
recentScripts={recentScripts.list}
80-
ratingScripts={ratingScripts.list}
80+
recentScripts={slimScriptListForSidebar(recentScripts.list)}
81+
ratingScripts={slimScriptListForSidebar(ratingScripts.list)}
8182
/>
8283
</Col>
8384
</Row>

src/app/[locale]/users/[id]/page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import UserScriptList from '@/components/UserProfile/UserScriptList';
22
import scriptService from '@/lib/api/services/scripts';
3+
import { slimScriptList } from '@/lib/utils/script-slim';
34
import type { ScriptSearchRequest } from '../../script-show-page/[id]/types';
45
import { Suspense } from 'react';
56

@@ -35,7 +36,7 @@ export default async function UserPage({
3536
<Suspense fallback={<div>{'Loading script...'}</div>}>
3637
<UserScriptList
3738
userId={userId}
38-
scripts={scripts.list}
39+
scripts={slimScriptList(scripts.list)}
3940
totalCount={scripts.total}
4041
initialFilters={apiParams}
4142
initialPage={apiParams.page || 1}

src/lib/utils/script-slim.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import type {
2+
Metadata,
3+
ScriptListItem,
4+
} from '@/app/[locale]/script-show-page/[id]/types';
5+
6+
/**
7+
* 裁剪 meta_json,只保留列表渲染需要的字段:
8+
* - icon / iconURL(图标)— base64 data URI 替换为后端代理 URL
9+
* - name:* / description:*(i18n 本地化名称和描述)
10+
*
11+
* @param scriptId 脚本 ID,用于生成 icon 代理 URL
12+
* @param updatetime 脚本更新时间,附加到 icon URL 用于缓存失效
13+
*/
14+
function slimMetaJson(meta: Metadata, scriptId?: number, updatetime?: number): Metadata {
15+
if (!meta) return {} as Metadata;
16+
17+
const slim: Record<string, string[]> = {};
18+
for (const key of Object.keys(meta)) {
19+
if (
20+
key === 'icon' ||
21+
key === 'iconURL' ||
22+
key.startsWith('name:') ||
23+
key.startsWith('description:')
24+
) {
25+
slim[key] = meta[key];
26+
}
27+
}
28+
29+
// 将 base64 data URI 替换为后端 icon 代理接口 URL
30+
if (scriptId) {
31+
const iconKey = slim['icon'] ? 'icon' : slim['iconURL'] ? 'iconURL' : null;
32+
if (iconKey && slim[iconKey]?.[0]?.startsWith('data:')) {
33+
const t = updatetime ? `?t=${updatetime}` : '';
34+
slim[iconKey] = [`/api/v2/scripts/${scriptId}/icon${t}`];
35+
}
36+
}
37+
38+
return slim as Metadata;
39+
}
40+
41+
/**
42+
* 裁剪 ScriptListItem 列表,只保留 ScriptCard 渲染所需字段。
43+
* 用于 search/page.tsx 和 users/[id]/page.tsx 等 SSR 页面,
44+
* 减少序列化到 HTML 中的数据量。
45+
*/
46+
export function slimScriptList(list: ScriptListItem[]): ScriptListItem[] {
47+
return list.map(
48+
(item) =>
49+
({
50+
id: item.id,
51+
user_id: item.user_id,
52+
username: item.username,
53+
avatar: item.avatar,
54+
name: item.name,
55+
description: item.description,
56+
category: item.category
57+
? { id: item.category.id, name: item.category.name }
58+
: item.category,
59+
tags: item.tags?.map((t) => ({ id: t.id, name: t.name })),
60+
score: item.score,
61+
score_num: item.score_num,
62+
type: item.type,
63+
public: item.public,
64+
today_install: item.today_install,
65+
total_install: item.total_install,
66+
updatetime: item.updatetime,
67+
script: {
68+
version: item.script.version,
69+
meta_json: slimMetaJson(item.script.meta_json, item.id, item.updatetime),
70+
},
71+
}) as ScriptListItem,
72+
);
73+
}
74+
75+
/**
76+
* 裁剪 ScriptListItem 列表,只保留侧边栏 ScriptListCard 所需的最少字段:
77+
* - id, name(标题和链接)
78+
* - script.meta_json 中的 icon/iconURL(图标)
79+
*/
80+
export function slimScriptListForSidebar(
81+
list: ScriptListItem[],
82+
): ScriptListItem[] {
83+
return list.map(
84+
(item) =>
85+
({
86+
id: item.id,
87+
name: item.name,
88+
script: {
89+
meta_json: slimMetaJson(item.script.meta_json, item.id, item.updatetime),
90+
},
91+
}) as ScriptListItem,
92+
);
93+
}

0 commit comments

Comments
 (0)