ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Harper Desktop 开发指南:Tauri + SvelteKit 架构、多平台打包与原生高亮子进程解析

Harper Desktop 开发指南:Tauri + SvelteKit 架构、多平台打包与原生高亮子进程解析 Harper Desktop 开发指南Tauri SvelteKit 架构、多平台打包与原生高亮子进程解析【免费下载链接】harperOffline, privacy-first grammar checker. Fast, open-source, Rust-powered项目地址: https://gitcode.com/GitHub_Trending/har/harperHarper Desktop 是 Harper一个离线、隐私优先的 Rust 语法检查器的桌面客户端当前定位为内嵌 Harper 语法检查能力的离线 Markdown 编辑器。本篇基于仓库中的 harper-desktop/README.md 展开补充 justfile 中的真实构建配方与src-tauri下的 Rust 实现细节帮助你掌握该应用的开发环境配置、just命令体系、前端/后端技术栈以及 macOS/Windows 全系统语法高亮子进程的工作原理能够独立完成本地开发、类型检查与各平台安装包构建。一、Harper Desktop 的定位与仓库现状官方 README 对当前版本的定位很明确Right now, Harper Desktop does little more than serve as an offline editor for Markdown with the Harper grammar checker baked in.目前 Harper Desktop 基本上只是一个内嵌 Harper 语法检查器的离线 Markdown 编辑器。同时 README 附带了一条官方声明该应用的文档尚不完整会以有空再更新的节奏维护因此本文以仓库实际代码与构建配置为准比 README 本身更完整。几个可以从仓库确认的基本事实版本号前端 package.json 与 tauri.conf.json 中的版本均为2.9.1应用标识为com.elijahpotter.harper-desktop产品名为Harper它是 Harper monorepo 的一部分README 明确指出它复用根目录的 Cargo workspace 与 pnpm workspace所有构建动作通过 justfile 提供的just命令完成从 Cargo.toml 的依赖看Rust 侧直接依赖harper-core核心检查引擎与harper-dictionary-wordlist词典序列化而非通过 WebAssembly 走 HTTP 调用——检查能力是编译进桌面进程的这与其离线定位一致。二、开发环境推荐的 IDE 配置README 给出的推荐 IDE 组合为VS CodeSvelte 扩展Tauri 扩展rust-analyzer前端是 Svelte 5 TypeScript后端是 Rust Tauri 2这一组合覆盖了两种语言的热重载与调试链路。除此之外从 package.json 可以看到项目锁定packageManager为pnpm10.10.0即必须使用 pnpmjust配方内部执行的也是pnpm installRust 侧则受仓库根目录rust-toolchain.toml约束。三、核心开发命令just dev-desktop背后的完整依赖链README 提供了三条命令本文逐一展开其真实执行链路依据 justfile 第 167–240 行的配方定义。1. 启动带热重载的开发版just dev-desktopjust dev-desktop这条命令并非直接跑tauri dev而是先构建一整套前端依赖包执行顺序为build-harperjs → build-lint-framework → build-components → build-harper-editor → pnpm install → pnpm tauri dev各步骤在 justfile 中的实际动作步骤作用关键命令build-wasm用wasm-pack编译 harper-wasm产出harper_wasm.js与 slim 版两个产物支持DISABLE_WASM_OPT1跳过 wasm-opt 加速本地迭代wasm-pack build --target webbuild-harperjs构建packages/harper.jsWASM 的 JS 封装并用 perl 脚本消除 Vite 对 WASM 二进制 URL 的重复打包pnpm build./docs.shbuild-lint-framework构建浏览器端 lint 框架包pnpm buildpackages/lint-frameworkbuild-components构建共享 Svelte 组件库componentspnpm install pnpm buildbuild-harper-editor构建共享编辑器库harper-editor依赖上两步的产物pnpm install pnpm build最后进入harper-desktoppnpm install后执行pnpm tauri dev见 justfile 第 168–174 行tauri dev启动后tauri.conf.json 中build.beforeDevCommand为pnpm dev即 Vite dev serverdevUrl指向http://localhost:1420。而 vite.config.js 对该端口做了strictPort: true的强制约束——端口被占用会直接失败而非换端口因为 Tauri 前端需要固定地址同时watch.ignored排除了**/src-tauri/**避免 Rust 侧文件变化触发 Vite 重编译。还有一个值得注意的细节justfile 中的dev-desktop-highlighter配方可以直接启动高亮子进程而无需拉起整个 Tauri 应用just dev-desktop-highlighter # 等价于cargo run -p harper-desktop -- highlighter其原理见后文高亮子进程一节。2. 前端 Rust 双重检查just check-desktopjust check-desktop对应 justfile 第 184–193 行分两段执行cd harper-desktop pnpm install pnpm check # svelte-kit sync svelte-check cd 仓库根目录 cargo check -p harper-desktop --all-targetspnpm check脚本见 package.json即svelte-kit sync svelte-check --tsconfig ./tsconfig.jsonRust 侧用--all-targets把 bin/lib 的测试目标一并纳入检查。3. 构建 Linux 安装包just build-desktop-linuxjust build-desktop-linux执行体为cd harper-desktop pnpm install pnpm tauri build -b deb,rpm,appimage即一次产出deb、rpm、AppImage三种 Linux 发行格式。四、其余平台的打包配方justfile 完整清单README 只列了 Linux但 justfile 中还有面向 Windows 与 macOS 的成熟配方全部继承同一套前端构建依赖链命令平台执行要点just build-desktop-windowsWindows (x86_64)先rustup target add x86_64-pc-windows-msvc再用--runner cargo-xwin --target x86_64-pc-windows-msvc -b nsis交叉编译并以--config {bundle:{createUpdaterArtifacts:false}}关闭 updater 产物NSIS 安装包just build-desktop-macosmacOS 通用二进制pnpm tauri build -b app,dmg --target universal-apple-darwin产出.app.dmgjust build-desktop-macos-arm64Apple Silicon同上但--target aarch64-apple-darwin官方注释注明比 universal 版更快just build-desktop-macos-unsignedmacOS 通用二进制同build-desktop-macos但createUpdaterArtifacts:false用于不生成自动更新签名的场景这里体现了一条打包惯例签名/更新产物是否生成取决于bundle.createUpdaterArtifacts配置默认true见 tauri.conf.json 第 28 行。Windows 与unsigned配方通过 Tauri 的命令行--config覆写为false。五、前端架构SvelteKit 的 SPA 模式与 WASM Linter5.1 为什么 SvelteKit 要配adapter-staticsvelte.config.js 中的注释解释得很直白Tauri 没有 Node.js 服务端可做真正的 SSR因此使用sveltejs/adapter-static并将fallback设为index.html把站点以SPA 模式打包成纯静态资源由 tauri.conf.json 的build.frontendDist: ../build指向构建产物目录。页面入口是单路由src/routes/page.svelte 在onMount中判断当前视图若窗口 label 为settings、URL 查询参数viewsettings或 hash 为#settings则动态import($lib/settings/SettingsApp.svelte)加载设置界面否则动态加载$lib/EditorView.svelte编辑器界面。两个视图均为动态导入天然实现了代码分割页面onMount时还会触发DesktopUpdater.maybeAutoUpdate()见 src/lib/DesktopUpdater.ts启动即检查自动更新。5.2 编辑器视图WASM Linter 跑在 Web Worker 里EditorView.svelte 的核心逻辑只有几行但信息量很大const [{ WorkerLinter }, { slimBinaryInlined }] await Promise.all([ import(harper.js), import(harper.js/slimBinaryInlined), ]); const nextLinter new WorkerLinter({ binary: slimBinaryInlined }); await nextLinter.setup(); linter nextLinter;可以看出编辑器内的语法检查走的是 WASM 路径——harper.js加载内联的 slim 版 WASM 二进制对应 justfilebuild-wasm中--no-default-features产出的harper_wasm_slim在 Web Worker 中运行避免阻塞 UI 线程UI 层复用的是 monorepo 内的共享库harper-editorEditor {linter} /与官网、其他插件共享同一套编辑器组件[package.json](https://link.gitcode.com/i/96beb1c587395127fa5807130838d678)中components、harper-editor、harper.js均为workspace:*内部依赖Tauri 能力层依赖tauri-apps/api及plugin-autostart开机自启、plugin-opener外部链接、plugin-updater自动更新三个插件。六、Rust 后端双模式二进制与全系统高亮服务Harper Desktop 的 Rust 侧不是单一 Tauri 应用而是同一个二进制承担两种角色——这是理解整个架构的关键。6.1 入口分发Tauri 应用 vs. Highlighter 子进程main.rs 只有一行调用harper_desktop_lib::run()真正的分发逻辑在 lib.rs#[derive(Parser)] struct Args { #[command(subcommand)] command: OptionCommand } #[derive(Subcommand)] enum Command { Highlighter { #[arg(long)] no_parent: bool } }run()用 clap 解析参数无子命令时走run_tauri()启动桌面应用带highlighter子命令时走run_highlighter(has_parent)以后台子进程形态运行。--no-parent标志允许它脱离父进程独立运行对应just dev-desktop-highlighter的调试场景。6.2 高亮服务如何拉起子进程Tauri 主进程通过 highlighter_process.rs 用当前可执行文件自身spawn 子进程并以管道接管其 stdin/stdoutlet child Command::new(std::env::current_exe()?) .arg(highlighter) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn()?;随后create_server()把子进程的 stdio 交给communication模块含framing.rs帧协议、message.rs消息定义建立请求/响应通道。子进程启动后通过fetch_highlighter_config()lib.rs依次向父进程拉取 dialect、用户词典、ignored lints、lint 配置、应用集成列表与防抖时长形成完整Config。启动条件在run_tauri()中有两个前提lib.rs系统辅助功能Accessibility权限为Granted且配置中highlighter_service_enabled为true。6.3 检查调用链从文本到 lints子进程内的lint_text闭包lib.rs展示了与harper-core的完整集成方式match debounce_state.status(text, debounce_ms) { DebounceStatus::Cached(lints) return lints, // 命中防抖缓存直接返回 DebounceStatus::Ready {} } let dictionary Config::dictionary_from_user_dictionary(...); let doc Document::new_markdown_default(text, dictionary); let mut organized_lints lint_linter.borrow_mut().organized_lints(doc); for lints in organized_lints.values_mut() { lint_ignored_lints.borrow().remove_ignored(lints, doc); // 过滤用户忽略项 } debounce_state.store_lints(text, debounce_ms, organized_lints);要点文本按Markdown 文档解析Document::new_markdown_default与应用的 Markdown 编辑器定位一致DebounceStatedebounce.rs基于Config.debounce_ms默认 0见后文配置节实现按文本内容的防抖缓存除 lint 外子进程还处理忽略某条 lint、加入用户词典、禁用某条规则、刷新配置四类事件每次操作都通过 stdin 协议同步回父进程如ignore_lint、add_to_dictionary、disable_rule保证设置界面中的改动即时生效。6.4 平台适配Broker 抽象从源码结构看应用用平台代理Broker隔离各系统 APIlib.rsmacOSmac_broker::MacBroker依赖accessibility、objc2-app-kit、core-graphics等 crate见 Cargo.toml通过 Accessibility API 读取聚焦窗口的文本与矩形位置Windowswindows_broker::WindowsBroker依赖uiautomationUI Automation与windowscrate其他平台含 Linuxos_broker::NoopBroker即空实现——这与目前主要面向 macOS/Windows的模块划分相符。高亮窗口本身用egui wgpu渲染egui-winit、egui-wgpu见 Cargo.tomlHighlighter::run_window_for_each_monitor会为每个显示器各建一个高亮窗口lib.rs相关窗口管理逻辑位于 highlighter/ 目录。七、配置系统字段、存储位置与默认值config/mod.rs 定义了应用的全部用户状态pub struct Config { pub mutable_dictionary: MutableDictionary, // 用户自定义词典 pub dialect: Dialect, // 语法方言美式/英式等 pub ignored_lints: IgnoredLints, // 用户忽略的 lint pub lint_config: FlatConfig, // 逐条规则开关 pub integrations: VecIntegration, // 允许高亮的目标应用bundle id pub onboarding_completed: bool, pub debounce_ms: u64, // 检查防抖时长 pub auto_update: bool, pub last_update_check: Optionu64, pub highlighter_service_enabled: bool, }几个值得注意的实现细节存储位置配置目录下的harper-desktop/文件夹主配置为config.json用户词典单独存为dictionary.txt由harper-dictionary-wordlist的load_dict/save_dict序列化测试main_path_points_to_harper_desktop_config_file明确验证了该路径约定词典不进 JSONserialize_main有意排除mutable_dictionary单测serialize_main_excludes_dictionary_word_list验证了这一点——词典走独立文件避免主配置膨胀方言自动探测detect_system_dialect()通过tauri_plugin_os::locale()获取 BCP-47 语言标签再转Dialect失败时回退美式英语首启流程run_tauri()先检查config.json是否存在不存在则创建默认配置、落盘并弹出设置窗口windows::show_settings_window即首次启动进入引导的行为在源码中可直接对应加载容错load_from_system失败时退回Config::new()默认值并打印错误lint_config.fill_with_curated()保证旧配置也能吃到新规则项的默认值检查器组装create_linter()返回LintGroup::new_curated(词典, 方言).with_lint_config(配置)词典由内置 FST 精选词典与用户词典合并MergedDictionary。八、自动更新与开机自启tauri.conf.json 中配置了 Tauri updater 插件包含 minisign 公钥pubkey与下载端点形如https://writewithharper.com/download-harper-desktop/{target}/{arch}/{version}且bundle.createUpdaterArtifacts默认为true意味着默认构建会生成签名用的更新产物本地开发或不需要更新链路的打包build-desktop-windows、build-desktop-macos-unsigned则显式置false。前端在 DesktopUpdater.ts 中于页面挂载时调用maybeAutoUpdate()与auto_update/last_update_check配置字段配合完成更新节流。开机自启则通过tauri-plugin-autostart在 lib.rs 注册macOS 使用LaunchAgent方式。九、小结命令速查目的命令开发版热重载just dev-desktop单独调试高亮子进程just dev-desktop-highlighter前端 Rust 类型检查just check-desktopLinux 打包deb/rpm/appimagejust build-desktop-linuxWindows 打包NSIS交叉编译just build-desktop-windowsmacOS 打包universal / arm64just build-desktop-macos/just build-desktop-macos-arm64macOS 打包无更新产物just build-desktop-macos-unsigned综合来看Harper Desktop 的技术栈可以概括为三层SvelteKitSPA 模式 Tauri 2 负责应用外壳harper.js 的 slim WASM 二进制在 Web Worker 中承担编辑器内检查独立的highlighter子进程egui 窗口 平台 Accessibility/UIA 代理 harper-core 原生引擎承担系统级高亮。三者共享同一套Config语义方言、词典、规则开关、忽略列表、防抖任何一处的修改都会通过 stdin 帧协议同步到另外两处。对贡献者而言最重要的入口是 justfile 与 lib.rs前者定义全部构建路径后者定义了进程分发与检查调用链的骨架。【免费下载链接】harperOffline, privacy-first grammar checker. Fast, open-source, Rust-powered项目地址: https://gitcode.com/GitHub_Trending/har/harper创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表