Agent SkillsTanStack/markdown › production-pipelines

production-pipelines

GitHub

用于构建生产级 Markdown 管道的审计清单,涵盖信任边界、代码高亮、兼容性验证及确定性输出检查,确保博客或文档渲染的安全与稳定。

skills/production-pipelines/SKILL.md TanStack/markdown

Trigger Scenarios

部署前审核 Markdown 渲染管道 处理不可信内容输入时的安全检查

Install

npx skills add TanStack/markdown --skill production-pipelines -g -y
More Options

Use without installing

npx skills use TanStack/markdown@production-pipelines

指定 Agent (Claude Code)

npx skills add TanStack/markdown --skill production-pipelines -a claude-code -g -y

安装 repo 全部 skill

npx skills add TanStack/markdown --all -g -y

预览 repo 内 skill

npx skills add TanStack/markdown --list

SKILL.md

Frontmatter
{
    "name": "production-pipelines",
    "sources": [
        "TanStack\/markdown:docs\/core-concepts\/security.md",
        "TanStack\/markdown:docs\/core-concepts\/document-model.md",
        "TanStack\/markdown:docs\/core-concepts\/syntax-profile.md",
        "TanStack\/markdown:docs\/guides\/react.md",
        "TanStack\/markdown:docs\/guides\/syntax-highlighting.md",
        "TanStack\/markdown:docs\/guides\/performance.md",
        "TanStack\/markdown:docs\/guides\/testing.md",
        "TanStack\/markdown:docs\/comparison.md",
        "TanStack\/markdown:src\/utils.ts",
        "TanStack\/markdown:tests\/security.test.tsx",
        "TanStack\/markdown:tests\/bundle-size.test.ts"
    ],
    "metadata": {
        "type": "lifecycle",
        "library": "@tanstack\/markdown",
        "library_version": "0.0.15"
    },
    "requires": [
        "render-markdown"
    ],
    "description": "Audit and ship a production Markdown pipeline with explicit trust boundaries, external syntax highlighting, parse-ahead caching, compatibility checks, deterministic output, and bundle budgets. Load before deploying blogs, docs, or untrusted-content rendering.\n"
}

This skill builds on render-markdown. Read it first for the supported syntax, AST, parser options, and renderer contracts.

TanStack Markdown — Production Pipeline Checklist

Run every section before deploying a blog, documentation site, or user-content renderer.

Trust Boundary Checks

Check: Classify every Markdown source

Expected:

import { renderHtml } from '@tanstack/markdown/html'

export function renderUntrustedMarkdown(
  source: string,
  sanitize: (html: string) => string,
): string {
  const rendered = renderHtml(source)
  return sanitize(rendered)
}

Fail condition: Untrusted input reaches allowHtml, an unaudited extension renderHtml hook, or an unaudited highlighter.

Fix: Separate trusted and untrusted entry points, keep trusted callbacks disabled for untrusted content, and enforce application link, image, and final-HTML policy.

Highlighting Checks

Check: Return trusted code contents only

Expected:

import { renderHtml } from '@tanstack/markdown/html'
import { createHighlighter } from '@tanstack/highlight/core'
import { plaintext } from '@tanstack/highlight/languages/plaintext'
import { ts } from '@tanstack/highlight/languages/ts'
import { createTanStackMarkdownHighlighter } from '@tanstack/highlight/markdown'
const highlighter = createHighlighter({ languages: [plaintext, ts] })
export const html = renderHtml('```ts {1}\nconst answer = 42\n```', {
  highlighter: createTanStackMarkdownHighlighter(highlighter),
})

Fail condition: The callback returns a complete <pre><code> tree, does not escape source code, or comes from an unreviewed transform.

Fix: Return only escaped markup for the renderer-owned <code> contents, and run highlighting during ingestion, build, or server rendering.

Compatibility Checks

Check: Validate the actual content corpus

Expected:

MARKDOWN_CORPUS_DIRS=../site/src/blog:../site/docs pnpm run test:corpus
pnpm run corpus:audit:tanstack
pnpm run corpus:audit:external

Fail condition: Adoption relies only on CommonMark examples or a comparison table instead of the site's Markdown.

Fix: Add downstream content directories, preserve practical regressions with focused fixtures, and require renderer and bundle accounting for new syntax.

Check: Verify deterministic output

Expected:

import { renderHtml } from '@tanstack/markdown/html'
import { parseMarkdown } from '@tanstack/markdown/parser'

const source = '# Deterministic\n\n- one\n- two'
const firstDocument = JSON.stringify(parseMarkdown(source))
const secondDocument = JSON.stringify(parseMarkdown(source))
const firstHtml = renderHtml(source)
const secondHtml = renderHtml(source)

if (firstDocument !== secondDocument || firstHtml !== secondHtml) {
  throw new Error('Markdown output is nondeterministic')
}

Fail condition: Identical source and options produce different serialized AST or HTML.

Fix: Remove time, randomness, environment state, and unstable ordering from extensions and render callbacks.

Performance and Cache Checks

Check: Parse once with final options

Expected:

import type { MarkdownDocument } from '@tanstack/markdown'
import { renderHtml } from '@tanstack/markdown/html'
import { parseMarkdown } from '@tanstack/markdown/parser'

const cache = new Map<string, MarkdownDocument>()

export function renderCachedArticle(key: string, source: string): string {
  const cacheKey = `markdown-0.0.15:${key}`
  let document = cache.get(cacheKey)
  if (!document) {
    document = parseMarkdown(source, {
      frontmatter: true,
      headingIds: true,
    })
    cache.set(cacheKey, document)
  }
  return renderHtml(document)
}

Fail condition: Stable content is reparsed per request, or parser options/extensions change after the AST is cached.

Fix: Build the AST with final parse options, version persisted cache keys, invalidate stored ASTs when node contracts change, and use only narrow entry points.

Check: Enforce bundle budgets

Expected:

pnpm run size
pnpm test -- tests/bundle-size.test.ts

Fail condition: Any measured entry exceeds its checked gzip budget or starts bundling a highlighter.

Fix: Inspect the bundle diff and justify any syntax or dependency cost before adjusting a budget.

Release Checks

Check: Run the complete package gate

Expected:

pnpm run verify

Fail condition: Tests, typechecking, build, docs validation, conformance accounting, sizes, benchmarks, or the npm dry run fail.

Fix: Resolve every gate before publishing, including HTML/React/Octane parity; audit raw HTML, highlighter output, HTML hooks, and component replacements separately.

Common Production Mistakes

CRITICAL Enabling HTML for untrusted Markdown

Wrong:

import { renderHtml } from '@tanstack/markdown/html'

export function renderComment(source: string): string {
  return renderHtml(source, { allowHtml: true })
}

Correct:

import { renderHtml } from '@tanstack/markdown/html'

export function renderComment(source: string): string {
  return renderHtml(source)
}

allowHtml emits raw nodes and is not a sanitization step.

Source: docs/core-concepts/security.md

HIGH Returning highlighter containers

Wrong:

import { renderHtml } from '@tanstack/markdown/html'

function escapeCode(code: string): string {
  return code.replace(/[&<>]/g, (character) => ({
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
  })[character] ?? character)
}

console.log(renderHtml('```ts\nconst x = 1\n```', {
  highlighter: (code) => `<pre><code>${escapeCode(code)}</code></pre>`,
}))

Correct:

import { renderHtml } from '@tanstack/markdown/html'

function escapeCode(code: string): string {
  return code.replace(/[&<>]/g, (character) => ({
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
  })[character] ?? character)
}

console.log(renderHtml('```ts\nconst x = 1\n```', {
  highlighter: (code) => `<span class="token">${escapeCode(code)}</span>`,
}))

The renderer owns <pre><code>; the callback supplies only the code element's trusted contents.

Source: docs/guides/syntax-highlighting.md

CRITICAL Trusting arbitrary highlighter output

Wrong:

import { renderHtml } from '@tanstack/markdown/html'

const source = '```html\n<img src=x onerror=alert(1)>\n```'
console.log(renderHtml(source, { highlighter: (code) => code }))

Correct:

import { renderHtml } from '@tanstack/markdown/html'

function escapeCode(code: string): string {
  return code.replace(/[&<>]/g, (character) => ({
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
  })[character] ?? character)
}

const source = '```html\n<img src=x onerror=alert(1)>\n```'
console.log(renderHtml(source, { highlighter: escapeCode }))

Highlighter output is inserted without further escaping in every renderer.

Source: docs/core-concepts/security.md

MEDIUM Bundling highlighting into static clients

Wrong:

import { Markdown } from '@tanstack/markdown/react'
import { tokenize } from '@tanstack/highlight'

export function Article({ source }: { source: string }) {
  return <Markdown highlighter={(code) => String(tokenize(code))}>{source}</Markdown>
}

Correct:

import { renderHtml } from '@tanstack/markdown/html'
import type { CodeHighlighter } from '@tanstack/markdown'

export function renderStaticArticle(
  source: string,
  highlighter: CodeHighlighter,
): string {
  return renderHtml(source, { highlighter })
}

Tokenizer runtimes, grammars, and themes can outweigh Markdown parsing and should remain build-time or server-side for static content.

Source: docs/guides/performance.md

CRITICAL Treating defaults as a sanitizer

Wrong:

import { renderHtml } from '@tanstack/markdown/html'

export function renderForEveryPolicy(source: string): string {
  return renderHtml(source)
}

Correct:

import { renderHtml } from '@tanstack/markdown/html'

export function renderWithPolicy(
  source: string,
  sanitize: (html: string) => string,
): string {
  return sanitize(renderHtml(source))
}

Core escaping and protocol filtering do not enforce application-specific outbound-link, image, or final-HTML policy.

For parsed Markdown destinations, urlTransform(url, kind, defaultUrl) can return the screened default, a trusted replacement, or null to remove the link or image while retaining its label content. Only allow data images after application validation of their content, MIME type, and size. Keep the default policy for other destinations. Callback results are not screened again, and the callback does not apply to raw HTML, extension-created URLs, or ASTs supplied directly to renderers. Do not enable raw HTML to allow images. Include URL-policy changes in persisted AST cache invalidation.

Source: docs/core-concepts/security.md

HIGH Assuming complete CommonMark behavior

Wrong:

import { renderHtml } from '@tanstack/markdown/html'

export function renderArbitraryMarkdown(source: string): string {
  return renderHtml(source)
}

Correct:

import { renderHtml } from '@tanstack/markdown/html'

export function renderControlledDocs(source: string): string {
  return renderHtml(source)
}

The package implements a documented docs/blog profile, not complete CommonMark, GFM, MDX, or arbitrary plugin behavior.

Source: docs/core-concepts/syntax-profile.md

MEDIUM Reparsing unchanged content

Wrong:

import { renderHtml } from '@tanstack/markdown/html'

export function renderRequest(source: string): string {
  return renderHtml(source)
}

Correct:

import type { MarkdownDocument } from '@tanstack/markdown'
import { renderHtml } from '@tanstack/markdown/html'
import { parseMarkdown } from '@tanstack/markdown/parser'

export function compile(source: string): MarkdownDocument {
  return parseMarkdown(source)
}

export function renderRequest(document: MarkdownDocument): string {
  return renderHtml(document)
}

String render inputs parse the complete document, while a cached MarkdownDocument skips that work.

Source: docs/core-concepts/document-model.md

HIGH Injecting HTML into React

Wrong:

import { renderHtml } from '@tanstack/markdown/html'

export function Article({ source }: { source: string }) {
  const html = renderHtml(source)
  return <article dangerouslySetInnerHTML={{ __html: html }} />
}

Correct:

import { Markdown } from '@tanstack/markdown/react'

export function Article({ source }: { source: string }) {
  return <article><Markdown>{source}</Markdown></article>
}

The HTML string adds a trusted insertion boundary and bypasses React component replacement.

Source: docs/guides/react.md

MEDIUM Expecting fence metadata to highlight

Wrong:

import { renderHtml } from '@tanstack/markdown/html'

const source = '```ts {1}\nconst answer = 42\n```'
console.log(renderHtml(source))

Correct:

import { renderHtml } from '@tanstack/markdown/html'

function escapeCode(code: string): string {
  return code.replace(/[&<>]/g, (character) => ({
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
  })[character] ?? character)
}

const source = '```ts {1}\nconst answer = 42\n```'
console.log(renderHtml(source, { highlighter: escapeCode }))

Fence metadata enters the AST, but token markup requires an external highlighter.

Source: docs/core-concepts/syntax-profile.md

Tensions

Compatibility breadth versus bundle budget

Do not maximize conformance by default. Require target-corpus evidence, renderer coverage, and measured bundle cost before adding syntax.

Rich trusted output versus untrusted-content safety

Do not enable raw HTML, extension HTML, or highlighter markup globally to solve presentation needs. Scope each trusted callback to controlled content.

Parse-ahead performance versus option timing

Build cached ASTs with final parser options and document transforms. Keep required HTML render hooks active when rendering those cached documents.

Pre-Deploy Summary

  • Every content source is classified as trusted or untrusted.
  • Raw HTML, extension HTML, and highlighter output have explicit owners.
  • Application link, image, and final-sanitization policies are enforced.
  • The downstream corpus passes deterministic AST and renderer checks.
  • Unsupported syntax is documented rather than silently assumed.
  • Stable content is parsed once with final options and versioned cache keys.
  • Highlighting runs at build time or on the server where possible.
  • Narrow entry points and individual extensions are used.
  • Bundle budgets and HTML/React/Octane parity tests pass.
  • pnpm run verify passes before release.

Related Skills

  • render-markdown for the supported profile, AST, parser options, and core HTML rendering.
  • docs-features for docs metadata and code-fence behavior.
  • custom-extensions for parser hooks and trusted HTML extension boundaries.
  • react-rendering and octane-rendering for framework component policy and SSR parity.

Version History

  • 6936a01 Current 2026-09-21 23:55

Same Skill Collection

skills/custom-extensions/SKILL.md
skills/docs-features/SKILL.md
skills/octane-rendering/SKILL.md
skills/react-rendering/SKILL.md
skills/render-markdown/SKILL.md

Metadata

Files
0
Version
6936a01
Hash
f5a8acf2
Indexed
2026-09-21 23:55

Accueil - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-09-22 00:28
浙ICP备14020137号-1