【免费下载链接】nasikoDeveloper Control Plane for your AI Agents项目地址https://gitcode.com/gh_mirrors/na/nasiko点击查看免费下载这篇技术指南以 nasiko 仓库中 ui/common/vendor/README.md 为核心完整介绍该项目 UI 侧零构建、零包管理器下的第三方库 vendoringvendor策略marked、DOMPurify、highlight.js三份单文件 ESM 为何被直接提交进仓库、各自版本与来源以及它们如何被 ui/common/utils/markdown.js 组装成Markdown 解析 → 语法高亮 → HTML 净化的渲染流水线。读完本文你将理解 nasiko 控制面板如何在没有任何打包工具的情况下安全地渲染来自 LLM 的不可信 Markdown 输出并掌握这套依赖的升级维护方法。为什么选择 vendoringUI 没有构建步骤也没有包管理器原文档开宗明义地交代了该策略的根本原因Single-file ESM builds, committed directly because the UI has no build step or package manager (see UI is vanilla JS in CLAUDE.md). Do not edit these files; replace them wholesale when upgrading.nasiko 的 Web 控制台是纯原生 JavaScriptvanilla JS实现页面直接以 HTML 文件形式提供如 ui/web/index.html、ui/web/chat.html每个页面配套一个*.preview.js与共享的/common模块体系。在这种架构下没有npm install、没有webpack/vite/rollup之类的打包步骤浏览器需要直接加载可执行的 ES Module 文件因此第三方库只能以单文件 ESM 构建产物的形式整体复制vendored进仓库随 UI 一起分发。由此产生两条硬性维护纪律原文档明确写出不要手工编辑这些 vendor 文件Do not edit these files升级时整体替换replace them wholesale when upgrading而不是在源码里打补丁。从仓库实际文件可以验证这一点marked.esm.js文件头部带有marked v15.0.12的版权头并醒目声明DO NOT EDIT THIS FILE见 ui/common/vendor/marked.esm.jsdompurify.esm.js则带有 DOMPurify 3.2.6 的 Apache 2.0 / MPL 2.0 双许可声明见 ui/common/vendor/dompurify.esm.jshighlight.esm.js是由 jsDelivr 使用 Rollup 与 esbuild 动态构建的 common-languages 打包产物见 ui/common/vendor/highlight.esm.js。这些文件的生成痕迹都指向从 CDN 整体下载、原样提交与 README 的说明完全一致。vendored 依赖清单版本、来源与用途原文档给出了一张精确的依赖清单表是理解这套栈的起点此处完整保留文件包名版本来源marked.esm.jsmarked15.0.12jsDelivr 上的marked15.0.12/lib/marked.esm.jsdompurify.esm.jsdompurify3.2.6jsDelivr 上的dompurify3.2.6/dist/purify.es.mjshighlight.esm.jshighlight.js11.11.1jsDelivr 上的highlight.js11.11.1/es/common/esmcommon-languages 包这三个库在渲染链路中各司其职marked15.0.12Markdown 解析器。负责把 LLM 输出的 Markdown 文本转换为 HTML并启用 GFMGitHub Flavored Markdown扩展即支持表格、嵌套列表、删除线等语法DOMPurify3.2.6HTML 净化器。LLM 输出是不可信内容DOMPurify 负责在渲染结果写入innerHTML之前剥离一切危险脚本、事件处理器与恶意属性highlight.js11.11.1代码高亮。使用es/common/esm这一 common-languages 打包版一次性内置了大量常见语言JavaScript/TypeScript、Python、Rust、Go、JSON、YAML、Bash、SQL、CSS 等可从文件末尾的registerLanguage序列看到完整的语言清单供围栏代码块fenced code block做语法着色。三份文件在仓库中均真实存在路径分别为 ui/common/vendor/marked.esm.js、ui/common/vendor/dompurify.esm.js、ui/common/vendor/highlight.esm.js。消费方markdown.js 中的三段式渲染流水线原文档末尾注明这些库的消费入口是/common/utils/markdown.js仓库路径 ui/common/utils/markdown.js。这份模块的头部注释把流水线概括为Pipeline: marked (GFM: tables, nested lists, strikethrough, ...) → highlight.js for fenced code blocks → DOMPurify sanitize.展开来看markdown.js内部实际做了这几件事1. 导入三份 vendor 模块并创建独立的 marked 实例import { Marked } from /common/vendor/marked.esm.js; import DOMPurify from /common/vendor/dompurify.esm.js; import hljs from /common/vendor/highlight.esm.js;注意代码注释特别说明这里创建的是专用实例new Marked({...})而不是直接修改 marked 的共享单例避免污染全局配置。实例启用了两个关键选项gfm: true开启 GFMLLM 输出的表格、嵌套列表、删除线才能正确渲染breaks: true单个换行渲染为br贴合 LLM 聊天文本的换行习惯。2. 自定义代码块渲染器接入 highlight.jsmarkdown.js 重写了renderer.code与renderer.codespan围栏代码块被包装进div classmd-code-block头部带有语言标签md-code-lang与复制按钮md-code-copy图标来自/common/utils/icons.js代码正文经highlightCode()处理function highlightCode(code, language) { if (language hljs.getLanguage(language)) { try { return hljs.highlight(code, { language, ignoreIllegals: true }).value; } catch { // fall through to plain rendering } } return escapeHtml(code); }其安全设计值得注意无论高亮成功与否返回的都是 HTML 安全文本。未知语言或高亮器抛错时会回退到escapeHtml()转义后的纯文本绝不会把原始代码直接拼进 DOM。3. 渲染入口 renderMarkdown() 与兜底逻辑renderMarkdown()markdown.js是整个模块对外暴露的唯一函数export function renderMarkdown(text) { if (!text) return ; let html; try { html marked.parse(text); } catch { // Never let a parser edge case blank out a chat message. html p${escapeHtml(text)}/p; } // Tables need a scroll container to avoid blowing out the chat bubble on // narrow screens. Markdown cant nest tables, so plain wrapping is safe. html html .replace(/table/g, div classmd-table-wraptable) .replace(/\/table/g, /table/div); return DOMPurify.sanitize(html); }三个细节解析兜底即使 marked 遇到解析边界情况抛错也会退化为转义后的p文本保证聊天消息永远不会因为一个解析错误而整条空白表格防溢出对table做正则包裹为.md-table-wrap滚动容器避免在窄屏聊天气泡中撑爆布局注释还解释了这样做的安全性——Markdown 语法本身不允许嵌套表格所以纯包裹替换不会引入结构错误最终净化所有 HTML 在返回前必须经过DOMPurify.sanitize()这是不可信内容进入 DOM 前的最后一道防线。4. 链接安全钩子由于 LLM 输出中的链接完全不可信markdown.js 注册了一个afterSanitizeAttributes钩子凡是有href的a标签一律强制追加target_blank与relnoopener noreferrer。这样链接会在新标签页打开且不会携带window.opener引用杜绝了反向 tabnabbing 一类攻击。注释特别提醒若不通过钩子处理DOMPurify 默认会直接剥离target/rel属性。调用方聊天页与编排步骤页如何消费 renderMarkdownrenderMarkdown()的实际消费者包括ui/common/components/chat-page.jsLLM 回复消息渲染。非用户消息的消息行被加上md-body类后写入innerHTML renderMarkdown(content)见 chat-page.js同时用事件委托统一绑定复制按钮——监听容器上的click命中.md-code-copy时读取同一代码块内code的textContent写入剪贴板见 chat-page.js这样流式渲染中不断重建的代码块也能持续获得复制能力ui/common/components/agent-steps.js编排步骤面板。步骤内容若标记为 Markdown则套用step-v step-v--md md-body类并调用renderMarkdown()见 agent-steps.js流式输出时也会持续追加原始文本并重渲染见 agent-steps.js。两处调用都遵循同一约定容器先加md-body类引入样式再填入renderMarkdown()的返回值即markdown.js头部注释中写明的用法container.classList.add(md-body); // styles: /common/styles/markdown.css container.innerHTML renderMarkdown(text);配套样式markdown.css 与 md-body渲染出的 HTML 依赖 ui/common/styles/markdown.css 完成视觉呈现该文件同样以渲染后的 Markdown 样式供 LLM 输出使用为定位。它定义了标题层级h1–h6与段落、列表、引用、分隔线的间距与字体内联代码code.md-inline-code与代码块.md-code-block的边框、圆角与头部布局复制按钮button.md-code-copy的尺寸、悬停与:focus-visible焦点环.md-table-wrap表格滚动容器、斑马纹行背景一套完整的 highlight.js 明暗双主题配色基于light-dark()适配明暗模式覆盖注释、关键字、字符串、数字、函数名等 token 类。也就是说vendor 库只负责生成正确的 HTML视觉层完全由项目自己的 CSS 承接这也体现了vendor 文件只做整体替换、样式由自家维护的职责划分。升级 vendor 依赖三步走流程原文档给出了明确的升级路径这是维护这套无构建栈最关键的操作知识To upgrade: download the new version from the URL above (bump the version in the path), strip any trailing//# sourceMappingURL...line (the.mapfiles are not vendored), and update this table.将其展开为可执行步骤下载新版本从上方清单中的 CDN 地址下载目标版本的单文件 ESM 构建注意在 URL 路径中把版本号替换为新版本例如将marked15.0.12改为markedx.y.z剥离 sourceMappingURL删除文件末尾的//# sourceMappingURL...注释行——对应的.map源映射文件不会一并 vendored保留该行只会产生无效引用整体替换并更新清单用新文件整体覆盖旧的 vendor 文件而不是在其上做局部修改并同步更新本 README 表格中的版本号与来源信息。替换后消费方 ui/common/utils/markdown.js 无需任何改动即可自动使用新版本因为导入路径固定指向 vendor 目录下的三个文件名。这正是单文件 ESM 固定文件名 整体替换策略带来的维护简单性。也正因如此ui/common/vendor/README.md 这张表格本身就是这套依赖的唯一事实来源source of truth升级后必须保持表格与磁盘文件一致。小结nasiko 的 UI 层用一套极其轻量的手段解决了两个问题一是没有构建工具时的第三方依赖管理——通过将 marked、DOMPurify、highlight.js 的官方单文件 ESM 构建整体提交进仓库见 ui/common/vendor/ 目录绕开了包管理器与打包步骤二是不可信 LLM 内容的安全渲染——由 markdown.js 完成marked 解析 → highlight.js 高亮 → DOMPurify 净化的完整流水线再配合md-body样式与复制按钮交互markdown.css、chat-page.js、agent-steps.js为聊天页与编排步骤页提供了统一、安全、可升级的 Markdown 呈现能力。理解这份 vendored 清单与它的消费链路也就掌握了这个无构建前端中依赖从哪来、怎么升级、怎么被安全使用的完整答案。赞分享【免费下载链接】nasikoDeveloper Control Plane for your AI Agents项目地址https://gitcode.com/gh_mirrors/na/nasiko点击查看免费下载相关推荐Turtl桌面应用版本0.7.3新特性详解Electron升级与koffi集成Turtl桌面应用版本0.7.3新特性详解Electron升级与koffi集成 Turtl桌面应用版本0.7.3带来了重要的底层升级和功能优化其中ElectSwiftGen 依赖清单全解析SPM 依赖、第三方库角色与构建工具链SwiftGen 依赖清单全解析SPM 依赖、第三方库角色与构建工具链 导读 本文以仓库根目录下的 DEPENDENCIES.md https://link.开发工具代码生成Emscripten静态库依赖管理文档依赖清单Emscripten静态库依赖管理文档依赖清单 1. 静态库依赖管理概述 在Emscripten项目开发中静态库依赖管理是确保编译过程顺利进行的关键环节。本编译器WebAssembly开发工具构建工具上一篇如何彻底解决音乐格式限制Unlock Music终极音乐解密工具完整指南下一篇如何快速构建现代化后台系统企业级管理框架的终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
