Skip to content

JSON DSL(renderDocx) ​

renderDocx() 接收可 JSON 序列化的 schema,适合 AI/LLM 驱动的生成、API 集成,以及将文档模板作为数据存储。

来自外部的 schema ​

平台默认实现面向可信 schema:Node 启用本地图片读取和 npm/local 插件,浏览器启用 URL 插件。处理 API 请求或 LLM 输出时,除了结构校验,还应明确限制运行时能力:

ts
import { renderDocx } from 'docx-kit/node'

const doc = await renderDocx(
  { content: [{ type: 'paragraph', text: 'External content' }] },
  { pluginLoader: false, resolveImage: false },
)
const bytes = await doc.toUint8Array()

这些选项也适用于 Figure 等可信插件编译的图片。请在应用代码中通过 .use() 注册可信插件。如需允许部分来源,可传入带 allowLoad 策略的 pluginLoader,并通过自定义 resolveImage 执行应用自身的资源边界检查。Manifest 和文档结构校验不会授权文件访问,也不会隔离可执行插件。

基础用法 ​

ts
import { renderDocx } from 'docx-kit'

const doc = await renderDocx({
  page: { size: 'A4', margin: '20mm' },
  styles: {
    h1: { fontSize: 24, fontWeight: 'bold' },
    p:  { fontSize: 12 },
  },
  content: [
    { type: 'heading',  level: 1, text: 'My Document', className: 'h1' },
    { type: 'paragraph', text: 'This document was generated from JSON.', className: 'p' },
    { type: 'pageBreak' },
    { type: 'heading',  level: 2, text: 'Section 2', className: 'h1' },
    { type: 'paragraph', text: 'More content...', className: 'p' },
  ],
})
const blob = await doc.toBlob()

Schema 结构 ​

ts
interface DocxSchema<TStyles> {
  content: BlockNode<TStyles>[]    // Ordered block nodes
  page?: DocxKitConfig['page']     // Page dimensions
  styles?: TStyles                 // Named stylesheet
}

全部节点类型 ​

标题节点 ​

ts
{
  type: 'heading',
  level: 1 | 2 | 3 | 4 | 5 | 6,
  text: string,
  className?: string,
  id?: string,
  style?: DocxStyleRule,
}
ts
{ type: 'heading', level: 1, text: 'Title', className: 'title' }
{ type: 'heading', level: 2, text: 'Section' }
{ type: 'heading', level: 3, text: 'Sub-section', id: 's1' }

段落节点 ​

ts
{
  type: 'paragraph',
  text: string,
  className?: string,
  id?: string,
  style?: DocxStyleRule,
  children?: InlineNode[],  // rich content
}
ts
// Simple
{ type: 'paragraph', text: 'A simple paragraph.', className: 'body' }

// Rich with inline children
{
  type: 'paragraph',
  children: [
    { type: 'text', text: 'Regular text ' },
    { type: 'text', text: 'bold text', style: { fontWeight: 'bold' } },
    { type: 'text', text: ' and back to normal.' },
  ],
}

图片节点 ​

ts
{
  type: 'image',
  data: string | Uint8Array | ArrayBuffer | Blob,
  width?: UnitValue,
  height?: UnitValue,
  alt?: string,
  imageType?: 'png' | 'jpeg' | 'jpg' | 'gif' | 'bmp',
  floating?: boolean | { wrap?: string, x?: UnitValue, y?: UnitValue },
  className?: string,
  style?: DocxStyleRule,
}

data 可直接接收字节、Blob 或 data URL。使用 docx-kit/node 的 renderDocx() 时,也支持本地文件路径与 file: URL。核心或浏览器调用方必须提供字节、data URL,或在运行时选项中提供显式 resolveImage 适配器,不会自动获取路径对应的内容。

表格节点 ​

ts
{
  type: 'table',
  columns: TableColumn[],
  data: Record<string, unknown>[],
  bordered?: boolean,
  striped?: boolean,
  header?: boolean,
  headerCellStyle?: DocxStyleRule,
  cellStyle?: DocxStyleRule,
  className?: string,
  style?: DocxStyleRule,
}
ts
{
  type: 'table',
  columns: [
    { key: 'name', title: 'Name' },
    { key: 'value', title: 'Value', align: 'right' },
    {
      key: 'trend',
      title: 'Trend',
      align: 'center',
      render: (val) => [
        { type: 'text', text: val as string, style: { color: '#22c55e' } },
      ],
    },
  ],
  data: [
    { name: 'Revenue', value: '$1.2M', trend: '↑ 15%' },
    { name: 'Costs', value: '$800K', trend: '↓ 3%' },
  ],
  bordered: true,
  headerCellStyle: { fontWeight: 'bold', backgroundColor: '#f5f5f5' },
}

分页节点 ​

ts
{ type: 'pageBreak' }

插件节点 ​

ts
{
  type: 'plugin',
  name: 'qrcode' | 'echarts' | string,  // registered plugin name
  options: Record<string, unknown>,      // plugin-specific options
  style?: DocxStyleRule,
}

重要: 插件节点要求在 schema 的 plugins 数组中声明插件,或在导出前通过 .use() 注册。

ts
import { echartsPlugin, qrcodePlugin, renderDocx } from 'docx-kit'

const doc = await renderDocx({ content: [...] })
doc
  .use(qrcodePlugin())
  .use(echartsPlugin())

const blob = await doc.toBlob()

完整 JSON 示例 ​

ts
import { echartsPlugin, qrcodePlugin, renderDocx } from 'docx-kit'

const report = {
  page: { size: 'A4', margin: '20mm 25mm' },
  styles: {
    title: { fontSize: 28, fontWeight: 'bold', color: '#1a1a2e', textAlign: 'center' },
    h2: { fontSize: 18, fontWeight: 'bold', color: '#333' },
    body: { fontSize: 12, lineHeight: 1.5 },
    small: { fontSize: 9, color: '#999' },
  },
  content: [
    { type: 'heading', level: 1, text: 'Monthly Report', className: 'title' },
    { type: 'paragraph', text: 'June 2026', className: 'small', style: { textAlign: 'center' } },

    { type: 'heading', level: 2, text: 'Executive Summary', className: 'h2' },
    { type: 'paragraph', text: 'Revenue exceeded projections by 12%. Key product lines showed strong growth across all regions.', className: 'body' },

    { type: 'heading', level: 2, text: 'Key Metrics', className: 'h2' },
    {
      type: 'table',
      columns: [
        { key: 'metric', title: 'Metric' },
        { key: 'value', title: 'Value', align: 'right' },
        { key: 'change', title: 'Change', align: 'center' },
      ],
      data: [
        { metric: 'Total Revenue', value: '$1.45M', change: '+12%' },
        { metric: 'New Customers', value: '847', change: '+23%' },
        { metric: 'Churn Rate', value: '2.1%', change: '-0.5%' },
        { metric: 'NPS Score', value: '72', change: '+5' },
      ],
      bordered: true,
      striped: true,
      headerCellStyle: { fontWeight: 'bold', backgroundColor: '#f8f9fa' },
    },

    { type: 'pageBreak' },

    { type: 'heading', level: 2, text: 'Revenue Chart', className: 'h2' },
    {
      type: 'plugin',
      name: 'echarts',
      options: {
        option: {
          title: { text: 'Monthly Revenue' },
          xAxis: { data: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'] },
          yAxis: {},
          series: [{ type: 'bar', data: [200, 220, 250, 240, 270, 290] }],
        },
        caption: 'Figure 1: Monthly revenue trend',
      },
    },

    { type: 'heading', level: 2, text: 'Contact', className: 'h2' },
    {
      type: 'plugin',
      name: 'qrcode',
      options: {
        text: 'https://example.com/contact',
        size: 128,
        caption: 'Scan to visit our website',
      },
    },
  ],
}

// Build, register plugins, and export in the browser
const doc = await renderDocx(report)
doc
  .use(echartsPlugin())
  .use(qrcodePlugin())

const url = URL.createObjectURL(await doc.toBlob())
const anchor = document.createElement('a')
anchor.href = url
anchor.download = 'monthly-report.docx'
anchor.click()
URL.revokeObjectURL(url)

AI/LLM 集成 ​

JSON DSL 专为 AI 驱动的文档生成设计。向 LLM 提供 schema 结构,即可生成完整 .docx 文件:

ts
import { renderDocx } from 'docx-kit/node'

// Example: AI generates this JSON from a natural language prompt
const aiResponse = {
  page: { size: 'A4' },
  content: [
    { type: 'heading', level: 1, text: '{{TITLE}}' },
    { type: 'paragraph', text: '{{CONTENT}}' },
  ],
}

// Template interpolation
function fillTemplate(schema: any, vars: Record<string, string>) {
  const json = JSON.stringify(schema)
  const filled = json.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? '')
  return JSON.parse(filled)
}

const filled = fillTemplate(aiResponse, {
  TITLE: 'Q2 Earnings Report',
  CONTENT: 'Revenue grew 15% to $1.45M, exceeding analyst expectations.',
})

const doc = await renderDocx(filled)
await doc.save('ai-report.docx')

Released under the MIT License.