写东西最怕的是"调格式"。Markdown 的价值就在于让你只关心内容。

#渲染链路

一个够用的博客渲染只需要三步:

const { marked } = require('marked');
const hljs = require('highlight.js');
const sanitizeHtml = require('sanitize-html');

function render(md) {
  const raw = marked.parse(md);          // 1. Markdown → HTML
  const safe = sanitizeHtml(raw, {       // 2. 过滤危险标签
    allowedTags: ['h1','h2','p','a','img','pre','code','ul','li','blockquote'],
    allowedAttributes: { a: ['href'], img: ['src','alt'] }
  });
  return safe;                            // 3. 交给模板
}

代码高亮通过自定义 renderer 注入:

renderer.code = function (text, lang) {
  const html = lang && hljs.getLanguage(lang)
    ? hljs.highlight(text, { language: lang }).value
    : hljs.highlightAuto(text).value;
  return `<pre class="code-block"><code>${html}</code></pre>`;
};

#千万别省略过滤

Markdown 允许内嵌 HTML,如果不做 sanitize,一段 <script> 就会被原样渲染。任何接受用户输入的内容都必须过滤。

#自动生成摘要

摘要可以不用手填,从正文剥掉标记即可:

function summary(md, len = 120) {
  const t = md.replace(/```[\s\S]*?```/g, '')
              .replace(/![[^]]*]([^)]*)/g, '')
              .replace(/[#>*_`~|-]/g, '')
              .replace(/\s+/g, ' ')
              .trim();
  return t.length > len ? t.slice(0, len) + '…' : t;
}

#我的写作习惯

  1. 先写大纲(## 标题),再填肉
  2. 代码示例必须是能跑的
  3. 发布前通读一遍,删掉所有"其实""某种程度上"

写清楚的难度远高于想清楚——但只有写下来,才知道自己有没有真的想清楚。