From bab659f8bd2851ac675fb4c9906d848a933bc1fc Mon Sep 17 00:00:00 2001 From: Menghuan1918 Date: Wed, 12 Aug 2026 18:19:44 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=A2=E6=88=B7=E7=AB=AF=E6=87=92?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E5=88=86=E5=9D=97=20=E2=80=94=20=E9=87=8D?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=EF=BC=88Univer/xterm/CodeMirror/Office?= =?UTF-8?q?=EF=BC=89=E6=8B=86=E7=8B=AC=E7=AB=8B=20bundle=20=E6=8C=89?= =?UTF-8?q?=E9=9C=80=E4=B8=8B=E5=8F=91=EF=BC=88/sidebar/bundle=20=E8=B7=AF?= =?UTF-8?q?=E7=94=B1=20+=20=5F=5FdshChunks=5F=5F=20=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E8=A1=A8=EF=BC=89=EF=BC=8C=E6=A0=B8=E5=BF=83=E5=90=AF=E5=8A=A8?= =?UTF-8?q?=E4=BB=85=20~325KB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 1 + README.md | 1 + docs/plans/2026-08-12-lazy-chunks-design.md | 88 +++++++ package.json | 6 + scripts/package-registry.mjs | 12 + src/bundle-route.ts | 130 ++++++++++ src/client/builtins/tabs.tsx | 33 ++- src/client/builtins/viewers.tsx | 44 ++-- src/client/chunk-loader.ts | 196 +++++++++++++++ src/client/chunks/docx.tsx | 8 + src/client/chunks/editor.tsx | 9 + src/client/chunks/pptx.tsx | 8 + src/client/chunks/terminal.tsx | 9 + src/client/chunks/xlsx.tsx | 9 + src/client/docx-view.tsx | 113 +++++++++ src/client/index.tsx | 5 + src/client/lazy-chunk.tsx | 89 +++++++ src/client/office-shared.tsx | 40 +++ src/client/office-view.tsx | 257 +------------------- src/client/xlsx-view.tsx | 116 +++++++++ src/index.ts | 20 +- tests/browser-globals.ts | 7 +- tests/bundle-route.spec.ts | 148 +++++++++++ tests/chunk-artifact.spec.ts | 43 ++++ tests/chunk-loader.spec.ts | 210 ++++++++++++++++ tests/lazy-chunk.spec.tsx | 194 +++++++++++++++ tests/manifest-consistency.spec.ts | 22 +- tests/smoke.spec.ts | 2 +- tsdown.config.ts | 216 ++++++++++------ 29 files changed, 1691 insertions(+), 345 deletions(-) create mode 100644 docs/plans/2026-08-12-lazy-chunks-design.md create mode 100644 src/bundle-route.ts create mode 100644 src/client/chunk-loader.ts create mode 100644 src/client/chunks/docx.tsx create mode 100644 src/client/chunks/editor.tsx create mode 100644 src/client/chunks/pptx.tsx create mode 100644 src/client/chunks/terminal.tsx create mode 100644 src/client/chunks/xlsx.tsx create mode 100644 src/client/docx-view.tsx create mode 100644 src/client/lazy-chunk.tsx create mode 100644 src/client/office-shared.tsx create mode 100644 src/client/xlsx-view.tsx create mode 100644 tests/bundle-route.spec.ts create mode 100644 tests/chunk-artifact.spec.ts create mode 100644 tests/chunk-loader.spec.ts create mode 100644 tests/lazy-chunk.spec.tsx diff --git a/AGENTS.md b/AGENTS.md index b909a41..dc6fd75 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -396,6 +396,7 @@ interface BetterSidebarService { | **host 半无此服务** | `ctx.betterSidebar` 只在 client 侧存在;host 半需要 better-sidebar 数据走 `/sidebar/api/*` HTTP 路由 | | **portal 限制** | 整面板 slot 由 ui-layout 独占,外部 tab 只能进入 better-sidebar 的 portal 内部,无法全屏替换 | | **id 冲突** | `registerTab` / `registerFileViewer` 对重复 id 抛错;建议用包前缀(`my-plugin:xxx`) | +| **懒加载 chunk** | 内置重依赖(Univer/xterm/CodeMirror/pptx/docx)在独立 bundle(`lib/client-.js`)中,经 `/sidebar/bundle` 路由按需下发;每个脚本把 factory 赋到插件自有全局注册表 `globalThis.__dshChunks__[]`,由 `src/client/chunk-loader.ts` 用自定义 require(externals 经 `__DSH_MODULES__` seed 分支解析)物化——**不经过** `__ModuleLoader__` 注册;**核心 bundle 禁止静态 import `src/client/chunks/*`**(会把库拖回启动路径);对消费插件透明——懒加载只作用于内置 descriptor,`component` 契约(`(props) => ReactNode` 纯渲染函数)不变 | --- diff --git a/README.md b/README.md index db1e883..6a6a8c4 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ - **🗂️ 资源管理器**:懒加载目录树(根 = 会话 cwd)、点击在侧边栏打开、行尾 `@文件` 引用到输入框、右键复制路径 - **📝 编辑与预览**:CodeMirror 6 多语言高亮 + Ctrl/Cmd+S 原子保存;图片 / Markdown(预览/编辑切换)/ HTML(沙箱 iframe 预览,相对资源可加载)/ PDF / Word / Excel / PPT 内联预览,切换 Tab 不丢草稿 +- **⚡ 客户端懒加载**:Office / 终端 / 代码编辑器等重依赖按需分块加载——启动只拉 ~325KB 核心,打开 .xlsx 才拉 Univer(~20MB)、打开 .docx 只拉 docx 预览器、打开终端才拉 xterm;首次打开短暂 loading 后即用(详见 `docs/plans/2026-08-12-lazy-chunks-design.md`) - **🌐 浏览器**:内嵌网页浏览 tab(多开),后退/前进/刷新 +「在浏览器中打开」;页面在**沙箱 iframe** 中运行(不透明源:无法访问界面数据与本地文件,拒绝 localhost 等本机地址),界面实时显示沙箱状态、可临时解锁(关闭时红色警示);被站点拒绝嵌入(X-Frame-Options)时显示原因面板;聊天/界面里的 http(s) 外链默认在侧边栏打开 - **💻 终端**:xterm.js + node-pty 真实 shell(每会话 3 个 UI 上限)、Tab 保活重连回放;可选为模型注入 8 个 `terminal_*` 工具 - **🌿 Git 面板**:真 diff + VSCode 式 diff tab、懒加载历史、右键暂存/放弃/提交/还原/捡取 diff --git a/docs/plans/2026-08-12-lazy-chunks-design.md b/docs/plans/2026-08-12-lazy-chunks-design.md new file mode 100644 index 0000000..0a81d9d --- /dev/null +++ b/docs/plans/2026-08-12-lazy-chunks-design.md @@ -0,0 +1,88 @@ +# 客户端懒加载分块(lazy chunks)设计 + +> 日期:2026-08-12 +> 状态:已实现 +> 范围:`dsh-better-sidebar` 插件,客户端 bundle 拆分 + +## 1. 背景与问题 + +改造前客户端是单文件 bundle(`lib/client.js`,约 24.6MB),页面启动时全部**下载 + 解析 + 执行**。实测构成(按 sourcemap 源字节): + +| 依赖 | 体积 | 用途 | +|---|---|---| +| `@univerjs/*` 全家桶 + echarts/zrender 等 | ~18MB | .xlsx 预览 | +| `@codemirror/*` + `@lezer/*` | ~1.9MB | 文本编辑器高亮 | +| `xlsx`(SheetJS) | ~0.6MB | .xlsx 解析 | +| `@aiden0z/pptx-renderer` | ~0.5MB | .pptx 预览 | +| `xterm` | ~0.3MB | 终端 | +| `docx-preview` + `jszip` | ~0.2MB | .docx 预览 | +| 插件自身代码 | ~0.35MB | — | + +虽然 `office-view.tsx` 用了动态 `import()`,但 `codeSplitting: false` 只保证**延迟执行**(`Promise.resolve().then(() => (init_docx_preview(), ...))`),下载与解析成本仍在启动时;且 `xlsx-to-univer.ts` 对 `@univerjs/presets` 的静态 value-import 让 Univer 核心实际在启动时执行。 + +**目标**:重依赖拆成独立脚本,首次打开对应功能才下载/解析/执行;启动只拉核心(~325KB)。 + +## 2. 机制 + +chunk 脚本**不经过** `window.__ModuleLoader__` / `ClientModuleSystem.import()` 的物化路径——模块系统的 import() 只解析 seed word / shell-own 模块 / 已注册 factory / boot graph row,chunk id 四者皆非,解析行为依赖 DSH 版本(实测某些版本在 factory 已注册时仍抛 "cannot resolve")。因此改为插件自有的全局 factory 注册表: + +1. **构建期**:每个 chunk 是独立 tsdown 浏览器 bundle(`lib/client-.js`),脚本首行为: + ```js + globalThis.__dshChunks__ = globalThis.__dshChunks__ || {}; + globalThis.__dshChunks__["terminal"] = (require) => { /* CJS 闭包体 */ }; + ``` + 与主 bundle 相同的 externals(react 等走 module table)、纯度门、CSS 内联管线;`codeSplitting: false` 保持单文件。 +2. **运行期** `loadChunk(name)`: + - 注入 `