# uni-render
**Repository Path**: alamhubb/uni-render
## Basic Information
- **Project Name**: uni-render
- **Description**: 在uniapp端支持原生vue,而非uniapp魔改后的vue,
优势,支持vue的渲染函数,通过vue的custom-render,
劣势,运行时解决方案,性能不如uniapp的编译时方案
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-12-26
- **Last Updated**: 2026-01-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# uni-render
[](https://www.npmjs.com/package/uni-render)
[](https://www.npmjs.com/package/uni-render)
[](https://github.com/AlamHubb/uni-render/blob/main/LICENSE)
让 UniApp 支持 Vue 渲染函数(h 函数)开发,兼容 H5 和微信小程序。
## 🚀 快速开始
### 方式一:使用脚手架(推荐)
```bash
# 创建新项目(不指定项目名时,默认使用 my-uni-render-project)
npx create-uni-render
# 或指定项目名
npx create-uni-render my-app
# 进入项目目录
cd my-uni-render-project
# 安装依赖
npm install
# 启动 H5 开发
npm run dev:h5
# 启动微信小程序开发
npm run dev:mp-weixin
```
### 方式二:在现有项目中安装
```bash
# 安装核心依赖
npm install uni-render vite-plugin-uni-render
# 或使用 pnpm
pnpm add uni-render vite-plugin-uni-render
```
在 `vite.config.ts` 中配置:
```typescript
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import { uniRender } from 'vite-plugin-uni-render'
export default defineConfig({
plugins: [
uniRender(),
uni()
]
})
```
### 编写组件
**Page 组件(pages/index/index.vue)**:
```vue
```
**普通组件(components/HelloWorld.vue)**:
```vue
```
**使用渲染函数的组件示例**:
```typescript
// components/Counter.ts
import { ref, h, defineComponent } from 'uni-render'
export default defineComponent({
setup() {
const count = ref(0)
return () => h('view', { class: 'counter' }, [
h('text', { class: 'title' }, '计数器'),
h('text', { class: 'count' }, `当前值: ${count.value}`),
h('button', {
onClick: () => count.value++
}, '点击 +1')
])
}
})
```
## 📦 包说明
| 包名 | 说明 | 安装 |
|------|------|------|
| `uni-render` | 核心运行时库,提供 `h`、`ref`、`defineRenderComponent` 等 API | `npm install uni-render` |
| `vite-plugin-uni-render` | Vite 插件,自动转换 Vue 组件 | `npm install vite-plugin-uni-render -D` |
| `create-uni-render` | 项目脚手架,快速创建新项目 | `npx create-uni-render` |
## ✨ 核心特性
- ✅ **标准 Vue 语法**:使用 `h` 函数编写组件,无需学习 UniApp 模板语法
- ✅ **自动转换**:插件自动处理 `vue → uni-render` 导入转换
- ✅ **兼容小程序**:支持微信小程序、支付宝小程序等
- ✅ **响应式支持**:完整的 Vue 3 响应式系统
- ✅ **零配置**:开箱即用,无需额外配置
---
## 📖 详细文档
将 Vue 渲染函数组件转换为 UniApp 兼容格式的工具链。
## 核心概念
本项目的目标是让开发者能够使用 Vue 的 `h` 函数(渲染函数)来编写 UniApp 组件,而不是使用 UniApp 的模板语法。
通过自定义渲染器 (`@vue/runtime-core`),我们将 VNode 树转换为 `RenderNode` 数据结构,然后由 `RenderComponent` 渲染到真正的 UniApp 组件。
## 文件处理规则
### vite-plugin-uni-render 处理规则
| 文件类型 | 输出格式 | 处理方式 |
|---------|---------|---------|
| `main.ts` | 不处理 | UniApp 入口文件,需要真正的 `vue` |
| 其他 `.ts` 文件 | `.ts` | 替换 `import from 'vue'` → `import from 'uni-render'` |
| Page `.vue` (pages.json 配置) | `.vue` | `transform` hook:编译 + `defineRenderComponent` + `` template |
| 非 Page `.vue` | **虚拟模块 `.ts`** | `resolveId` 拦截 → 虚拟模块 → 纯 `.ts` + CSS 虚拟模块 |
### 详细说明
#### 1. `main.ts` - 不处理
UniApp 的入口文件,需要使用真正的 `vue` 包(`createSSRApp`)。
#### 2. 其他 `.ts` 文件
所有 `src/` 目录下的 `.ts` 文件(除 `main.ts`)都会被处理:
- 将 `import { xxx } from 'vue'` 替换为 `import { xxx } from 'uni-render'`
#### 3. Page 组件(`.vue`)
在 `pages.json` 中配置的页面组件:
- 保持 `.vue` 格式
- template 会被编译为渲染函数
- 使用 `defineRenderComponent` 包装
- 添加 `` 作为新的 template
#### 4. 非 Page 组件(虚拟模块)
不在 `pages.json` 中配置的 `.vue` 文件(包括 node_modules 中的):
- **`resolveId` hook 拦截**:将 `.vue` 导入重定向到虚拟模块 ID(`\0uni-render:xxx.ts`)
- **`load` hook 返回**:编译后的纯 `.ts` 代码
- **CSS 虚拟模块**:样式提取为独立虚拟模块(`virtual:unirender-css:xxx.vue.css`)
- UniApp 不会处理虚拟模块(以 `\0` 开头)
### `.vue` 文件两步处理
1. **合并 template 和 script**:
- 有 template + 无渲染函数 → template 转为 render 函数
- 有 template + 有渲染函数 → 抛弃 template,保留渲染函数
- 无 template + 有渲染函数 → 直接用渲染函数
2. **输出格式**:
- Page → `.vue`(带 `` template)
- Component → `.ts`(纯 TypeScript)
## 📁 项目结构
```
uni-render/
├── uni-render/ # 核心运行时库
│ ├── src/
│ │ ├── index.ts # 导出所有 API
│ │ ├── renderer/ # 自定义渲染器
│ │ ├── components/ # 运行时组件
│ │ └── event/ # 事件系统
│
├── vite-plugin-uni-render/ # Vite 插件
│ └── src/
│ ├── index.ts # 插件入口
│ └── uniRenderCompiler.ts # 编译器
│
├── create-uni-render/ # 项目脚手架
│ ├── bin/
│ │ └── index.js # 脚手架脚本
│ └── template/ # 项目模板
│
└── my-vue3-project/ # 示例项目
```
## 虚拟模块架构
### 为什么使用虚拟模块?
UniApp 的 Vite 插件会处理所有 `.vue` 文件。为了让非 Page 组件使用我们的 custom renderer 而不是 UniApp,我们使用虚拟模块绕过 UniApp 的处理。
### 虚拟模块 ID 规范
| 类型 | import 语句 | 内部虚拟模块 ID |
|-----|------------|----------------|
| 组件 TS | `import XXX from './HelloWorld.vue'` | `\0uni-render:D:/.../HelloWorld.ts` |
| 组件 CSS | `import 'virtual:unirender-css:xxx.vue.css'` | `\0unirender-css:xxx.vue.css` |
- `\0` 前缀是 Vite 虚拟模块约定
- 使用完整绝对路径,避免冲突
- `.ts` / `.css` 后缀让 Vite 正确识别模块类型
## 使用方式
### 1. 安装依赖
```bash
npm install uni-render vite-plugin-uni-render
```
### 2. 配置 vite.config.ts
```typescript
import uniRender from 'vite-plugin-uni-render'
export default defineConfig({
plugins: [
uniRender({ debug: true }), // 可选:打印转换日志
// ... 其他插件
]
})
```
### 3. 编写组件
**Page 组件(pages/index/index.vue)**
```vue
```
**普通组件(components/HelloWorld.vue)**
```vue
```
**使用渲染函数的组件(components/Counter.ts)**
```typescript
import { ref, h, defineComponent } from 'uni-render'
export default defineComponent({
setup() {
const count = ref(0)
return () => h('view', { class: 'counter' }, [
h('text', { class: 'title' }, '计数器'),
h('text', { class: 'count' }, `当前值: ${count.value}`),
h('button', {
onClick: () => count.value++
}, '点击 +1')
])
}
})
```
## ⚙️ 配置选项
### vite-plugin-uni-render 选项
| 选项 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `debug` | `boolean` | `false` | 是否开启调试日志,打印转换过程 |
```typescript
uniRender({
debug: true // 开启调试模式
})
```
## ⚠️ 注意事项
1. **导入来源**:在组件中使用 `import { ref, h } from 'uni-render'`,插件会自动处理 `vue → uni-render` 的转换
2. **样式处理**:非 Page 的 `.vue` 组件样式通过 CSS 虚拟模块处理,会自动注入到页面中
3. **响应式系统**:`ref`、`reactive` 等 API 从 `uni-render` 导入,使用完整的 Vue 3 响应式系统
4. **事件处理**:使用 `onClick`、`onInput` 等 Vue 风格的事件名,会自动转换为 UniApp 的事件格式
5. **Vue 版本**:要求 Vue 3.4.x 版本,确保兼容性
## 🔗 相关链接
- [uni-render 运行时库文档](./uni-render/README.md)
- [vite-plugin-uni-render 插件文档](./vite-plugin-uni-render/README.md)
- [create-uni-render 脚手架文档](./create-uni-render/README.md)
- [GitHub Issues](https://github.com/AlamHubb/uni-render/issues)
## 🏷️ 标签映射表
### customRenderer 标签转换(第一层)
在 Custom Renderer 中,HTML 标签会被转换为 UniApp 兼容的标签类型:
| HTML 标签 | → UniApp 类型 | 说明 |
|---------|--------------|-----|
| `div` | `view` | 块级容器 |
| `p` | `view` | 段落,作为块级元素处理 |
| `span` | `text` | 行内文本 |
| `img` | `image` | 图片 |
| `a` | `navigator` | 链接/导航 |
| `code` | `text` | 代码文本 |
| `h1`~`h6` | 原样保留 | 进入默认处理,渲染为 view |
| `view` | `view` | 保持不变 |
| `text` | `text` | 保持不变 |
| `image` | `image` | 保持不变 |
| `button` | `button` | 保持不变 |
| `input` | `input` | 保持不变 |
| `navigator` | `navigator` | 保持不变 |
| 其他 | 原样保留 | 进入 RenderComponent 默认处理 |
### RenderComponent 渲染(第二层)
RenderComponent 根据节点的 `type` 值渲染对应的 UniApp 组件:
| type 值 | 渲染为 | 特殊处理 |
|--------|-------|---------|
| `view` | `` | 支持 tap、longpress 事件 |
| `text` | `` | 支持文本内容和子节点 |
| `#text` | `` | 纯文本节点 |
| `button` | `