如何给 DSH 写一个插件并安装 / 卸载它本文基于真实环境deepseek-ai/dsh0.2.1-rc.5Windows的实操复盘。DSH 各版本插件 API 名字可能略有差异本文以已验证可加载的写法为准——下文所有结论都来自实际安装、加载、卸载的验证而非照抄社区教程。0. 先说清 DSH 的插件模型DSH 的口号是万物皆是插件。一个插件本质是一个包通过package.json里的dsh清单声明自己然后在它的客户端半边里往 DSH 的 UI 贡献样式、组件、页面、服务。本文带你从零写一个把界面染成红色的插件my-red-theme并走完安装、验证、卸载全流程。1. 动手前先核对你的运行时很多人栽在这网上教程常写放进dsh-runtime/node_modules 改cordis.patch.yml但你的真实环境是这样的全局 CLInpm i -g deepseek-ai/dsh本机版本0.2.1-rc.5。家目录home没设DSH_HOME时用默认~/.dshWindows 即C:\Users\你\.dsh。插件按 profile 隔离~/.dsh/profiles/name/各自有node_modules/和cordis.patch.yml。你实际在用的 profile 叫web路径C:\Users\你\.dsh\profiles\web\node_modules\ ← 插件都装这里 C:\Users\你\.dsh\profiles\web\cordis.patch.yml已装的dsh-better-sidebar就在这个web/node_modules里——它是你最好的真实样本比任何博客都准。关键认知没有全局插件这种事插件是跟着 profile 走的。“把插件装进全局 dsh的真实含义是装到某个 profile 的node_modules并让 loader 挂载”。2. 一个最小可加载插件的真实结构照官方自带的cordis-plugin-development技能模板里面有一个decoration装饰模板来写一个纯 UI 插件只需要 4 个文件my-red-theme/ ├── package.json # ESM dsh 清单 ├── index.js # host 半边空壳 ├── client.js # client 半边真正干活的注入样式 └── cordis.patch.yml # bundle patch让 loader 挂载package.json{name:local/my-red-theme,version:1.0.0,private:true,type:module,exports:{.:./index.js,./client:./client.js},files:[index.js,client.js,cordis.patch.yml],dsh:{bundle:{patch:./cordis.patch.yml},client:{platform:web,immediately:true,inject:[]}}}注意三点和社区版 Cordis 教程不同用dsh字段声明插件不是cordis: true。必须是ESMtype: module。用 CommonJS 会直接加载失败。local/是本地开发插件的约定作用域。index.jshost 半边// 纯 UI 装饰不需要 host 逻辑exportfunctionapply(){}client.jsclient 半边——重点// 运行在浏览器里document 可用window.__ModuleLoader__.load({id:local/my-red-theme,factory(require){constCSS_IDmy-red-theme-css;constRED_CSS:root, body, #app { --dsh-bg: #2b0000 !important; --dsh-fg: #ffd9d9 !important; --dsh-primary: #ff2f2f !important; background: var(--dsh-bg) !important; color: var(--dsh-fg) !important; } button, .btn { background: #ff2f2f !important; color: #fff !important; };functioninject(){if(typeofdocumentundefined)return;if(document.getElementById(CSS_ID))return;// 幂等热重载不重复插consteldocument.createElement(style);el.idCSS_ID;el.textContentRED_CSS;document.head.appendChild(el);}inject();if(typeofdocument!undefined)document.addEventListener(DOMContentLoaded,inject);return{inject:[],apply(){}};},});cordis.patch.yml-insert:-id:my-red-themename:local/my-red-theme# 必须与 package.json 的 name 完全一致3. 最关键的坑host 半边 ≠ client 半边这是 90% 新手写出来了但界面没反应的原因host 半边index.js跑在Node里document/window不存在。client 半边client.js经window.__ModuleLoader__.load注册才跑在浏览器里。所以让界面变红这种 DOM 操作只能写在 client 半边。很多教程让你在入口ctx.inject([style], ...)直接碰 DOM在你的版本里会因为没有document而静默失败。想加侧边栏 Tab也是同理在client.js的apply(ctx)里用ctx.slots.register(...)官方decoration模板就是这么注册 UI 的并把inject改成[slots]。4. 安装与卸载命令清单dsh plugin子命令的本质是把后续参数原样转发给该 profile 目录里的 pnpm。安装本地路径 / npm 包 / tgz 都支持dsh plugin--profile web add D:\path\to\my-red-theme它会把包装进~/.dsh/profiles/web/node_modules并写入dsh.profile.bundles让 loader 挂载。装本地路径时它创建的是link:软链实测看到link:D:/.../my-red-theme意味着你改工作区源码、重启 web 就能见效不用重装。也可以是 npm 包名dsh plugin --profile web add dsh-better-sidebar0.28.2或本地打的包add ./xxx.tgz。卸载dsh plugin--profile web remove local/my-red-theme包名用package.json里的name含local/。实测执行后node_modules/local/my-red-theme目录消失profile 的package.json依赖与 bundle 列表均无残留。验证是否真的加载了肉眼最直观重启 web 界面看变化红主题装上去界面立刻全红。看启动日志里有没有插件相关报错。浏览器开发者工具 → Elements检查head里有没有你的style idmy-red-theme-css。改完插件后必须重启 web 界面——client 半边的增删没有热更新刷新页面才会重新加载。5. 你可能没注意到的 7 件事插件是 per-profile 的没有全局插件。装到web只在web生效。host / client 半边之分DOM 操作只能放 client 半边否则document为undefined。cordis: true是社区版 Cordis 的写法你的deepseek-ai/dsh用的是package.json的dsh字段。照搬社区教程会装不上。必须是 ESM。CommonJS 入口加载即失败。cordis.patch.yml的name必须和包名完全一致否则 loader 按名字匹配不到挂载不上。dsh plugin add走的是 pnpm本地路径会建link:软链——这是最舒服的开发方式改源码即生效重启即可。CSS 全用!important只是最快见效要做可切换主题更优雅的做法是把样式包在[data-themered]选择器里再让插件动态给html加属性。DSH 自身的颜色 token如--dsh-bg最好去开发者工具里抄它的真实变量名再覆盖比盲写!important更不容易破版。6. 小结写 DSH 插件 一个 ESM 包 dsh清单 client.js里用window.__ModuleLoader__.load注入逻辑安装/卸载统一走dsh plugin --profile name add/remove。最大的两个坑是host/client 半边之分与ESM/清单格式——避开这两点你就能在十分钟内让界面全红再往上逐步加服务、加 Tab。附本次实操时间线复盘在d:/zhonglin/dsh/packages/my-red-theme按社区教程初版写了插件cordisjs/corecordis: true CommonJS ctx.inject。实地核对真实运行时发现全局是deepseek-ai/dsh0.2.1-rc.5家目录~/.dsh插件在profiles/web/node_modules。读官方cordis-plugin-development的decoration模板和已装的dsh-better-sidebar确认真实格式ESM dsh清单 window.__ModuleLoader__.load的 client 半边。按真实格式重写插件4 个文件node --check语法校验通过。dsh plugin --profile web add 本地路径安装 → 界面实测全红验证加载成功。dsh plugin --profile web remove local/my-red-theme卸载 → 验证node_modules、依赖、bundle 列表均清理干净。
企业数字化 ERP 产品动态
相关推荐
#11.1对于printf的深入学习(加餐) 欢迎指正,无论是学习方法,代码编写还是博客书写的内容和格式,我乐于听取一切有效的建议~
我的第五篇博客
依旧是小事记录,如果和一个不干脆的人共事真的非常非常让人心累,搞不清做事的目的是什么。但是也算是搞完了吧&… · 2026/11/3 10:49:18
体素、机械、建筑:同一模型三类题材的生成质量差异与成因 体素、机械、建筑:同一模型三类题材的生成质量差异与成因
Qwen3.5-4B-3D-Coder 是一个基于 Qwen3.5-4B 的独立微调模型,不输出网格、点云或 glTF,而是直接吐出一个自包含的 HTML 文件:内联 CSS、内联着色器参数、只从 cdnjs 引入… · 2026/11/3 10:49:18
MP4、TS 流媒体容器结构、特点与应用场景详解 目录
背景
一、编码、容器、分发是三层
1.1 编码、容器、分发三层介绍
1.2、三层各留各的信息
二、MP4:索引在 moov,样本在 mdat
2.1 盒子
2.2 一个点播文件里的三块
2.3 用这些表定位一帧
2.4 moov 在头,还是在尾
2.5 分片 MP4
… · 2026/11/3 10:49:18
SkyWalking动态配置探针功能详解与实践 1. SkyWalking动态配置探针功能概述Apache SkyWalking作为一款优秀的应用性能监控(APM)系统,其Java Agent探针功能一直是其核心能力之一。在实际生产环境中,我们经常需要在不重启应用的情况下动态调整探针的采集行为,这正是Dynamic Configura… · 2026/11/3 14:42:43
Univer开源文档引擎:嵌入式富文档渲染与离线计算能力解析 1. Univer 是什么:一个被误读的开源办公引擎,不是“在线 Office”替代品很多人第一次看到“Univer”这个词,是在技术社区里刷到“univer在线”“univer SDK”这类关键词,下意识以为这是又一个国产版 WPS Web 或腾讯文档的底层框架… · 2026/11/3 14:42:43
C、Go、Rust内存管理与并发模型深度对比 1. 编程语言发展现状与对比意义 1972年诞生的C语言至今已走过半个世纪,而Go、Rust等新生代语言正以每年两位数的增长率快速占领市场。作为参与过银行核心系统C语言改造项目的工程师,我亲眼目睹了不同语言在关键业务场景中的真实表现。这次对比不是简单的… · 2026/11/3 14:42:43
树莓派环境监测站:从传感器到数据可视化 1. 项目概述 树莓派作为一款信用卡大小的微型计算机,凭借其丰富的GPIO接口和强大的扩展能力,成为物联网开发的理想平台。这个项目将指导你使用树莓派配合常见传感器,构建一个功能完善的环境监测站,实时采集温度、湿度等环境数据&a… · 2026/11/3 14:42:43
Reactor网络模型与Linux百万级并发实践 1. Reactor网络模型与百万级并发的关系 在Linux高性能网络编程领域,Reactor模型是实现百万级并发连接的核心架构模式。这种事件驱动的设计范式与传统的多线程/多进程模型有着本质区别——它通过单线程事件循环配合非阻塞I/O,能够以极低的资源消耗处理海量… · 2026/11/3 14:42:43
Univer SDK:Web端文档能力引擎与Excel/PDF一体化开发指南 1. 项目概述:Univer 是什么,它解决的到底是什么问题?Univer 这个名字最近在开发者圈子里出现得越来越频繁,但很多人第一次看到时会下意识地联想到“universe”(宇宙)或者“universal”(通用&… · 2026/11/3 14:41:42
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46