From ec35400249ca38746d8eb4a9249a2fcdb001616a Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Tue, 1 Sep 2026 00:49:56 -0600 Subject: [PATCH] =?UTF-8?q?perf(=E9=A6=96=E9=A1=B5):=20=E5=8D=8F=E4=BD=9C?= =?UTF-8?q?=E5=BC=B9=E6=A1=86=E6=94=B9=E5=BC=82=E6=AD=A5=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=EF=BC=8C=E9=A6=96=E5=B1=8F=20JS=20=E5=B0=91=E4=B8=89=E5=88=86?= =?UTF-8?q?=E4=B9=8B=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CollabHost 静态 import CollabModal,把整套 CodeMirror(view / state / language / autocomplete / lang-*)拖进了入口 chunk,而那个组件是 v-if="isTeacher" 的——学生根本不渲染,字节却人人下、人人解析。改成 defineAsyncComponent 之后: 入口 eager JS 1355 KB → 717 KB(gzip 447 → 234) 首页 JS 总量 1923 KB → 1285 KB(gzip 642 → 428) 机房那批 Chrome 91 省下的不只是下载,还有六百多 KB 的解析。老师端代价 是第一次接单时多一次 chunk 请求。 顺带修掉题目列表的重复请求:onMounted 拉一次,profile 回来时那个 watch 又拉一次。但请求本来就带 cookie(withCredentials),后端 optionalAuth 认的也是 cookie,首屏那一份的状态列本来就是全的。watcher 改成拿 storage 里的登录态做基线,只在登录态真的变了才补拉。 这条在本机复现不了(/api/me 1ms 就回,路由 chunk 还没挂载完),给 preview 代理的 /api/me 加 300ms 延迟、用 production 构建验证:改前 /problems 发两遍,改后一遍且状态列有值,登录/退出两个切换仍各触发 一次重拉。 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Tj3959yNB2srvc1oL3PaZH --- apps/web/src/oj/problem/list.vue | 19 ++++++++++++++----- apps/web/src/shared/components/CollabHost.vue | 14 +++++++++++++- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/apps/web/src/oj/problem/list.vue b/apps/web/src/oj/problem/list.vue index 6194d5c..32516b2 100644 --- a/apps/web/src/oj/problem/list.vue +++ b/apps/web/src/oj/problem/list.vue @@ -3,6 +3,8 @@ import { Icon } from "@iconify/vue" import { NFlex, NTag } from "naive-ui" import { useRouteQuery } from "@vueuse/router" import { getProblemList } from "oj/api" +import { STORAGE_KEY } from "utils/constants" +import storage from "utils/storage" import { getTagColor } from "utils/functions" import type { ProblemFiltered, Tag as ContractTag } from "utils/types" import { getProblemTagList } from "shared/api" @@ -129,12 +131,19 @@ watch( }, ) +// 这里只补「用登录框登进来」那一下:那时页面不刷新,列表还是匿名时拉的。 +// +// 进站时的那次 listProblems 不需要它跟着再来一遍 —— 请求带 cookie(axios 开了 +// withCredentials),后端 optionalAuth 认的也是 cookie,所以首屏那一份里状态列 +// 本来就是全的。基线取 storage 里的登录态,它和 cookie 同生共死,正好用来区分 +// 「profile 回来了,还是原来那个人」和「刚登进来 / 刚退出去」。 +let authedAtLoad: boolean = storage.get(STORAGE_KEY.AUTHED) ?? false watch( - () => userStore.isFinished && userStore.isAuthed, - (isAuthenticatedAndFinished) => { - if (isAuthenticatedAndFinished) { - listProblems() - } + () => [userStore.isFinished, userStore.isAuthed], + ([isFinished, isAuthed]) => { + if (!isFinished || isAuthed === authedAtLoad) return + authedAtLoad = isAuthed + listProblems() }, ) diff --git a/apps/web/src/shared/components/CollabHost.vue b/apps/web/src/shared/components/CollabHost.vue index fc00137..f5ce1b8 100644 --- a/apps/web/src/shared/components/CollabHost.vue +++ b/apps/web/src/shared/components/CollabHost.vue @@ -1,7 +1,6 @@