必须调用 marked.parse() 并初始化,禁用 HTML 解析(html: false),fetch 后显式 .text(),DOM 更新后再调用 hljs.highlightAll(),且始终用 DOMPurify.sanitize() 净化输出。

直接调用 marked.parse() 但必须避开 v4+ 版本的函数调用陷阱
新版 marked(v4 及以上)已移除直接调用 marked(text) 的能力,写成这样会报 TypeError: marked is not a function。你必须显式使用 marked.parse(),且不能漏掉初始化步骤。
- CDN 引入后,立刻执行
marked.setOptions({ gfm: true, breaks: true })或更推荐的marked.use({ gfm: true, breaks: true, html: false }) -
html: false是关键安全项——它禁用原始 HTML 解析,防止用户输入中混入<script>或onerror属性 - 若在模块环境(如 Vite/ESM)中使用,应改用
import { marked } from 'marked',而非全局脚本加载
加载外部 .md 文件时 fetch 响应体必须用 .text() 显式读取
浏览器不会自动把 fetch('doc.md') 的响应当作文本处理;如果服务端没返回 Content-Type: text/plain(或 text/markdown),Chrome/Safari 会静默拒绝解析,控制台只显示 Failed to fetch,没有具体原因。
- Vite 用户需在
vite.config.js中加server.headers: { 'Content-Type': 'text/plain' },否则本地开发时 404 都不报错 - fetch 后必须链式调用
.text(),不能省略或误用.json()、.blob() - 别忽略
r.ok判断:HTTP 状态码 404/500 时r.text()仍会成功执行,但内容是错误页 HTML,导致marked.parse()报语法错误
代码块没高亮?问题不在 marked,而在 highlight.js 调用时机和方式
marked 只生成带 <pre><code class="js"> 结构的 HTML,它不负责着色。如果你看到代码块是白底黑字,说明 highlight.js 的 JS 逻辑根本没跑。
用于端到端视频本地化流程的轻量编排器,路由至四个专注子技能——/wjs-transcribing-audio、/wjs-translating-subtitles...
- 必须在
innerHTML = marked.parse(...)之后再调用hljs.highlightAll(),顺序颠倒等于没做 - 若用了
marked.use({ async: true }),marked.parse()返回 Promise,得await完再调高亮,否则 DOM 还没更新就去遍历pre code - highlight.js 11.x+ 不再支持
hljs.highlightBlock(el),要用hljs.highlightElement(el),且只传单个节点(循环调用)或直接highlightAll()
生产环境必须加 DOMPurify.sanitize(),且配置要收窄
即使关了 html: false,攻击者仍可通过 [xss](javascript:alert(1))、<img src=x onerror=...> 或 SVG 标签触发 XSS。marked 不做内容净化,这事得交出去做。
立即学习“前端免费学习笔记(深入)”;
- 引入
DOMPurify后,至少限制ALLOWED_TAGS:只留['p','h1','h2','h3','ul','ol','li','strong','em','code','pre','blockquote','a'] - 别用默认配置,
DOMPurify.sanitize(html)不加选项等于白搭——它默认允许大量危险标签和属性 - 如果渲染区域是用户可控内容(比如评论区),建议每个
marked.parse()后都过一遍DOMPurify,别图省事只做一次全局过滤
最常被跳过的其实是 marked.use({ html: false }) 和 DOMPurify 的组合,这两步一缺,XSS 就几乎板上钉钉;而高亮失效往往卡在 highlightAll() 放太前或 async: true 没 await,调试时容易盯着 marked 白忙活。


















