主题
完整 Demo
Demo 的入口是传统 Vue 2 SFC App.vue,内部组合全部组件形态和语法功能。
每个功能示例都以独立的 .demo-card 呈现;说明、状态、操作结果和插槽内容均渲染在对应功能卡片内部,不在卡片外另行展示。
运行
bash
pnpm install
pnpm demo:dev生产与 SSR:
bash
pnpm demo:build
pnpm demo:ssr-build组件目录
text
demo/src/components/
├── traditional/ # template 与局部 JSX/TSX
├── options/ # Options API render
├── functional/ # 显式 functional 与箭头函数 sugar
├── composition/ # setup SFC 与独立模块
├── modules/ # 独立 JSX/TSX 与 HMR
├── features/ # 所有 JSX 语法功能
└── shared/ # template 辅助组件功能与文件映射
| 功能 | Demo 文件 |
|---|---|
| 传统 template | TraditionalCard.vue |
| SFC 局部 JSX | LocalJsxInSfc.vue |
| SFC 局部 TSX | LocalTsxInSfc.vue |
| Options JSX/TSX | OptionsRenderJsx.vue、OptionsRenderTsx.vue |
| Functional SFC | FunctionalSfcJsx.vue、FunctionalSfcTsx.vue |
| Functional sugar | FunctionalArrow.jsx、FunctionalArrow.tsx |
| setup SFC | SetupSfcJsx.vue、SetupSfcTsx.vue |
| setup context | SetupContextSfc.vue |
| setup module | SetupModule.jsx、SetupModule.tsx |
| 独立 JSX/TSX | StandaloneJsx.jsx、StandaloneTsx.tsx |
| VNodeData | VNodeDataDemo.vue |
| v-model | VModelDemo.vue |
| 标准事件属性与事件对象 | VOnDemo.vue |
| directives | DirectiveDemo.vue |
| slots | SlotsDemo.vue |
| spread | SpreadDemo.vue |
| SVG / Fragment | SvgFragmentDemo.tsx |
| HMR | HmrNamedCard.jsx |
| SSR | entry-server.ts |
Vite 配置
ts
import { defineConfig } from 'vite'
import vue2 from '@vitejs/plugin-vue2'
import vue2JsxOxc from 'vite-plugin-vue2-jsx-oxc'
export default defineConfig({
base: process.env.DEMO_BASE || '/',
plugins: [
vue2(),
vue2JsxOxc({
compositionAPI: 'native',
vOn: false,
fragment: 'array',
hmr: true,
ssr: true,
dependencyScan: true
})
],
server: {
port: 5178
},
build: {
sourcemap: true
}
})根组件
vue
<template>
<main class="demo-shell">
<header class="hero-panel">
<p class="eyebrow">Vite 8 · Vue 2.7 · Oxc Parser</p>
<h1>vite-plugin-vue2-jsx-oxc</h1>
<p class="hero-copy">
Vue 单文件组件、Options API、函数式组件、Composition API、JSX、TSX 与全部语法能力示例。
</p>
<div class="hero-badges">
<span>真实 .vue SFC</span>
<span>JSX + TSX</span>
<span>HMR + SSR</span>
</div>
</header>
<DemoSection
id="traditional"
title="Vue 单文件组件"
description="传统模板组件,以及在普通 Vue SFC 中局部声明 JSX/TSX 子组件。"
>
<TraditionalCard />
<LocalJsxInSfc />
<LocalTsxInSfc />
</DemoSection>
<DemoSection
id="options-api"
title="Options API render"
description="在 .vue 文件中使用 JSX 和 TSX script 编写 render。"
>
<OptionsRenderJsx />
<OptionsRenderTsx />
</DemoSection>
<DemoSection
id="functional"
title="函数式组件"
description="Vue 2 functional SFC 与 JSX/TSX 箭头函数语法糖。"
>
<FunctionalSfcJsx text="functional SFC / JSX" />
<FunctionalSfcTsx text="functional SFC / TSX" :count="functionalCount" />
<FunctionalArrowJsx label="functional arrow / JSX" @activate="functionalCount += 1" />
<FunctionalArrowTsx label="functional arrow / TSX" :value="functionalCount" />
</DemoSection>
<DemoSection
id="composition"
title="setup() 组合式组件"
description="Vue 2.7 原生 Composition API、setup context、render function 与 JSX/TSX 模块。"
>
<SetupSfcJsx />
<SetupSfcTsx />
<SetupRenderInstanceSfc />
<SetupContextSfc :ping-total="setupPings" data-source="setup-context" @ping="setupPings += 1">
<p class="section-note">setup context 默认插槽内容</p>
</SetupContextSfc>
<SetupModuleJsx />
<SetupModuleTsx />
</DemoSection>
<DemoSection
id="modules"
title="独立 JSX / TSX 组件"
description="不依赖 .vue 文件,直接使用 Vue.extend 或 defineComponent 输出组件。"
>
<StandaloneJsx />
<StandaloneTsx />
<HmrNamedCard />
</DemoSection>
<DemoSection
id="features"
title="Vue 2 JSX 功能覆盖"
description="VNodeData、事件、v-model、指令、插槽、spread、SVG、Fragment 等全部转换能力。"
>
<VNodeDataDemo />
<VModelDemo />
<VOnDemo />
<DirectiveDemo />
<SlotsDemo />
<SpreadDemo />
<SvgFragmentDemo />
</DemoSection>
<footer class="demo-footer">
修改任意 JSX、TSX 或 Vue SFC 文件可验证 HMR;执行 pnpm demo:ssr-build 可验证 SSR 转换。
</footer>
</main>
</template>
<script>
import DemoSection from './components/shared/DemoSection.vue'
import TraditionalCard from './components/traditional/TraditionalCard.vue'
import LocalJsxInSfc from './components/traditional/LocalJsxInSfc.vue'
import LocalTsxInSfc from './components/traditional/LocalTsxInSfc.vue'
import OptionsRenderJsx from './components/options/OptionsRenderJsx.vue'
import OptionsRenderTsx from './components/options/OptionsRenderTsx.vue'
import FunctionalSfcJsx from './components/functional/FunctionalSfcJsx.vue'
import FunctionalSfcTsx from './components/functional/FunctionalSfcTsx.vue'
import { FunctionalArrowJsx } from './components/functional/FunctionalArrow.jsx'
import { FunctionalArrowTsx } from './components/functional/FunctionalArrow.tsx'
import SetupSfcJsx from './components/composition/SetupSfcJsx.vue'
import SetupSfcTsx from './components/composition/SetupSfcTsx.vue'
import SetupContextSfc from './components/composition/SetupContextSfc.vue'
import SetupRenderInstanceSfc from './components/composition/SetupRenderInstanceSfc.vue'
import SetupModuleJsx from './components/composition/SetupModule.jsx'
import SetupModuleTsx from './components/composition/SetupModule.tsx'
import StandaloneJsx from './components/modules/StandaloneJsx.jsx'
import StandaloneTsx from './components/modules/StandaloneTsx.tsx'
import { HmrNamedCard } from './components/modules/HmrNamedCard.jsx'
import VNodeDataDemo from './components/features/VNodeDataDemo.vue'
import VModelDemo from './components/features/VModelDemo.vue'
import VOnDemo from './components/features/VOnDemo.vue'
import DirectiveDemo from './components/features/DirectiveDemo.vue'
import SlotsDemo from './components/features/SlotsDemo.vue'
import SpreadDemo from './components/features/SpreadDemo.vue'
import SvgFragmentDemo from './components/features/SvgFragmentDemo.tsx'
export default {
name: 'DemoApp',
components: {
DemoSection,
TraditionalCard,
LocalJsxInSfc,
LocalTsxInSfc,
OptionsRenderJsx,
OptionsRenderTsx,
FunctionalSfcJsx,
FunctionalSfcTsx,
FunctionalArrowJsx,
FunctionalArrowTsx,
SetupSfcJsx,
SetupSfcTsx,
SetupContextSfc,
SetupRenderInstanceSfc,
SetupModuleJsx,
SetupModuleTsx,
StandaloneJsx,
StandaloneTsx,
HmrNamedCard,
VNodeDataDemo,
VModelDemo,
VOnDemo,
DirectiveDemo,
SlotsDemo,
SpreadDemo,
SvgFragmentDemo
},
data() {
return {
functionalCount: 0,
setupPings: 0
}
}
}
</script>