Merge pull request #5570 from deepseek-harness/perf/trim-desktop-unused-assets

perf(desktop): trim Domino tooling and legacy KaTeX font formats
This commit is contained in:
07akioni authored and GitHub committed 2026-10-10 13:49:38 +08:00
commit db0210088b
13 files changed
+136 -8

No files matched your search

+2 -2
View File
@@ -51,8 +51,8 @@
en: 5f05072ec82cc62d
zh: a3d63b58d1ef2db7
/deepseek-harness-desktop/package/runtime-file-selection:
en: 4c83b25ef03d0c1b
zh: 6c97d8f485e2d6d0
en: 66898d7b99807291
zh: dfbbbb607ad2709f
/deepseek-harness-desktop/package/upload-updates:
en: f48baa680e841b0d
zh: 25ded1aeaac6dad1
+1 -1
View File
@@ -274,7 +274,7 @@ The served `time` is the real packing time, so pnpm 11's default 24-hour `minimu
### Runtime file selection
Desktop packs workspace packages locally and installs external dependencies through the target's bundled Node and pnpm. [Desktop's file policy](scripts/runtime-file-policy.ts) then filters the immutable `resources/app.asar/dsh/node_modules` copy before signing and integrity sealing. It omits TypeScript declarations, recognized JavaScript/CSS/TypeScript source maps, TypeScript build caches, Domino's test directory, selected native compiler outputs, and node-pty prebuilds for other platforms. Non-Windows targets also omit `node-pty/third_party/conpty`; Windows targets retain that directory. It preserves runtime JavaScript, target native modules and their DLL/EXE helpers, WASM, unknown assets, licenses, and notices. Dependency manifests pass through electron-builder's metadata cleanup before integrity sealing, so archiving preserves their recorded bytes. The policy does not alter npm tarballs, the bundled package manager, or user-installed plugin files.
Desktop packs workspace packages locally and installs external dependencies through the target's bundled Node and pnpm. [Desktop's file policy](scripts/runtime-file-policy.ts) then filters the immutable `resources/app.asar/dsh/node_modules` copy before signing and integrity sealing. It omits TypeScript declarations, recognized JavaScript/CSS/TypeScript source maps, TypeScript build caches, Domino's test directory and Yarn development metadata, selected native compiler outputs, and node-pty prebuilds for other platforms. Non-Windows targets also omit `node-pty/third_party/conpty`; Windows targets retain that directory. It preserves runtime JavaScript, target native modules and their DLL/EXE helpers, WASM, unknown assets, licenses, and notices. Dependency manifests pass through electron-builder's metadata cleanup before integrity sealing, so archiving preserves their recorded bytes. The policy does not alter npm tarballs, the bundled package manager, or user-installed plugin files.
The [Electron shell file list](scripts/electron-builder-config.mjs) excludes recognized JavaScript/CSS/TypeScript source maps and TypeScript build caches from the separate `resources/app.asar/node_modules` dependency collection. These exclusions preserve runtime code, native modules, WASM, data files (including ordinary `.map` assets), licenses, and notices; [shell archive tests](tests/shell-file-selection.spec.ts) check retained bytes and exclusions.
+1 -1
View File
@@ -276,7 +276,7 @@ pnpm run dev:bundle-registry
### 运行时文件筛选
Desktop 在本地打包工作区包,并通过目标捆绑的 Node 和 pnpm 安装外部依赖。[Desktop 文件策略](scripts/runtime-file-policy.ts)随后在签名和完整性封装前过滤不可变的 `resources/app.asar/dsh/node_modules` 副本。它排除 TypeScript 声明、已识别的 JavaScript/CSS/TypeScript source map、TypeScript 构建缓存、Domino 测试目录、选定的原生编译器输出和其他平台的 node-pty 预构建文件。非 Windows 目标还会排除 `node-pty/third_party/conpty`;Windows 目标保留该目录。它保留运行时 JavaScript、目标平台的原生模块及其 DLL/EXE 辅助文件、WASM、未知资源、许可证和 notices。依赖清单在完整性封装前经过 electron-builder 的元数据清理,确保归档保持已记录的字节。该策略不修改 npm tarball、捆绑的包管理器或用户安装的插件文件。
Desktop 在本地打包工作区包,并通过目标捆绑的 Node 和 pnpm 安装外部依赖。[Desktop 文件策略](scripts/runtime-file-policy.ts)随后在签名和完整性封装前过滤不可变的 `resources/app.asar/dsh/node_modules` 副本。它排除 TypeScript 声明、已识别的 JavaScript/CSS/TypeScript source map、TypeScript 构建缓存、Domino 测试目录及 Yarn 开发元数据、选定的原生编译器输出和其他平台的 node-pty 预构建文件。非 Windows 目标还会排除 `node-pty/third_party/conpty`;Windows 目标保留该目录。它保留运行时 JavaScript、目标平台的原生模块及其 DLL/EXE 辅助文件、WASM、未知资源、许可证和 notices。依赖清单在完整性封装前经过 electron-builder 的元数据清理,确保归档保持已记录的字节。该策略不修改 npm tarball、捆绑的包管理器或用户安装的插件文件。
[Electron 外壳文件清单](scripts/electron-builder-config.mjs)从单独收集的 `resources/app.asar/node_modules` 依赖中排除已识别的 JavaScript/CSS/TypeScript source map 和 TypeScript 构建缓存。这些排除规则保留运行时代码、原生模块、WASM、数据文件(包括普通 `.map` 资源)、许可证和 notices;[外壳归档测试](tests/shell-file-selection.spec.ts)检查保留文件的字节和排除项。
@@ -34,6 +34,7 @@ export function desktopRuntimeFileExclusion(
return 'fs-ext build configuration'
}
if (name === '@mixmark-io/domino' && (entry === 'test' || entry.startsWith('test/'))) return 'Domino test fixtures'
if (name === '@mixmark-io/domino' && (entry === '.yarn' || entry.startsWith('.yarn/'))) return 'Domino development tooling'
if (name === 'node-pty' && target.platform !== 'win32' && /^third_party\/conpty(?:\/|$)/u.test(entry)) {
return 'node-pty Windows ConPTY sources'
}
@@ -27,6 +27,8 @@ it('omits development artifacts while preserving executable modules, assets and
'node-pty/prebuilds/win32-x64/conpty.pdb',
'@koromix/koffi-win32-x64/win32_x64/koffi.lib',
'@mixmark-io/domino/test/entities.html',
'@mixmark-io/domino/.yarn/plugins/@yarnpkg/plugin-version.cjs',
'@mixmark-io/domino/.yarn/versions/release.yml',
'@deepseek-ai/libreoffice-kit-wasm/assets/soffice.data',
'@deepseek-ai/libreoffice-kit-darwin-arm64/bin/libreoffice-kit',
'.modules.yaml', '.pnpm-workspace-state-v1.json', '.bin/tool', '.pnpm/cache',
@@ -45,6 +47,8 @@ it('omits development artifacts while preserving executable modules, assets and
'node-pty/third_party/conpty/win10-x64/OpenConsole.exe',
'@koromix/koffi-win32-x64/win32_x64/koffi.node',
'@mixmark-io/domino/lib/HTMLParser.js', '@mixmark-io/domino/lib/EntityParser.js',
'@mixmark-io/domino/LICENSE', '@mixmark-io/domino/package.json',
'example/.yarn/runtime.cjs', '@mixmark-io/domino/.yarn-data.json',
'@img/sharp-win32-x64/lib/libvips-42.dll',
'@deepseek-ai/libreoffice-kit-win32-x64/bin/libreoffice-kit.exe',
'@deepseek-ai/libreoffice-kit-win32-x64/sources/core-source.json',
@@ -73,6 +77,8 @@ it('omits development artifacts while preserving executable modules, assets and
it('applies package-specific rules inside scoped and nested dependency containers', () => {
expect(desktopRuntimeFileExclusion('outer/node_modules/@mixmark-io/domino/test/data.html', windows, 'win32-x64')).toBeDefined()
expect(desktopRuntimeFileExclusion('outer/node_modules/@mixmark-io/domino/.yarn/plugin.cjs', windows, 'win32-x64')).toBeDefined()
expect(desktopRuntimeFileExclusion('@mixmark-io/domino/.yarn', windows, 'win32-x64')).toBeDefined()
expect(desktopRuntimeFileExclusion('outer\\node_modules\\node-pty\\prebuilds\\win32-arm64\\conpty.node', windows, 'win32-x64')).toBeDefined()
expect(desktopRuntimeFileExclusion('outer/node_modules/unrelated/test/data.html', windows, 'win32-x64')).toBeUndefined()
expect(desktopRuntimeFileExclusion('outer/fs-ext/build/Release/fs_ext.lib', windows, 'win32-x64')).toBeUndefined()
+33
View File
@@ -0,0 +1,33 @@
/** WOFF2-only KaTeX font sources for the Web and Desktop browser bundle. */
import { transform } from 'lightningcss'
import type { Plugin } from 'vite'
/**
* Select WOFF2 before Vite collects KaTeX font assets, preserving every face and layout rule.
* A face without WOFF2 rejects the build. Other packages' stylesheets are unchanged.
* @returns Vite stylesheet transform for the installed KaTeX distribution.
*/
export function katexWoff2Fonts(): Plugin {
return {
name: 'dsh-katex-woff2-fonts',
enforce: 'pre',
transform(code, id) {
if (!/\/node_modules\/katex\/dist\/katex(?:\.min)?\.css(?:\?|$)/u.test(id.replaceAll('\\', '/'))) return
const result = transform({
filename: id, code: Buffer.from(code), sourceMap: true,
visitor: { Rule: { 'font-face'(rule) {
const descriptors = rule.value.properties.filter(property => property.type === 'source')
if (descriptors.length === 0) throw new Error('KaTeX font face requires a WOFF2 source')
for (const property of descriptors) {
const sources = property.value.filter(source => source.type === 'url' && source.value.format?.type === 'woff2')
if (sources.length === 0) throw new Error('KaTeX font face requires a WOFF2 source')
property.value = sources
}
return rule
} } },
})
return { code: result.code.toString(), map: result.map?.toString() }
},
}
}
+75
View File
@@ -0,0 +1,75 @@
import { readFile, mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'
import { createRequire } from 'node:module'
import { tmpdir } from 'node:os'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { transform } from 'lightningcss'
import { build, loadConfigFromFile } from 'vite'
import { expect, it, onTestFinished } from 'vitest'
const require = createRequire(new URL('../../../packages/client/ui-primitives/package.json', import.meta.url))
const stylesheet = require.resolve('katex/dist/katex.min.css')
/** Build a stylesheet with the application's asset plugins without writing artifacts. */
async function bundleStyle(source: { path: string } | { package: string; css: string }) {
const root = await mkdtemp(join(tmpdir(), 'katex-fonts-'))
onTestFinished(() => rm(root, { recursive: true, force: true }))
let input: string
if ('path' in source) input = source.path
else {
input = join(root, 'node_modules', source.package, 'dist', 'katex.min.css')
await mkdir(dirname(input), { recursive: true })
await writeFile(input, source.css)
await writeFile(join(dirname(input), 'font.woff'), 'fixture font')
}
const loaded = await loadConfigFromFile({ command: 'build', mode: 'production' }, fileURLToPath(new URL('../vite.config.ts', import.meta.url)))
if (!loaded) throw new Error('Expected the Web build configuration')
// The product isolation check requires the full application's HTML entry.
const plugins = (loaded.config.plugins ?? []).flat().filter(plugin => !(plugin && typeof plugin === 'object'
&& 'name' in plugin && plugin.name === 'dsh-product-web-bundle-isolation'))
const result = await build({
...loaded.config, configFile: false, plugins,
root, logLevel: 'silent',
build: { write: false, cssMinify: false, assetsInlineLimit: 0, rollupOptions: { input } },
})
if ('on' in result) throw new Error('Expected a completed build')
return (Array.isArray(result) ? result : [result]).flatMap(bundle => bundle.output)
}
/** Normalize layout CSS independently of emitted font URLs and format fallbacks. */
function layoutCss(css: string): string {
return transform({
filename: 'layout.css', code: Buffer.from(css), minify: true,
visitor: { Rule: { 'font-face'(rule) {
rule.value.properties = rule.value.properties.filter(property => property.type !== 'source')
return rule
} } },
}).code.toString()
}
it('ships all KaTeX WOFF2 faces with identical font bytes and layout styles', async () => {
const output = await bundleStyle({ path: stylesheet })
const fonts = output.filter(asset => asset.type === 'asset' && /\.(?:woff2?|ttf)$/u.test(asset.fileName))
expect(fonts).toHaveLength(20)
for (const font of fonts) {
expect(font.fileName).toMatch(/\.woff2$/u)
if (font.type !== 'asset') throw new Error('Expected a font asset')
const name = font.names[0]!
expect(Buffer.from(font.source)).toEqual(await readFile(join(dirname(stylesheet), 'fonts', name)))
}
const css = output.find(asset => asset.type === 'asset' && asset.fileName.endsWith('.css'))
if (css?.type !== 'asset') throw new Error('Expected a stylesheet asset')
const text = Buffer.from(css.source).toString()
expect(text).not.toMatch(/\.(?:woff|ttf)["')]/u)
expect(layoutCss(text)).toBe(layoutCss(await readFile(stylesheet, 'utf8')))
})
it.each(['src: url(font.woff) format("woff");', ''])('rejects a KaTeX face without WOFF2 (src=%s)', async (source) => {
await expect(bundleStyle({ package: 'katex', css: `@font-face { font-family: KaTeX_Main; ${source} }` }))
.rejects.toThrow('KaTeX font face requires a WOFF2 source')
})
it('preserves older font formats in unrelated stylesheets', async () => {
const output = await bundleStyle({ package: 'other', css: '@font-face { font-family: Other; src: url(font.woff) format("woff"); }' })
expect(output.some(asset => asset.type === 'asset' && asset.fileName.endsWith('.woff'))).toBe(true)
})
+7
View File
@@ -122,6 +122,13 @@ describe('web e2e: settled Markdown math rendering', () => {
await expect.poll(() => page.locator('.katex').count(), { timeout: 10_000 }).toBe(6)
await expect.poll(() => page.locator('.katex-display').count(), { timeout: 10_000 }).toBe(2)
expect(await page.locator('.katex-error').count()).toBe(0)
const fonts = await page.evaluate(async () => {
const faces = [...document.fonts].filter(face => face.family.includes('KaTeX_'))
await Promise.all(faces.map(face => face.load()))
return faces.map(face => face.status)
})
expect(fonts).toHaveLength(20)
expect(fonts.every(status => status === 'loaded')).toBe(true)
await expect.poll(
() => page.getByText('1 turns 1 steps', { exact: false }).count(),
{ timeout: 10_000 },
+3 -2
View File
@@ -6,6 +6,7 @@ import type { Plugin } from 'vite'
import react from '@vitejs/plugin-react'
import { clientBuildEnvironmentDefines } from '../../scripts/client-build-environment.ts'
import { productWebBundleIsolation } from './product-isolation.ts'
import { katexWoff2Fonts } from './katex-fonts.ts'
const src = (rel: string): string => fileURLToPath(new URL(rel, import.meta.url))
const STANDALONE_ERROR = 'apps/web is not a standalone application: bare Vite cannot inject window.__DSH_BOOT__. '
@@ -149,7 +150,7 @@ const BOOT_GRAMMAR_FILES: readonly string[] = [
'dist/json.mjs',
]
/** Font asset extensions routed to assets/fonts/ (KaTeX's woff2/woff/ttf faces). */
/** Font asset extensions routed to assets/fonts/. */
const FONT_EXTENSIONS: readonly string[] = ['.woff2', '.woff', '.ttf']
/**
@@ -170,7 +171,7 @@ export default defineConfig({
// directory, and the served index resolves identically from the site root.
base: './',
plugins: [
rejectStandaloneServe(), clientDocumentTitle(), brandFontLicense(), react(), emitPreviewPage(),
rejectStandaloneServe(), clientDocumentTitle(), brandFontLicense(), katexWoff2Fonts(), react(), emitPreviewPage(),
productWebBundleIsolation(src('../..'), src('.')),
],
build: {
+2 -2
View File
@@ -15,8 +15,8 @@
en: d152484eb41ac6b4
zh: 09388d293f9be9cb
/deepseek-ai-dsh-client-web/use-this-package:
en: 0c8b98946feedb0f
zh: ae10ae7b9ecbf89c
en: 8778e166024b9628
zh: 777d6923db199337
/deepseek-ai-dsh-client-web/use-this-package/what-boot-looks-like:
en: f3b01aa878764e5c
zh: f02eab65d441bfe0
+2
View File
@@ -31,6 +31,8 @@ Static application pages install `__DSH_BOOT_READY__` before the entry runs. The
The shell base styles apply automatic CJK/Latin spacing to ordinary content in supporting browsers. Semantic code and terminal, diff, read, and search output containers retain literal source spacing and column alignment; browsers without `text-autospace` support ignore both declarations.
Web and Desktop mathematical rendering requires WOFF2 support. The [Web build](../../../apps/web/katex-fonts.ts) retains every KaTeX font face in WOFF2 and omits WOFF/TTF fallbacks; a face without WOFF2 rejects the build. Font glyphs, weights, styles, and layout rules are preserved.
### What boot looks like
Boot runs in two stages: the module stage adopts the parser-loaded bootstrap batch, builds the module system from the Host-provided boot graph, and prefetches the `immediately` tier through the shared application-batch URL, which executes once. The plugin stage then activates every graph entry and waits for all of them before handing the marked boot DOM to the UI renderer, which hydrates it and switches to the complete UI.
+2
View File
@@ -31,6 +31,8 @@ kind: "package-library"
外壳基础样式会在支持的浏览器中为普通内容自动添加中西文间距。语义化代码以及终端、diff、读取和搜索输出容器会保留源码中的原始间距和列对齐;不支持 `text-autospace` 的浏览器会忽略这两项声明。
Web 和 Desktop 的数学公式渲染要求支持 WOFF2。[Web 构建](../../../apps/web/katex-fonts.ts)以 WOFF2 保留全部 KaTeX 字体样式,并排除 WOFF/TTF 后备格式;任一字体样式缺少 WOFF2 都会使构建失败。字体的字形、字重、样式和布局规则保持不变。
### 启动过程是怎样的
启动分两个阶段:模块阶段接纳 parser 已加载的 bootstrap 批次,从 Host 提供的启动图构建模块系统,并通过只执行一次的共享 application 批次 URL 预取 `immediately` 层级。插件阶段随后激活每个图 entry 并等待全部就绪,之后才把带标记的启动 DOM 交给 UI 渲染器,由它 hydrate 并切换到完整 UI。
+1
View File
@@ -11,6 +11,7 @@
"apps/web/tests/collapse-timing.e2e.ts",
"apps/web/tests/chat-flow-layout.e2e.ts",
"apps/web/product-isolation.ts",
"apps/web/katex-fonts.ts",
"apps/web/tests/connection-recovery.e2e.ts",
"apps/web/tests/server-restart.e2e.ts",
"apps/web/tests/shortcuts.e2e.ts",