@wdcjs/harmonyos-jsx
v0.1.1
Published
使用 TSX 编写鸿蒙 HarmonyOS 原生应用,纯编译时转换为 ArkTS 声明式语法,零运行时开销
Maintainers
Readme
harmonyos-jsx
使用 TSX 编写鸿蒙 HarmonyOS 原生应用,纯编译时转换为 ArkTS 声明式语法,零运行时开销。
@wdcjs/harmonyos-jsx 不引入任何运行时框架,不创建 Virtual DOM,直接把 TSX 源码编译为等效的原生 ArkTS 代码,保持鸿蒙原生应用的性能表现。
设计理念
- 纯编译时转换:TSX → 原生 ArkTS,无运行时、无额外依赖
- 镜像目录结构:
tsx/目录与ets/目录一一对应,增量编译 - 原生状态管理:直接使用鸿蒙
@State、@Prop、@Link等装饰器 - 链式调用映射:JSX 属性自动映射为 ArkTS 链式方法(
.width()、.height()、.onClick()) - VS Code 优先:推荐使用 VS Code 编写 TSX,对 TSX 有原生一等支持(语法高亮、补全、重构)
快速开始
安装
推荐局部安装到项目 devDependencies(避免全局版本冲突,确保团队版本一致):
pnpm add -D @wdcjs/harmonyos-jsx局部安装后通过 pnpm exec hsx 调用,或在 package.json 的 scripts 中直接使用。
也可以全局安装(便于在任意目录直接使用 hsx 命令):
pnpm add -g @wdcjs/harmonyos-jsx
hsx --version配置 npm scripts(自动)
首次运行 hsx dev 或 hsx build 时,会自动检测项目根目录的 package.json,若不存在 dev/build/clean scripts,则自动注入:
{
"scripts": {
"dev": "hsx dev",
"build": "hsx build",
"clean": "hsx clean"
}
}已存在的同名 scripts 不会被覆盖,你可以安全自定义。注入后即可直接通过 pnpm dev / pnpm build / pnpm clean 使用。
使用 VS Code 开发
推荐使用 VS Code 作为主要开发编辑器,VS Code 对 TSX 有原生的语法高亮、自动补全、括号匹配、重构等支持,无需额外插件。
执行初始化命令后会自动在项目根目录生成 .vscode/settings.json,确保 .tsx 文件被正确识别为 TypeScript JSX 格式:
pnpm exec hsx # 局部安装
# 或
hsx # 全局安装关于 TypeScript:编译器使用 Babel 解析 TSX,不需要安装
typescript包即可编译和获得基本的语法高亮。VS Code 内置了 TypeScript 语言服务,能读取tsconfig.json和arkts-global.d.ts声明文件提供完整的类型提示和组件属性补全。如需更严格的类型检查,可执行pnpm add -D typescript安装。
首次执行将:
- 在项目根目录创建
.vscode/settings.json(自动关联*.tsx为 TypeScript JSX) - 在项目根目录的
package.json中自动注入dev/build/cleanscripts(已存在则不覆盖) - 在
entry/src/main/ets/下创建tsx/目录(TSX 源码目录,与 ets 结构镜像) - 生成
tsx/pages/Index.tsx示例页面 - 生成
arkts-global.d.ts(ArkTS 装饰器/组件类型声明)和tsconfig.json配置
VS Code 智能提示
通过自动生成的 arkts-global.d.ts 类型声明文件,VS Code 提供以下智能提示能力:
- 装饰器提示:
@Entry、@Component、@State、@Prop、@Link、@Builder等装饰器悬停时显示文档说明 - 组件属性补全:输入
<Column后自动列出可用属性(width、height、alignItems、justifyContent等) - 枚举值提示:输入
alignItems="后弹出"center" | "start" | "end"等有效值,输入错误值时会标红 - 属性类型检查:传入类型错误的属性值(如字符串给数字类型)会标红提示
- 事件补全:输入
on后自动补全onClick、onChange、onAppear等事件 - 覆盖 40+ 组件:Column、Row、Stack、Flex、List、Text、Button、Image、TextInput、Scroll、Tabs、Swiper 等常用组件均有完整类型定义
这些提示完全由 VS Code 内置的 TypeScript 语言服务驱动,无需安装任何额外插件。
目录结构
项目根目录/
├── .vscode/
│ └── settings.json # VS Code 配置(自动生成,关联 *.tsx 语法高亮)
├── entry/src/main/ets/
│ ├── tsx/ # TSX 源码(你编写的代码)
│ │ ├── pages/
│ │ │ └── Index.tsx
│ │ └── components/
│ │ └── MyComponent.tsx
│ ├── pages/ # 编译生成的 ArkTS(勿手动修改)
│ │ └── Index.ets
│ └── components/
│ └── MyComponent.ets
└── package.json编译产物会镜像 tsx/ 的目录结构输出到对应的 ets/ 位置。
开发流程
- 用 VS Code 打开项目根目录
- 运行
pnpm dev启动监听模式 - 在
tsx/目录下编写.tsx文件,保存即自动编译为.ets - 编译产物可直接被 DevEco Studio 用于预览和真机构建
命令
| 命令 | 说明 |
|------|------|
| hsx dev | 启动开发模式,监听 tsx/**/*.tsx 文件变化,增量编译 |
| hsx build | 一次性编译所有 TSX 文件 |
| hsx clean | 清理所有编译生成的 .ets 文件 |
所有命令支持 -r, --root <path> 选项指定项目根目录(默认为当前目录)。
局部安装时通过 pnpm exec 调用:
pnpm exec hsx dev # 开发模式,监听文件变化
pnpm exec hsx build # 一次性构建
pnpm exec hsx clean # 清理编译产物
pnpm exec hsx build -r ./e2e # 指定子目录作为项目根目录配置好 scripts 后可直接:
pnpm dev
pnpm build
pnpm cleanTSX 语法
基本组件
@Entry
@Component
class Index {
@State count: number = 0
build() {
return (
<Column space={10} width="100%" height="100%" alignItems="center" justifyContent="center">
<Text fontSize={40} fontColor="#333">Count: {this.count}</Text>
<Button type={ButtonType.Capsule} onClick={() => this.count++}>
Click +1
</Button>
</Column>
)
}
}编译为原生 ArkTS:
@Entry
@Component
struct Index {
@State count: number = 0
build() {
Column({ space: 10 }) {
Text(`Count: ${this.count}`).fontSize(40).fontColor("#333")
Button("Click +1", { type: ButtonType.Capsule }).onClick(() => this.count++)
}.width("100%").height("100%").alignItems("center").justifyContent("center")
}
}属性映射规则
JSX 属性按以下优先级映射:
- 构造参数:组件的构造函数参数(如
Column的space、Button的type)放在({ ... })中 - 事件:以
on开头的属性(onClick、onChange等)映射为.onXxx()链式调用 - 文本内容:
Text、Button等组件的子文本作为第一个构造参数(支持模板字符串插值) - 链式属性:其余属性(
width、height、fontSize等)映射为.xxx()链式调用 - style 对象:
style={{ width: 100, height: 50 }}会展开为多个链式调用
条件渲染
{this.show && <Text>visible</Text>}
{this.on ? <Text>On</Text> : <Text>Off</Text>}编译为:
if (this.show) {
Text("visible")
}
if (this.on) {
Text("On")
} else {
Text("Off")
}列表渲染
{this.list.map(item => <Text>{item.name}</Text>)}编译为:
ForEach(this.list, (item: any) => {
Text(item.name)
}, (item: any) => item.id ?? item)自定义组件
PascalCase 开头的组件视为自定义组件,所有属性作为构造参数传入:
<MyCard title="Hello" desc="World" onClick={this.handleClick} />编译为:
MyCard({ title: "Hello", desc: "World", onClick: this.handleClick })注意事项
- 组件类请使用
class关键字定义(编译器会自动转换为struct) - 所有鸿蒙原生装饰器(
@Entry、@Component、@State、@Prop、@Link、@Builder等)保持原样使用 - TSX 文件需放在
tsx/目录下,编译输出到对应的ets/位置 - 请勿手动修改编译生成的
.ets文件,它们会在下次编译时被覆盖 - 推荐使用 VS Code 开发,初始化时已自动配置
.vscode/settings.json确保 TSX 语法高亮
开发
pnpm install
pnpm test # 运行单元测试License
MIT
