vue3tohtml

将 Vue 3 单文件组件 SSR 渲染为纯静态 HTML——零 JavaScript 产物,截图与预览首选
523
Install
npm install vue3tohtml
Latest Version:1.2.0
Vue:3
License:MIT
Last Updated:Sep 22, 2026
Links: GitHub  ·  npm
Maintainer: akinohra

vue3tohtml

将 Vue 3 单文件组件 (.vue) SSR 渲染为纯静态 HTML——不含任何 JavaScript, 打开即有完整内容,无头浏览器截图、缩略图生成、静态预览的首选方案。

特性

  • ✅ 支持完整的 Vue 3 模板语法(v-if / v-for / v-model / v-html / 插值)
  • ✅ 支持 <script setup> + Composition API(ref / computed / watch)
  • ✅ 支持 TypeScript(类型注解自动剥离)
  • ✅ scoped 样式在静态输出中真实生效
  • ✅ 零 JavaScript 产物:无网络请求、无 JS 执行、无白屏等待
  • ✅ 内容哈希缓存:首次渲染 ~150ms,同组件再次渲染 < 1ms

架构

架构图

调用方(Node 脚本 / Express / Puppeteer)→ index.ts(API 入口)→ ssr.ts(渲染层:缓存查询、组件求值、renderToString)→ compiler.ts(编译层:compileSFC、scoped 样式、TS 剥离)→ 纯静态 HTML。缓存命中时跳过编译与求值,直接复用已求值的组件模块(<1ms)。

交互版(深浅色切换、导出 PNG/SVG):docs/architecture.html

安装

# 作为 npm 包使用(发布后)
npm install vue3tohtml

# 本地开发
pnpm install
npm run build   # 构建 dist/(发布产物)

快速开始

import { writeFile } from 'fs/promises'
import { compileVueToStaticHTML } from 'vue3tohtml'

// 传 .vue 文件路径,返回静态 HTML 字符串
const html = await compileVueToStaticHTML('./App.vue', {
  title: 'My Demo',       // 可选,不传默认取文件名(App.vue → App)
})

await writeFile('output.html', html)
// 浏览器打开 output.html:完整内容 + 样式,零 JS、零网络依赖

API

函数 说明
compileVueToStaticHTML(filePath, options?) 从 .vue 文件渲染完整静态 HTML
compileVueToStaticHTMLFromCode(code, options?) 从 SFC 源码字符串渲染完整静态 HTML
renderVueToString(code, options?) 渲染为 HTML 片段 + 样式(无文档壳),适合直接喂无头浏览器
compileSFC(source, options?) 编译为编译结果对象 { script, styles, scopeId, descriptor }
generateStaticHTML(appHtml, styles, options?) 片段 + 样式组装为 HTML 文档

选项(所有渲染函数通用):

interface RenderOptions {
  title?: string    // 页面标题。文件路径 API 不传时默认取文件名;
                    // 源码 API 不传时默认 'Vue SFC Preview'。会被 HTML 转义
  filename?: string // 文件名,用于错误提示与样式预处理
  props?: Record<string, unknown> // 传给根组件的 props(JSON 对象),
                                  // 组件内用 defineProps 接收,每次调用独立生效
}

传入 props(每次调用可传不同 JSON 数据):

import { compileVueToStaticHTMLFromCode } from 'vue3tohtml'

// 组件内用 defineProps 声明接收
const code = `
<script setup lang="ts">
defineProps<{ user: { name: string; tags: string[] } }>()
</script>
<template>
  <h1>{{ user.name }}</h1>
  <ul><li v-for="tag in user.tags" :key="tag">{{ tag }}</li></ul>
</template>`

const html = await compileVueToStaticHTMLFromCode(code, {
  props: { user: { name: 'Alice', tags: ['a', 'b'] } },
})

同一组件(源码不变)每次调用传不同的 props 会得到不同渲染结果——模块缓存只复用编译产物,setup() 每次渲染重新执行,无状态残留。

使用场景

场景一:批量截图 / 缩略图

import { compileVueToStaticHTMLFromCode } from 'vue3tohtml'

const components = [code1, code2, code3] // SFC 源码数组
const pages = await Promise.all(
  components.map(code => compileVueToStaticHTMLFromCode(code)),
)
// 逐个交给无头浏览器截图;同组件重复渲染走缓存(<1ms)

场景二:Puppeteer 直喂(不写临时文件)

import { renderVueToString } from 'vue3tohtml'

const { appHtml, styles } = await renderVueToString(vueCode)
const css = styles.map(s => s.code).join('\n')
await page.setContent(`<!DOCTYPE html><html><head><style>${css}</style></head>
<body><div id="app">${appHtml}</div></body></html>`)
const screenshot = await page.screenshot()

场景三:HTTP 渲染服务(Express)

import express from 'express'
import { compileVueToStaticHTMLFromCode } from 'vue3tohtml'

const app = express()
app.use(express.json())

app.post('/api/render', async (req, res) => {
  try {
    const html = await compileVueToStaticHTMLFromCode(req.body.code)
    res.type('html').send(html)
  } catch (error) {
    res.status(400).json({ error: (error as Error).message })
  }
})

app.listen(3000)

支持的 Vue 特性

类别 支持情况
模板语法 插值、v-if / v-for / v-model / v-html、class / style 绑定
Script <script setup>、Composition API(ref / reactive / computed / watch)
TypeScript lang="ts" 类型注解自动剥离(as 断言、泛型、interface 等全支持)
样式 scoped CSS(静态输出中真实生效)、CSS 预处理器(需额外安装 sass/less)
无 script 组件 纯 template 的 .vue 同样可渲染

限制与注意事项

产物是静态快照:

  • onMounted 等浏览器生命周期不执行、事件绑定(@click 等)不生效
  • setup 顶层不能访问 window / document(Node 环境没有;放进 onMounted 即可)
  • 插值、computed、v-for 等渲染时求值的特性全部正常

安全(重要): 渲染会在 Node 进程内执行 SFC 中的脚本代码。 如果组件来源不可信(用户提交、AI 生成),请在隔离环境(容器、独立 worker)中运行。

常见问题:

  • 需要 CDN 或网络吗? 不需要,所有渲染在 Node 内完成,产物自包含
  • 生成的 HTML 可以部署吗? 可以,直接扔到任何静态服务器
  • 如何自定义基础样式? 修改 src/ssr.ts 中的 BASE_STYLES 后重新 build

开发

npm run typecheck  # TypeScript 类型检查(tsc --noEmit)
npm test           # 自动化测试(node:test,夹具来自 examples/)
npm run build      # 构建 dist/

手动渲染单个 .vue 查看:

node -e "import('fs').then(async fs => { const { compileVueToStaticHTML } = await import('./src/index.ts'); fs.writeFileSync('../output.html', await compileVueToStaticHTML('examples/Showcase.vue')) })"

源码为 TypeScript:开发时由 Node 原生 type stripping 直接运行(Node >= 23.6, import 需写显式 .ts 扩展名);发布产物为 dist/ 下编译后的纯 JS + .d.ts。

项目结构

vue3tohtml/
├── src/
│   ├── index.ts     # API 入口
│   ├── compiler.ts  # SFC 编译(ssrRender + 样式)
│   └── ssr.ts       # 组件求值 + renderToString + 缓存 + HTML 组装
├── test/
│   └── ssr.test.ts  # 自动化测试
├── docs/
│   ├── architecture.html  # 交互版架构图(主题切换 + 导出)
│   └── architecture.svg   # README 内嵌用双主题架构图
├── examples/        # 测试夹具 + 示例组件
│   ├── Showcase.vue # 展示页(全特性试金石)
│   ├── TodoApp.vue  # v-for / v-model / computed
│   ├── App.vue      # TypeScript + scoped
│   ├── Simple.vue   # 基础组件
│   └── TemplateOnly.vue # 无 script 块
└── tsconfig.json

许可证

MIT

Related Packages

vue3renderer

渲染器:把 .vue 单文件组件或网页渲染成 PNG 截图,常驻浏览器、并发限流、props 数...

715
@farm.js/vue

Vue renderer for FARMJS applications

1,185 577
j-vue

.vue single-file component back-end compiler. Belong to "Plan J"./.vue 单文件组...

6,068 7
vue-server-renderer

server renderer for Vue 2.0

13,054,069 212,644
@vue/component-compiler

bundler agnostic API for compiling Vue SFC

3,126,609 343

Version History

Version Released Vue License
1.2.0 ^3.5.43 MIT
1.1.0 ^3.5.43 MIT
1.0.0 ^3.5.43 MIT