Skip to content

feat: 优化同步数据结构 — 来源追溯 + 动态回填,减少 Supabase 存储 80%#263

Open
didyhu wants to merge 3 commits into
zyronon:masterfrom
didyhu:feat/sync-optimization-and-traceability
Open

feat: 优化同步数据结构 — 来源追溯 + 动态回填,减少 Supabase 存储 80%#263
didyhu wants to merge 3 commits into
zyronon:masterfrom
didyhu:feat/sync-optimization-and-traceability

Conversation

@didyhu
Copy link
Copy Markdown

@didyhu didyhu commented May 8, 2026

概述

将特殊词库(收藏、错词、已掌握)的存储模型从"全量副本"改为"引用 + 按需回填"。
实测单行 JSON 体积可从 2.36MB 降至 ~0.5MB,降幅约 80%。

方案

  1. 来源追溯 — Word 类型新增 sourceDictId,收藏/错词/已掌握时自动注入当前词典 ID
  2. 智能瘦身 — shakeCommonDict() 对同步数据分级处理:
    • 有 sourceDictId:极致瘦身(仅保留 word/id/sourceDictId,删全部详情)
    • 无来源(旧数据/自定义词):平衡瘦身(保留 trans/phonetic/sentences)
  3. 动态回填 — 新增 useWordHydrator,展示时从本地词典回填详情;词典不可用时展示提示引导用户下载

涉及文件

文件 变更
packages/core/src/types/types.ts Word 类型新增 sourceDictId
packages/core/src/hooks/dict.ts 收藏/标记掌握时注入 sourceDictId
apps/nuxt/app/pages/(words)/practice-words/[id].vue 错词收集时注入 sourceDictId
packages/core/src/utils/index.ts shakeCommonDict 分级瘦身
packages/core/src/hooks/useWordHydrator.ts 新增:动态回填引擎
packages/core/src/components/word/WordItem.vue 触发回填 + 缺失时展示提示

兼容性

  • 旧同步数据:无 sourceDictId 的单词走平衡瘦身,旧版 app 仍可显示释义
  • 新同步数据:有 sourceDictId 的单词极致瘦身,旧版 app 仅显示单词名(不报错)
  • 下次同步自动优化:shakeCommonDict 在每次同步时执行,已有数据自动瘦身

测试

  • 收藏/错词/已掌握正常注入 sourceDictId
  • 同步前后 IndexedDB 与 Supabase 数据一致
  • 删除词典后列表仅显示单词名,展示下载 XX 查看释义提示
  • 点击提示跳转词典列表页
  • 旧数据(无 sourceDictId)正常显示
  • 离线模式正常

Closes #260

…ation

Replace full-copy word storage with a reference + backfill model:
- Add sourceDictId to Word type to trace word origin
- Auto-inject sourceDictId when collecting, marking wrong, or marking known
- Intelligently slim words before sync: extreme slimming for words with
  sourceDictId (details stripped), balanced for legacy/custom words
- New useWordHydrator composable rehydrates stripped words on display
  from locally available dictionaries
- When dict not available, show clickable placeholder "下载 XX 查看释义"
  instead of auto-downloading full dict JSON from CDN

Closes zyronon#260
Copilot AI review requested due to automatic review settings May 8, 2026 03:27
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

该 PR 通过“来源追溯 + 同步瘦身 + 展示时动态回填”的方式,减少 Supabase 同步数据中三类特殊词库(收藏/错词/已掌握)对完整 Word 详情的冗余存储,从而显著降低同步 payload 体积并保持可用性。

Changes:

  • Word 增加 sourceDictId,并在收藏/错词/已掌握写入时自动注入来源词典 ID。
  • 调整 shakeCommonDict():对特殊词库按是否有来源进行分级瘦身(有来源则极致瘦身,无来源则平衡瘦身)。
  • 新增 useWordHydratorWordItem 端的回填触发/缺失提示,引导用户下载对应词典查看释义。

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
packages/core/src/utils/index.ts 对特殊词库做分级瘦身以降低同步体积
packages/core/src/types/types.ts Word 类型新增 sourceDictId 用于来源追溯
packages/core/src/hooks/useWordHydrator.ts 新增动态回填逻辑,从本地词典按需补全详情
packages/core/src/hooks/dict.ts 收藏/已掌握操作时注入 sourceDictId
packages/core/src/components/word/WordItem.vue 列表项触发回填并在缺词典时展示跳转提示
apps/nuxt/app/pages/(words)/practice-words/[id].vue 记录错词时注入 sourceDictId

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +4 to +6
const dictCache: Record<string, Word[]> = {}
const pendingRequests: Record<string, Promise<Word[]>> = {}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Comment on lines +4 to +6
const dictCache: Record<string, Word[]> = {}
const pendingRequests: Record<string, Promise<Word[]>> = {}

Comment on lines +49 to +50
Object.assign(word, details)
}
Comment on lines +56 to +67
function goDictList() {
router.push('/dict-list')
}

onMounted(() => {
doHydrate(props.item)
})

watch(
() => props.item,
val => {
doHydrate(val)
Comment on lines +46 to +69
async function doHydrate(item: Word) {
const result = await hydrate(item)
if (!result.hydrated && result.dictName) {
hydrateFailed = true
missingDictName = result.dictName
} else if (result.hydrated) {
hydrateFailed = false
}
}

function goDictList() {
router.push('/dict-list')
}

onMounted(() => {
doHydrate(props.item)
})

watch(
() => props.item,
val => {
doHydrate(val)
}
)
Comment on lines +83 to +86
<TranslationList :pos-space="false" :word="item" :showFull="showWord" v-if="showTranslate && !hydrateFailed" />
<div v-else-if="showTranslate && hydrateFailed" class="missing-dict-hint" @click="goDictList">
下载 {{ missingDictName }} 查看释义
</div>
Comment on lines +21 to +47
const dictId = word.sourceDictId
let wordsData: Word[] = []

if (dictCache[dictId]) {
wordsData = dictCache[dictId]
} else if (pendingRequests[dictId]) {
wordsData = await pendingRequests[dictId]
} else {
// 检查用户已添加的词典中是否有已加载的单词数据
const store = useBaseStore()
const userDict = store.word.bookList.find(v => v.id === dictId)

if (userDict?.words?.length) {
dictCache[dictId] = userDict.words
wordsData = userDict.words
} else {
// 词典数据不可用:不自动下载,返回失败状态
const dictName = userDict?.name || dictId
return { hydrated: false, dictName }
}
}

if (wordsData.length > 0) {
const sourceWord = wordsData.find(
w => w.word.toLowerCase() === word.word.toLowerCase()
)
if (sourceWord) {
- Replace dictCache with indexed Map per dictId (O(1) lookup), validate
  dict still exists in bookList on each hydrate to prevent stale cache
- Remove dead pendingRequests variable
- Return hydrated=false when sourceWord not found in dictionary
- Skip hydration when showTranslate is false
- Add incrementing token to prevent race condition in async hydration
- Change missing-dict-hint from <div> to <button> for accessibility
@vercel
Copy link
Copy Markdown

vercel Bot commented May 14, 2026

@didyhu is attempting to deploy a commit to the zyronon's projects Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Optimization] 优化 Supabase 同步数据结构,减少特殊词库(已掌握、错词、收藏)的数据冗余

2 participants