Dioxus VSCode 扩展指南:在编辑器内自动格式化 RSX、HTML 转 RSX 与源码级构建
【免费下载链接】dioxusFullstack app framework for web, desktop, and mobile.项目地址: https://gitcode.com/GitHub_Trending/di/dioxus
本文以 packages/extension/README.md 为骨架,结合其 TypeScript 入口、Rust/WASM 导出层与 Cargo/package 配置,系统讲解 Dioxus VSCode 扩展的四大命令(HTML 转 RSX、HTML 转 Dioxus Component、Format RSX、Format RSX Document)、保存即格式化的dioxus.formatOnSave配置,以及如何从源码构建出.vsix安装包。读完本文,你将能够像维护者一样使用这套“编辑器侧封装 Dioxus CLI 能力”的工具链,并理解其格式化、翻译能力的底层实现来源。
扩展的定位:把 Dioxus CLI 的核心能力搬进编辑器
Dioxus 是面向 Web、桌面与移动端的全栈应用框架,其 UI 使用 Rust 中的rsx!宏描述。手写 RSX 时缩进、括号与 HTML 标签转换极易出错,因此官方在 packages/extension 维护了一个 VSCode 扩展:
This extension wraps functionality in Dioxus CLI to be used in your editor!
与把格式化逻辑在 TypeScript 中重复实现一遍不同,该扩展把 Rust 侧已有的工具库(dioxus-autofmt负责 RSX 格式化、dioxus-rsx-rosetta负责 HTML 转 RSX)编译为 WebAssembly,再由 VSCode 扩展宿主直接调用。这意味着编辑器里的格式化结果与命令行/Dioxus CLI 保持一致,且扩展本体可以打包成一个纯 JS/WASM 产物,不依赖本地安装额外的二进制工具(除从源码构建时需要 Rust 工具链外)。
扩展声明的能力清单(摘自 README):
- Auto-format RSX(保存文件时自动格式化 RSX);
- Convert HTML to RSX(把选中 HTML 片段转换为合法 rsx);
- Convert HTML to Dioxus Component(转换为 Dioxus 组件,并把内联 SVG 抽成独立模块);
- Format RSX(格式化当前文件/选区中的 RSX)。
从 manifest 看命令注册与激活方式
扩展的运行时清单位于 packages/extension/package.json。几个值得注意的关键点:
"activationEvents": ["onLanguage:rust"]:仅在打开 Rust 文件时激活扩展;"main": "./out/main.js":webpack 打包后的入口由 packages/extension/webpack.config.js 生成到out目录,并以commonjs2作为库目标输出;"extensionKind": ["ui", "workspace"]:扩展同时支持在 UI 侧与工作区侧运行;- 通过
contributes.commands注册了 4 个命令:
| 命令 ID | 命令面板标题 | 作用 |
|---|---|---|
extension.htmlToDioxusRsx | Dioxus: Convert HTML to RSX | 将选中 HTML 翻译为 RSX |
extension.htmlToDioxusComponent | Dioxus: Convert HTML to Component | 将选中 HTML 翻译为 Dioxus 组件 |
extension.formatRsx | Dioxus: Format RSX | 格式化当前选区(自动补全到完整花括号块) |
extension.formatRsxDocument | Dioxus: Format RSX Document | 格式化整个 Rust 文档 |
dioxus.formatOnSave配置的三档取值及语义见后文“保存即格式化”一节。
命令背后的实现细节(TypeScript 入口)
扩展激活逻辑在 packages/extension/src/main.ts。activate()的第一步是从磁盘pkg/dioxus_ext_bg.wasm读取 WASM 字节并调用init()。注释中特别解释了原因:wasm-bindgen 默认生成的胶水代码依赖fetch加载 WASM,而 VSCode 扩展宿主环境没有fetch,因此这里直接以字节缓冲方式初始化,绕开 fetch 机制。
随后注册两个格式化钩子与 4 条命令:
context.subscriptions.push( vscode.workspace.onWillSaveTextDocument(formatOnSave) ); context.subscriptions.push( vscode.commands.registerCommand('extension.htmlToDioxusRsx', () => translate(false)), vscode.commands.registerCommand('extension.htmlToDioxusComponent', () => translate(true)), vscode.commands.registerCommand('extension.formatRsx', fmtSelection), vscode.commands.registerCommand('extension.formatRsxDocument', formatRsxDocument) );HTML 转 RSX / 转 Component:translate(false | true)
两个 HTML 翻译命令共用同一个translate(component)函数:
- 读取当前
activeTextEditor的选区文本; - 若选区为空,弹出提示
"Please select HTML fragment before invoking this command!"并返回; - 调用
dioxus.translate_rsx(html, component),其中第二个布尔参数决定是否生成组件形态; - 返回字符串非空则用
editor.edit替换选区;为空则提示"Errors occurred while translating, make sure this block of HTML is valid"。
README 对“Convert HTML to Dioxus Component”有额外说明:转换时会生成一个合法的 Dioxus 组件,且把所有 SVG 抽离到各自独立的模块(module)中,方便复用与维护图标资源。
Format RSX 命令:fmtSelection 的选区智能扩展
fmtSelection并非只格式化光标所在行,它做了两步“选区补全”,保证能拿到完整的rsx!{ ... }块:
- 把选区横向扩到整行(从选中行首到结束行尾字符);
- 循环统计花括号配对:只要开括号
{数量大于闭括号}数量,就继续向下扩展一行,直到括号闭合或到达文件末尾。
随后,通过统计选区上方文本的花括号深度计算base_indentation,结合编辑器的tabSize与insertSpaces设置,调用 WASM 侧的dioxus.format_selection(...),最后按基础缩进为结果补空格或 Tab。若格式化抛错,会提示确认已安装最新版 Dioxus CLI 且选中了合法 rsx(错误信息同时给出 Rust 侧提示),因为部分格式化路径仍以 CLI/rustfmt 为后盾。
保存即格式化:onWillSaveTextDocument + waitUntil
扩展通过vscode.workspace.onWillSaveTextDocument挂入保存管线,并且刻意使用e.waitUntil(...)让返回的TextEdit[]在保存完成前生效——这是与 VSCode 保存流程正确同步的关键。main.ts 源码注释明确说明它“与其他格式化器(如 rust-analyzer)并行运行”,因此rustfmt负责普通 Rust 代码、Dioxus 扩展负责rsx!块,二者互不冲突。
formatOnSave的判定顺序是:文档语言必须是rust→ 读取该文档作用域的dioxus.formatOnSave→ 仅当其值不等于'disabled'时才执行。也就是说即使editor.formatOnSave被关闭,只要dioxus.formatOnSave显式设为enabled,保存时仍会格式化 RSX;反之设为disabled则任何情况下都不格式化。
Format RSX Document 命令与 dioxus.formatOnSave 配置
dioxus.formatOnSave由 package.json 的contributes.configuration声明,类型为字符串枚举,默认值及含义如下:
| 取值 | 行为 |
|---|---|
followFormatOnSave(默认) | 仅在编辑器editor.formatOnSave开启时,保存 Rust 文件才格式化 RSX |
enabled | 只要保存 Rust 文件就总是格式化 RSX |
disabled | 保存文件时从不格式化 RSX |
formatRsxDocument命令则直接调用与formatOnSave相同的formatDocument逻辑,只是通过WorkspaceEdit立即应用结果,方便手动触发整文档格式化。
Rust/WASM 导出层:四条命令如何落到真实逻辑
扩展并非重复造轮子,命令最终都调用 Rust 侧通过#[wasm_bindgen]导出的函数,这些函数定义在 packages/extension/src/lib.rs,其 Cargo 依赖见 packages/extension/Cargo.toml:wasm-bindgen、dioxus-autofmt、dioxus-rsx-rosetta、html_parser、syn,且crate-type = ["cdylib", "rlib"]以便产出 WASM。导出面共有四组:
format_rsx(raw, use_tabs, indent_size) -> String:调用dioxus_autofmt::fmt_block,根据布尔值选择IndentType::Tabs或IndentType::Spaces,缩进宽度为indent_size;format_selection(raw, use_tabs, indent_size, base_indent) -> String:同上,但把base_indent传入fmt_block作为基准缩进——对应编辑器里选区上方嵌套层级深、需要把格式化结果“塞回”原缩进层级的情形;format_file(contents, use_tabs, indent_size) -> FormatBlockInstance:先以syn::parse_file解析整个文件,再交由dioxus_autofmt::try_fmt_file找出文件内所有可格式化的rsx!宏块,最后用apply_formats合并成新文本。FormatBlockInstance暴露formatted()与length()(内部保存Vec<FormattedBlock>,长度表示实际产生了几处修改,TypeScript 侧据此判断“是否有变化可应用”);translate_rsx(contents, component) -> String:先由html_parser::Dom::parse保证输入是合法 HTML,再用dioxus_rsx_rosetta::rsx_from_html转成 RSX 调用体,最后经dioxus_autofmt::write_block_out输出规范排版的 RSX 文本。
从源码结构看,扩展在“格式化”场景走的是全文件精确映射路线:dioxus-autofmt会收集文件中每个rsx!宏的字节偏移并产出FormattedBlock(见 packages/autofmt/src/lib.rs 中FormattedBlock { formatted, start, end }的定义与try_fmt_file的“嵌套 RSX 自动处理、表达式不完整即提前返回”策略),这与format_file接口完全对应,也为将来把整块重写改成逐行精准小编辑预留了接口设计空间。
从源码构建扩展(.vsix)
README 给出三条构建前置步骤。结合 package.json 的 scripts 可以做更完整的还原:
- 安装 wasm-bindgen-cli(版本需匹配):README 原文为
cargo binstall wasm-bindgen-cli,确保与 Cargo.lock 中 wasm-bindgen 版本一致,否则绑定生成可能不兼容; - 安装 Node 依赖:在
packages/extension目录执行npm install; - 生成 .vsix:执行
npm run vsix(其内部调用vsce package,而vscode:prepublish钩子会先执行npm run build-base)。
build-base脚本链完整展示了从 Rust 到 VSCode 插件的流水线:
cargo build --target wasm32-unknown-unknown --release # 编译出 pkg/dioxus_ext.wasm wasm-bindgen --out-dir=pkg --target=web \ --omit-default-module-path --omit-imports pkg/dioxus_ext.wasm # 生成 web 胶水与 .d.ts webpack --mode development # 打包 main.ts → out/main.js最终pkg/目录(其清单见 packages/extension/pkg/package.json,以本地依赖"dioxus-ext": "./pkg"引入)同时提供dioxus_ext.js、dioxus_ext.d.ts与.wasm文件,供 src/main.ts 以import init, * as dioxus from 'dioxus-ext'的方式调用。开发期还可使用npm run watch/npm run webpack-dev观察模式迭代,并用vsce package生成本地.vsix后,在 VSCode 扩展面板选择“从 VSIX 安装”。注意构建前需具备wasm32-unknown-unknowntarget(rustup target add wasm32-unknown-unknown)。
验证与进一步阅读
- 格式化能力的行为基线可由 Rust 侧测试佐证:packages/autofmt/tests/samples.rs 及其
tests/samples目录中的 50+ 份.rsx样例覆盖了常见 RSX 结构;HTML 翻译的正确性依赖dioxus-rsx-rosetta(packages/rsx-rosetta/tests)。 - 若需了解 RSX 语法与格式化语义,可对照 packages/rsx 与 packages/core-macro 的宏实现;想了解与编辑器格式化配套的 CLI 能力可参考 packages/autofmt 的 README 与源码文档注释。
- Dioxus 的入门与深入教程分属项目外文档(README 中“Working with Dioxus”一节列出),此处不再展开。
许可说明
扩展本体以 MIT 协议发布(见仓库根目录 LICENSE-MIT 与扩展目录 packages/extension/LICENSE.txt)。README 同时约定:除非显式声明,否则任何为 Dioxus 提交的贡献,其版权默认按 MIT 授权并遵循仓库的贡献流程(详见 notes/CONTRIBUTING.md)。
【免费下载链接】dioxusFullstack app framework for web, desktop, and mobile.项目地址: https://gitcode.com/GitHub_Trending/di/dioxus
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考