@composy/longpress
@composy/longpress
V21 UI 与默认文档升级:完整展示站见
playground/README.md,30 页功能目录、指南、API 和示例与初始化脚手架同步;搜索props初始化报错修复及验证指南见docs/V21_PRODUCT_SHOWCASE.md。
Playground 独立 Vue/React iframe 构建与安全限制:参见 V20 隔离构建说明。
Longpress 是 LDesign 生态中的现代文档系统,基于 Vue 3、Vite、TypeScript 和 Markdown 构建,面向组件库、工具链、业务 SDK 和团队规范站点。
V10 资源管理器(2026-10-10)
开发工作台「资源」面板现在支持名称/路径搜索、按图片/文档/音视频/字体分类、24 项分页、延迟加载图片缩略图和直接插入 Markdown。仍不提供文件删除或重命名。
后端旧 listAdminAssets(config, folder, limit) 保持兼容;新增可选第四参数:{ query, kind, cursor }。Bridge / REST GET /api/assets 同步支持筛选与游标,响应新增可选 nextCursor / scanLimited。目录枚举上限 3000 项,遇上限时结果可能不完整;应缩小资源目录或使用未来的增量索引。
上传服务端现在校验文件头与允许扩展名匹配;明显伪装的内容会拒绝并返回 HTTP 415。此校验不是恶意软件扫描或媒体完整解码。可运行 pnpm run check:assets 进行目录与文件头专项检查,详见 IMPLEMENTATION_V10_2026-10-10.md。
特性
- Markdown 增强:代码高亮、行号、复制、容器语法、任务列表、数学公式、Mermaid、ECharts。
- 主题系统:内置 default、paper、aurora、mono、catalog 主题,支持外观、密度、圆角、色彩预设和 CSS 变量覆盖。
- 插件系统:内置搜索、SEO、sitemap、版本、反馈、导出、PWA、REST API、AI 等插件能力。
- 文档体验:导航、侧栏、面包屑、右侧目录、阅读进度、相关页面、上下一页和搜索命中定位。
- 工具链:支持 dev、build、preview、workbench bridge,并可接入
@composy/launcher。 - LDesign Token 集成:所有颜色使用
packages/color生成的--ld-*CSS 变量,尺寸使用packages/size生成的--ld-*CSS 变量。
Class 命名规范
所有可见 DOM class 使用 ldesign-doc-* 前缀(BEM 风格):
/* 组件块 */
.ldesign-doc-layout {
}
.ldesign-doc-nav {
}
.ldesign-doc-sidebar {
}
/* 元素 */
.ldesign-doc-nav__logo {
}
.ldesign-doc-sidebar__item {
}
/* 修饰符 */
.ldesign-doc-nav--fixed {
}
.ldesign-doc-sidebar__item--active {
}
运行时保留 ldoc-* → ldesign-doc-* 的兼容别名,旧版主题消费者无需立即迁移。
CSS 变量 Token 约定
组件使用 --ldesign-doc-* CSS 变量,颜色默认引用 packages/color 生成的 --ld-* token:
:root {
/* 颜色:引用 packages/color token */
--ldesign-doc-c-bg: var(--ld-bg-page);
--ldesign-doc-c-text-1: var(--ld-text-primary);
--ldesign-doc-c-divider: var(--ld-border);
/* 尺寸:引用 packages/size token */
--ldesign-doc-space-md: var(--ld-spacing-md);
--ldesign-doc-radius-lg: var(--ld-radius-lg);
/* 组件自有值(无上游 token 时) */
--ldesign-doc-shadow-1: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
}
暗色模式下,--ld-* token 会自动切换为暗色值,组件变量无需重复覆盖。
安装
pnpm add @composy/longpress
ldoc 仍作为兼容别名保留;新项目和新文档优先使用 longpress。
CLI 命令
Longpress 提供完整文档站生命周期命令:
longpress init [root]
longpress dev [root]
longpress build [root]
longpress preview [root]
init 支持三类初始化目标:
- 已有项目:
longpress init . - 空目录:进入空目录后运行
longpress init . - 新建目录:
longpress init my-docs
常用初始化参数:
longpress init . --theme default --no-deploy
longpress init my-docs --name "My Docs" --deploy vercel
longpress init . --force
初始化会生成 .ldesign/doc.config.ts、.ldesign/docs/**,并在 package.json 中补充
docs:dev、docs:build、docs:preview 脚本。
静态输出与插件生命周期
longpress build
会为每个 Markdown 页面输出独立 HTML:页面正文、标题、描述以及 SEO 插件生成的 canonical、Open
Graph 和 JSON-LD 会直接写入对应页面。客户端运行时仍会在加载后接管交互,因此静态内容可被搜索引擎和禁用 JavaScript 的阅读环境直接读取。静态
.html 地址同时作为交互路由的别名,例如 /guide/getting-started.html 会加载
/guide/getting-started 的客户端页面并保留查询参数和锚点。
插件的 extendSiteData、extendPageData、extendRoutes、onBeforePageRender、
onAfterPageRender、generateBundle 和 onDestroy 均在对应生命周期执行。generateBundle
适合生成 sitemap、标签索引等依赖最终输出目录的产物。
程序化 API
import { createLDoc } from '@composy/longpress/node'
const ldoc = await createLDoc(process.cwd(), {
command: 'build',
mode: 'production',
})
ldoc.use(myPlugin)
const stopListening = ldoc.onUpdate(() => {
// 文件变化时执行
})
const page = await ldoc.getPageData('/guide/getting-started')
await ldoc.build() // 会等待通过 use() 注册的插件完成初始化
stopListening()
await ldoc.close() // 关闭服务器并按反向注册顺序调用插件 onDestroy
快速开始
// .ldesign/doc.config.ts
import { defineConfig } from '@composy/longpress'
export default defineConfig({
title: '我的文档',
description: '使用 Longpress 构建的文档站点',
lang: 'zh-CN',
theme: 'default',
themeConfig: {
nav: [
{ text: '指南', link: '/guide/getting-started' },
{ text: 'API', link: '/api/' },
],
sidebar: {
'/guide/': [
{
text: '指南',
items: [{ text: '快速开始', link: '/guide/getting-started' }],
},
],
},
},
})
pnpm longpress dev
pnpm longpress build
pnpm longpress preview
内容安全模式
默认 security.contentTrust 为
trusted,用于已经审核的仓库内容和内联组件。对包含用户提交 Markdown、评论或外部内容的站点,建议显式启用
safe:
export default defineConfig({
security: { contentTrust: 'safe' },
})
safe
模式会关闭 Markdown 原始 HTML,清理危险标签、事件属性和不安全 URL;ECharts 只接受 JSON 配置。需要保留原始 HTML 或组件演示时,应继续使用
trusted,并把文档源纳入代码审查。
当配置文件位于 .ldesign/doc.config.ts 且没有显式设置 srcDir 时,默认文档目录是 .ldesign/docs。
自定义主题
Longpress 支持类似 VitePress 的本地主题约定。项目根目录下存在 .ldesign/theme/index.ts
时,会优先作为站点主题入口;历史目录 .ldesign/doc-theme/index.ts 仍然兼容。也可以通过
theme: './path/to/theme' 显式指定主题目录,或使用内置主题名
default、paper、aurora、mono、catalog。
// .ldesign/theme/index.ts
import { defineTheme } from '@composy/longpress/theme'
import { definePlugin } from '@composy/longpress/plugins'
import DefaultTheme from '@composy/longpress/theme-default'
import CustomNav from './components/CustomNav.vue'
import './styles/index.css'
const themeBadgePlugin = definePlugin({
name: 'local-theme-badge',
slots: {
'nav-bar-content-after': {
component: 'ThemeBadge',
order: 10,
},
},
})
export default defineTheme({
extends: DefaultTheme,
components: {
VPNav: CustomNav,
},
plugins: [themeBadgePlugin],
styles: ['./styles/index.css'],
enhanceApp({ app }) {
// app.component('MyComponent', MyComponent)
},
})
如果要完全接管页面结构,可以直接提供 Layout:
import { defineTheme } from '@composy/longpress/theme'
import Layout from './Layout.vue'
export default defineTheme({
Layout,
})
默认主题的主题色和尺寸切换直接使用 @composy/color-core 的 ldesign-color-theme-selector 和
@composy/size-core 的 ldesign-size-preset-selector Web Component。Longpress 只负责把这些组件的
change 事件同步到文档系统已有的 storage、根节点属性和兼容 CSS 变量。
主题也可以携带 plugins。这类插件会和站点配置里的 plugins
一起参与客户端运行时;当主题是配置文件里直接传入的 defineTheme(...)
对象时,也会进入 Node 侧插件容器,用于 Markdown、build hook 等能力。
构建缓存
Node 端可通过 createBuildCache 复用 Markdown 与代码高亮结果。maxEntries
只有缓存容量超限时才完整扫描并淘汰最旧的磁盘条目,常规写入采用原子替换,避免每次写入重复遍历缓存目录。内存缓存按 LRU 同时限制条目数量与估算 JSON 字节数(默认 32 MiB);容量统计覆盖内置与自定义缓存类型。缓存文件元数据在读取与 prune() 时校验版本、时间戳和有效性。
import { createBuildCache } from '@composy/longpress/node'
const cache = createBuildCache(process.cwd(), {
maxAge: 7 * 24 * 60 * 60 * 1000,
maxEntries: 5000,
maxMemoryBytes: 32 * 1024 * 1024, // 可针对 CI 内存上限进一步调低
})
开发环境扫描页面和生成本地搜索索引时,会使用基于 mtime/ctime/size 的进程内增量缓存。修改或删除文档后会自动失效;该加速不改变生产索引格式。增强搜索在小型站点仍输出单个 JSON 数组,大型站点输出 version: 1 的内容寻址分片清单,并在清单发布后删除不再引用的旧分片。
Workbench
pnpm longpress dev --workbench
也可以在外部 runtime 或 tool-ui 壳层中直接接入:
import { createLongpressWorkbench } from '@composy/longpress/workbench'
createLongpressWorkbench({
backendBaseURL: 'http://127.0.0.1:17802',
})
Launcher 接入
import { createLongpressLauncherDevConfig } from '@composy/longpress/node'
const config = await createLongpressLauncherDevConfig({
root: process.cwd(),
port: 5173,
})
目录结构
tools/longpress/
├─ .ldesign/ # pack、ESLint、TypeScript 与文档站配置
│ ├─ pack.config.ts # @composy/pack 的权威共享入口配置
│ └─ tsup.config.ts # build 编排器使用的兼容入口
├─ bin/ # CLI wrapper
├─ playground/ # playground workspace
├─ scripts/ # 构建脚本
├─ eslint.config.js # 指向 .ldesign/ 权威配置
├─ tsconfig.json # 指向 .ldesign/ 权威配置
├─ src/
│ ├─ client/ # 客户端运行时
│ ├─ markdown/ # Markdown 渲染与扩展
│ ├─ node/ # Node.js 构建、服务、CLI、配置
│ ├─ plugins/ # 内置插件
│ ├─ themes/ # 内置主题
│ └─ shared/ # 共享类型与工具
└─ README.md
更细的源码职责说明见 src/README.md。阅读源码时建议从 src/node/cli/cli.ts 开始看命令注册,再进入
src/node/cli/init.ts、src/node/core/createLDoc.ts、src/node/build/build.ts 和
src/node/server/serve.ts。
构建产物
每次 pnpm build 会创建完整执行日志:
.ldesign/.logs/longpress/<ISO 时间>-<pid>.log
日志会记录构建阶段、终端输出、异常堆栈、退出码与耗时;常见的 token、密码、secret 与 API key 参数会自动脱敏,日志不可写不会改变构建结果。
当前构建输出到 dist/ 目录:
共享 TypeScript 入口由 @composy/pack 使用 .ldesign/pack.config.ts 打包;现有 scripts/build.ts
继续编排 Vite 运行时构建与发布目录整理。根目录 ESLint/TypeScript 文件仅作为工具自动发现入口,权威配置保存在
.ldesign/。
dist/
├─ es/ # ESM 入口(主入口)
├─ lib/ # CJS 入口
├─ types/ # TypeScript 声明
└─ es/themes/ # 主题运行时
npm 发布内容还包含 README、主题资源与 MIT LICENSE;发布前可运行
npm pack --dry-run --ignore-scripts 核对最终 payload。
开发
pnpm install
pnpm --dir tools/longpress run build # 构建包
pnpm --dir tools/longpress run type-check # 类型检查
pnpm --dir tools/longpress run lint:check # 代码检查
pnpm --dir tools/longpress/playground run dev # 启动文档站开发服务器
pnpm --dir tools/longpress/playground run build # 构建文档站
验证
# 确认 class 命名规范
rg "\.ldoc-|\.vp-" src/themes/ src/client/ --include "*.css" --include "*.vue"
# 应只在兼容别名文件中出现
# 硬编码颜色扫描
rg "#[0-9a-fA-F]{3,8}\b" src/themes/core/styles/index.css
# 应只在 token fallback 值中出现
# 构建验证
pnpm --dir tools/longpress run build
pnpm --dir tools/longpress/playground run build
License
MIT
通过 @composy/cli 统一接入
- 接入类型:
bin - 统一命令:
ldesign longpress - 命令别名:无
- 包内原生 bin:
ldoc、longpress
当前包通过独立 bin 接入,统一命令会转发到包自身 CLI。
pnpm add -D @composy/cli
ldesign longpress --help
ldesign tools run longpress --help
2026-10 主题与文档交互增强
默认主题支持「复制文档链接 / 打印」快捷操作。单篇文档可通过 frontmatter docActions: false 隐藏。VPCodeBlock 提供 collapsible(默认 false)、collapsedLines(默认 16)可选属性。
主题组件同时保留 vp-* 和 ldesign-doc-* 类名,以兼容历史用户 CSS;在修改 scoped style 与模板时运行 pnpm run check:theme 避免重新引入不一致。
本轮详细改动、验证结果、尚待处理事项请参阅 OPTIMIZATION_REPORT_2026-10-10.md。
Longpress V7 · 统一 UI 与侧边栏宽度
默认主题通过 src/themes/core/styles/design-system-v7.css 定义共享的
--ldoc-ui-* 语义变量;已有 --ldesign-doc-*、--vp-* 变量及 vp-* CSS
兼容类名仍有效。明暗模式、颜色预设及站点原有 CSS 变量优先通过旧契约驱动。
桌面端文档侧边栏可将鼠标移到右侧分隔条拖动宽度;选中分隔条后可按左右 方向键逐步调整、Shift + 方向键加速调整,或双击恢复配置宽度。小屏抽屉不显示分隔条。 宽度默认按站点 base 存储到当前浏览器 localStorage;浏览器禁止存储时仍可临时调整。
可以在站点的 themeConfig.ui 中关闭或自定义该能力:
export default {
themeConfig: {
layout: { sidebarWidth: 260 },
ui: {
sidebarResize: {
enabled: true, // 默认 true;设为 false 可完全关闭
minWidth: 208, // 最小有效范围 180~400px
maxWidth: 420, // 最大允许到 640px;默认宽度更宽时会保留原宽度
step: 12, // 键盘左右方向键每次调整的像素
persist: true, // 默认 true;关闭后刷新时恢复站点配置
},
},
},
}
也可以直接设 ui: { sidebarResize: false }。页面宽度默认值保持与旧版相同,
没有用户手动修改时,不会自动替换 layout.sidebarWidth。
新增 pnpm run check:ui,会检查 V7 样式入口、语义 token、防自引用、无障碍和
减少动画适配;该检查已加入 quality:check,但不能代替浏览器视觉回归。
详见 IMPLEMENTATION_V7_2026-10-10.md。
Longpress V8 · 本机版本历史与资源拖放
在开发文档工作台顶部选择「历史」,可以创建手动检查点,查看成功保存后自动记录的
文档快照,或将历史内容恢复到编辑区。恢复不会自动写入磁盘:确认内容后点击
「保存页面」。现有服务端 expectedRevision 校验仍生效,过期版本不能覆盖外部修改。
历史仅保存在当前浏览器 localStorage,按页面路径隔离,最多保留 10 条 / 30 天;
超大页面或禁用本地存储时可能无法记录历史。此功能不是服务器备份或多人协作历史,
共享工作站上的未发布文档可使用「清空当前页历史」及时清理。
资源面板支持拖放文件和原有文件选择器;读取前检查 10 MiB 上限及服务器允许的资源
扩展名。图片插入 ,PDF、音视频和字体插入普通 Markdown 链接。
新增检查命令:pnpm run check:workbench 和 pnpm run audit:styles。
前者仅检查关键源码接口连接,后者输出 CSS 源文件体积与导入概况,不自动删改样式。
完整改动和测试边界见 IMPLEMENTATION_V8_2026-10-10.md。
V9 · 服务器页面历史与资源库
工作台「历史」现在会显示浏览器本地检查点和服务器页面旧版本(默认每页最多 20 条、保留 90 天)。页面更新或删除前会尝试保存原始 Markdown 到项目根目录 .longpress/history/;恢复只是载入编辑器,仍需手动保存并通过 expectedRevision 校验。新增历史/资源 API 见 IMPLEMENTATION_V9_2026-10-10.md。
资源页支持浏览当前 public 子目录已有媒体文件并插入对应 Markdown 链接。资源清单有数量、目录深度与类型限制。历史快照是明文敏感项目文件,不得通过 Web 服务器公开 .longpress/;此功能不能代替 Git/数据库审计及备份。运行 pnpm run check:history 检查快照及差异工具。
Longpress V11 · 资源引用分析(只读)
在开发工作台中打开「资源」,选中已有资源的「引用」按钮,可检查文档源码里对该资源的常见静态引用,查看来源 Markdown 路径、行号及同一行的引用次数。报告同时提供已扫描页面数、扫描是否完整,以及超限/读取失败原因。
也可以从管理 REST API 读取:
GET /api/assets/references?path=images%2Flogo.png
Workbench Bridge 通过 inspectAssetReferences({ path: 'images/logo.png' }) 提供相同能力。路径相对于 srcDir/public,仅支持资源目录已列出的公开文件格式。管理端原有访问令牌、Origin 等限制保持不变。响应示意:
{
"asset": "images/logo.png",
"references": [{ "page": "guide/intro.md", "line": 12, "occurrences": 1 }],
"scannedPages": 80,
"complete": true,
"limitations": []
}
扫描支持 Markdown 图片/链接、引用定义、常见 Frontmatter 图像字段、HTML src/href/poster/srcset 和 CSS url(...);忽略代码围栏、行内代码和 HTML 注释。使用 public 资源路径与站点 base 进行规范化;跳过隐藏目录、node_modules、符号链接和 public 本身。为保护开发服务器,单次最多扫描 1500 篇 Markdown、32 MiB 文本,单文档最多 1 MiB,最多返回 200 个引用位置。超过预算或遇到无法读取的源文件时 complete=false。
关键安全约束: 即便 complete=true 且 references=[],也不意味着资源可删除。组件代码、CSS 文件、脚本、插件、动态 URL 与生产生成产物不在完整覆盖范围内。V11 没有提供删除或重命名接口,不会修改任何资源或 Markdown 文件。正式删除前请做 Git 全局检索和构建产物检查。
本地使用 pnpm run check:references 执行专项检查(Node 22 也可用 node --experimental-strip-types scripts/check-v11-references.mjs 独立运行)。实施记录见 IMPLEMENTATION_V11_2026-10-10.md。
V12 增量资源引用索引
管理后台的「资源 → 引用」已支持 内存中有界增量反向索引。它在每次请求时校验目录和文件元数据,只重新读取并解析发生变化的 .md/.mdx 文件;同时返回复用/重新解析的篇数。页面新增、删除、修改会在下一次查询中更新,多个同时发起的查询共享扫描。
- 点击引用结果中的
.md文件和行号,可在工作台打开对应 Markdown 并高亮该行;.mdx仍只支持查看路径。 - 每次最多扫描 1500 篇文档、32 MiB 的文本,每篇不超过 1 MiB,并限制索引引用数量;如有跳过或超限,报告显示
complete: false。 - 索引是会话内缓存,不新增隐藏磁盘文件,不执行删除;动态 URL、生成内容、插件及 CSS 文件中的引用不保证覆盖,未发现引用不意味着文件可以安全删除。
- 新的报告字段
cache?: { reusedPages, reparsedPages }为可选字段,老版scanAssetReferences()保持可用。
项目依赖安装完成后执行 pnpm run check:references 进行 V11/V12 检查,pnpm run benchmark:references 可在本机运行 250 篇文档、20 次查询的微基准(不是全站构建指标)。
V14:资源重命名及静态引用预览(2026-10-10)
工作台资源列表新增「重命名」:先填写 public/ 目录内的新相对路径,使用检查并预览查看影响的 Markdown 文件及具体 URL 改写,然后经确认后执行。新、旧资源必须具有相同的受支持扩展名。管理接口同时支持 POST /api/assets/rename/preview(只读)与 POST /api/assets/rename(提交预览返回的 planId);Workbench Bridge 提供 previewAssetRename / renameAsset。
批量修改会强制重新检查引用索引和源文件/页面修订版本,并在写入异常时尽力回滚。它不是事务数据库;运行时 JS、CSS、组件和插件内的动态引用无法自动更新。执行前请先提交 Git 以备恢复。详见 IMPLEMENTATION_V14_2026-10-10.md。可运行 pnpm run check:v14 做专项 URL 改写检查。
V15:资源安全删除与可恢复回收站
资源库支持先检查引用、再确认移入回收站;删除前会重新扫描 Markdown 静态引用,并要求输入完整相对路径。操作会把资源保存在项目根目录的 .longpress/trash/assets/,可从工作台「资源回收站」恢复。恢复时校验 SHA-256,拒绝覆盖现有文件;「操作审计」支持查看最近的删除、恢复和重命名记录(.longpress/audit/)。
对应 REST 接口:POST /api/assets/delete/preview、POST /api/assets/delete、GET /api/assets/trash、POST /api/assets/trash/restore、GET /api/assets/audit;Bridge 提供 previewAssetDelete、deleteAsset、listAssetTrash、restoreAsset、listAssetAudits。
注意: 索引只覆盖静态 Markdown 引用,不覆盖 JS、CSS、插件或动态 URL。即使没有发现引用,也不保证删除对运行时安全。回收站不是正式备份或崩溃一致事务,发布前请保留 Git/外部备份。专项检查:pnpm run check:v15。完整说明见 IMPLEMENTATION_V15_2026-10-10.md。
Playground iframe 安全隔离(V18,可选)
对于放在站点 public/playground/ 目录下的自包含原生 ESM 演示,可以启用独立沙箱。此模式不会在文档主页面直接 import() 示例源码:父页面先在 1 MiB / 12 秒限制内下载模块,再将源码交给不具有同源权限的 iframe 执行。
::: native-playground title="隔离计数器" module="/playground/native-counter.js" exportName="render" isolation="iframe" showCode
:::
或在 Vue 页面中:
<LDocPlayground
runtime="native"
module="/playground/native-counter.js"
export-name="render"
isolation="iframe"
/>
安全与兼容边界:
- iframe 仅开放
sandbox="allow-scripts",不可加入allow-same-origin。iframe CSP 禁止connect-src、表单、嵌套 frame 及外部图片/脚本请求。 - 仅支持同源
/playground/路径下的.js、.mjs自包含文件。模块不得依赖相对import、外部样式/脚本、网络请求或父页面 Vue/React 状态;Props/插槽必须能转换为有界 JSON。导出渲染函数应返回可选的清理函数。 - Vue、React 和直接传入的
render函数尚不支持 iframe 模式;配置不兼容时会明确报错,不会悄悄退回主页面执行。默认仍为isolation="none",仅应用于可信代码。 - 主站若设置了 CSP,需按实际部署策略允许该 iframe 的
srcdoc;某些更严格的 CSP 或浏览器策略可能阻止 Blob ESM 加载。请在部署浏览器中进行验收。 - 此特性限制宿主 DOM/存储的可访问性,不等于在浏览器中运行任意不可信代码的完整安全审计。它也不是 iframe Vue/React 构建器。
可运行 node --experimental-strip-types scripts/check-v18-iframe.mjs 执行协议、配置校验及沙箱脚本模拟回归测试。
Related Packages
A VitePress plugin that automatically identifies and links glossary terms with i...
A VitePress blog theme with authors, tags, archives, and a built-in setup wizard
Version History
| Version | Released | License |
|---|---|---|
| 1.0.0 | MIT | |
| 0.0.1 | MIT |