npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vokex.app

v0.1.5

Published

超轻量级桌面应用构建库 - Vite 构建后一键打包为原生可执行文件

Readme

Vokex

npm version license

超轻量级桌面应用构建库。将前端代码通过 Vite 构建后一键嵌入到预编译的 Rust 壳中,生成单个原生可执行文件(最小 ~1.8MB)。架构类似 Tauri 的极简版,壳基于 tao + wry(系统 WebView)。

目前仅支持 Windows。macOS、Linux 将在后续版本中添加。

特性

  • 超轻量:构建产物最小 ~1.8MB,仅依赖系统 WebView
  • 零 Rust 门槛npm install vokex.app 即可使用,不需要 Rust 工具链
  • Vite 原生集成:Vite 插件自动接管开发和构建流程
  • 单文件输出:前端资源 zlib 压缩后嵌入到可执行文件尾部
  • 双模式运行:开发时加载 localhost,生产时从自身尾部读取资源
  • 丰富的 API:14 个模块,112 个公开方法
  • TypeScript 优先:完整的类型支持
  • 安全沙箱:远端页面默认禁用危险 API,支持白名单配置
  • 远程窗口:支持加载远端 URL 创建子窗口
  • 文件搜索:支持 glob 模式匹配(*.txt, **/*.js

快速开始

1. 创建项目

npm create vite@latest my-app -- --template vanilla
cd my-app
npm install vokex.app

2. 配置 Vite

// vite.config.ts
import { defineConfig } from "vite";
import { vokexPlugin } from "vokex.app/vite-plugin";

export default defineConfig({
  plugins: [
    vokexPlugin({
      name: "我的应用",
      identifier: "com.example.myapp",
      version: "1.0.0",
      icon: "icon.png",
      window: {
        title: "我的应用",
        width: 1200,
        height: 800,
      },
      devtools: process.env.NODE_ENV === 'development',
    }),
  ],
});

3. 使用 API

import { app, fs, browserWindow, menu, dialog } from "vokex.app";

// 应用就绪后执行
app.on("ready", async () => {
  const name = await app.getName();
  console.log(`${name} 已启动`);
});

// 文件操作
const content = await fs.readFile("config.json");
await fs.writeFile("output.txt", "Hello World");

// 窗口管理
const win = await browserWindow.create({ title: "子窗口", width: 600, height: 400 });

// 原生菜单
await menu.setApplicationMenu([
  { type: 'submenu', label: '文件', submenu: [
    { id: 'new', label: '新建' },
    { type: 'separator' },
    { type: 'native', nativeLabel: 'quit' },
  ]},
]);

// 对话框
const result = await dialog.showOpenDialog({
  filters: [{ name: "文本文件", extensions: ["txt", "md"] }],
});

4. 构建与开发

# 开发模式(启动 dev server + 原生壳)
npm run dev

# 构建打包(输出到 release/ 目录)
npm run build

# 验证构建产物
npx vokex.app validate release/我的应用.exe

架构

┌───────────────────────────────────────┐
│  前端代码 (HTML/JS/CSS)               │
│  import { app, fs } from "vokex.app"  │
├───────────────────────────────────────┤
│  运行时 Bridge (注入 JS)              │
│  window.__VOKEX__.call("fs.readFile") │
├───────────────────────────────────────┤
│  IPC: postMessage ↔ evaluate_script   │
├───────────────────────────────────────┤
│  Rust 壳 (wry + tao)                  │
│  窗口管理 │ API 路由 │ 资源加载        │
├───────────────────────────────────────┤
│  系统 WebView                         │
│  Windows: WebView2  macOS: WKWebView  │
└───────────────────────────────────────┘

IPC 通信链路:

前端: window.__VOKEX__.call("fs.readFile", [path])
  → window.ipc.postMessage(JSON)
    → Rust wry IPC handler
      → 主线程事件循环
        → dispatch 到对应 API 模块
          → 同步直接 eval / 异步线程池完成后 eval
            → window.__VOKEX_IPC__(response)
              → Promise resolve

API 参考

所有 API 都是异步的,返回 Promise。

app - 应用管理

import { app } from "vokex.app";

| 方法 | 说明 | |---|---| | quit() | 退出应用 | | exit(code?) | 退出并返回指定退出码 | | restart() | 重启应用 | | getAppPath() | 获取应用可执行文件路径 | | getPath(name) | 获取系统路径:home appData desktop documents downloads temp cwd | | getVersion() | 获取版本号 | | getName() | 获取应用名称 | | getIdentifier() | 获取应用标识符 | | getLocale() | 获取系统语言 | | getPid() | 获取进程 PID | | getArgv() | 获取启动参数 | | getEnv(key) | 获取环境变量 | | getPlatform() | 获取平台:win32 darwin linux | | getArch() | 获取架构:x64 arm64 | | requestSingleInstanceLock() | 请求单实例锁,返回 true 表示是首个实例 | | on(event, callback) | 监听应用事件 |

事件: ready window-all-closed before-quit second-instance activate

browserWindow - 窗口管理

import { browserWindow } from "vokex.app";

创建窗口:

const win = await browserWindow.create({
  title: "子窗口",
  width: 800,
  height: 600,
  url: "page.html",     // 相对路径或完整 URL
  center: true,
  resizable: true,
  icon: "icon.png",
});

静态方法:

| 方法 | 说明 | |---|---| | create(options?) | 创建新窗口,返回 BrowserWindow 实例 | | getAll() | 获取所有窗口信息 | | getFocused() | 获取当前聚焦窗口信息 | | getById(id) | 按 ID 获取窗口实例 | | getWindow(id) | 同 getById | | getCurrentWindow() | 获取当前窗口实例 | | getFocusedWindow() | 获取当前聚焦窗口实例 |

窗口实例方法:

| 方法 | 说明 | |---|---| | getId() | 获取窗口 ID | | close() | 关闭窗口 | | show() / hide() | 显示 / 隐藏 | | minimize() / maximize() / restore() | 最小化 / 最大化 / 恢复 | | unmaximize() | 取消最大化 | | focus() / blur() | 聚焦 / 失焦 | | isMaximized() isMinimized() isFullScreen() isFocused() isVisible() | 状态查询 | | isResizable() / setResizable(flag) | 可调整大小 | | isMinimizable() / setMinimizable(flag) | 可最小化 | | isMaximizable() / setMaximizable(flag) | 可最大化 | | isClosable() / setClosable(flag) | 可关闭 | | isDecorated() / setDecorated(flag) | 窗口装饰(标题栏) | | setFullScreen(flag) | 全屏切换 | | setTitle(title) / getTitle() | 设置 / 获取标题 | | setSize(w, h) / getSize() | 设置 / 获取大小 | | setMinimumSize(w, h) / setMaximumSize(w, h) | 限制窗口尺寸范围 | | setPosition(x, y) / getPosition() | 设置 / 获取位置 | | center() | 窗口居中 | | setOpacity(opacity) | 设置透明度 (0.0~1.0) | | setBackgroundColor(color) | 设置背景色 | | setIcon(icon) | 设置窗口图标 | | setAlwaysOnTop(flag) | 置顶 | | setAlwaysOnBottom(flag) | 置底 | | loadFile(path) / loadURL(url) | 加载本地文件 / URL | | reload() | 重新加载 | | setProgressBar(progress) | 任务栏进度条 (0.0~1.0) [Windows] | | setSkipTaskbar(flag) | 隐藏任务栏图标 | | flashTaskbar(flag) | 闪烁任务栏 | | requestUserAttention(level?) | 请求用户关注 | | setContentProtection(enabled) | 内容保护(防截图) | | setVisibleOnAllWorkspaces(visible) | 所有工作区可见 | | scaleFactor() | 获取缩放因子 | | getInnerPosition() | 获取客户区位置 | | getOuterSize() | 获取窗口外部大小 | | setCursorIcon(icon) | 设置光标图标 | | setCursorPosition(x, y) | 移动光标 | | setCursorGrab(grab) | 锁定光标 | | setCursorVisible(visible) | 隐藏/显示光标 | | sendMessage(message, targetWindow) | 窗口间通信 | | on(event, callback) / off(event, callback) | 监听 / 移除事件 |

事件: close resize move minimize maximize restore focus blur enter-full-screen leave-full-screen window.message

fs - 文件系统

import { fs } from "vokex.app";

| 方法 | 说明 | |---|---| | readFile(path) | 读取文件为文本 | | readFileBinary(path) | 读取文件为 Base64 | | writeFile(path, data) | 写入文件 | | appendFile(path, data) | 追加内容 | | deleteFile(path) | 删除文件 | | readDir(path) | 列出目录内容,返回 DirEntry[] | | createDir(path) | 创建目录 | | removeDir(path) | 删除目录 | | stat(path) | 获取文件信息 | | exists(path) | 检查文件是否存在 | | copyFile(src, dest) | 复制文件 | | moveFile(src, dest) | 移动 / 重命名文件 | | glob(options) | glob 模式搜索文件 |

GlobOptions:

| 选项 | 类型 | 说明 | |---|---|---| | pattern | string | glob 模式,如 *.txt, **/*.js | | cwd | string? | 搜索目录,默认当前目录 | | ignore | string[]? | 排除模式列表 | | nodir | boolean? | 只返回文件,不返回目录 | | absolute | boolean? | 返回绝对路径 | | dot | boolean? | 是否包含隐藏文件(以 . 开头) |

http - 网络请求

import { http } from "vokex.app";

| 方法 | 说明 | |---|---| | request(url, options?) | 通用请求 | | get(url, options?) | GET 请求 | | post(url, data?, options?) | POST 请求 | | put(url, data?, options?) | PUT 请求 | | delete(url, options?) | DELETE 请求 |

RequestOptions: method headers body timeout

HttpResponse: statusCode statusText headers body ok

dialog - 对话框

import { dialog } from "vokex.app";

| 方法 | 说明 | |---|---| | showMessageBox(options) | 消息对话框,返回 { response, cancelled } | | showErrorBox(options) | 错误对话框 | | showOpenDialog(options?) | 打开文件对话框,返回文件路径或 null | | showSaveDialog(options?) | 保存文件对话框,返回文件路径或 null |

showMessageBox 支持的 type: none okCancel yesNo yesNoCancel showMessageBox 支持的 icon: info warning error

对话框选项: title defaultPath defaultName multiple directory filters

menu - 原生菜单

import { menu } from "vokex.app";

| 方法 | 说明 | |---|---| | setApplicationMenu(menu) | 设置应用顶部菜单栏 | | removeApplicationMenu() | 移除应用菜单栏 | | setContextMenu(menu, x?, y?) | 弹出右键上下文菜单 | | onMenuClick(callback) | 监听菜单项点击事件 |

菜单项类型:

| type | 说明 | |---|---| | normal(默认) | 普通菜单项,需要 idlabel | | separator | 分隔线 | | submenu | 子菜单,需要 labelsubmenu | | checkbox | 复选框菜单项,支持 checked 属性 | | native | 系统原生菜单项,需要 nativeLabel |

NativeLabel(原生菜单项): separator copy cut paste selectAll undo redo minimize maximize fullscreen hide hideOthers showAll closeWindow quit about services bringAllToFront

示例:

// 应用菜单栏
await menu.setApplicationMenu([
  { type: 'submenu', label: '文件', submenu: [
    { id: 'new', label: '新建' },
    { type: 'separator' },
    { type: 'native', nativeLabel: 'quit' },
  ]},
  { type: 'submenu', label: '编辑', submenu: [
    { type: 'native', nativeLabel: 'copy' },
    { type: 'native', nativeLabel: 'paste' },
  ]},
]);

// 右键菜单
await menu.setContextMenu([
  { id: 'copy', label: '复制' },
  { id: 'paste', label: '粘贴' },
], e.x, e.y);

// 监听点击
menu.onMenuClick(({ id }) => {
  console.log('点击了:', id);
});

tray - 系统托盘

import { tray } from "vokex.app";

| 方法 | 说明 | |---|---| | tray.create(options) | 创建托盘图标,返回 Tray 实例 |

TrayOptions: icon(必填) tooltip title menu

Tray 实例方法:

| 方法 | 说明 | |---|---| | getId() | 获取托盘 ID | | setToolTip(text) | 设置提示文本 | | setTitle(title) | 设置标题 (macOS) | | setMenu(template) | 更新右键菜单 | | setImage(icon) | 更新图标 | | destroy() | 销毁托盘 | | on(event, callback) | 监听事件 |

事件: click right-click double-click

示例:

const myTray = await tray.create({
  icon: "icon.png",
  tooltip: "我的应用",
  menu: [
    { id: "show", label: "显示窗口" },
    { type: "separator" },
    { id: "quit", label: "退出" },
  ],
});

myTray.on("click", () => {
  // 托盘左键点击
});

clipboard - 剪贴板

import { clipboard } from "vokex.app";

| 方法 | 说明 | |---|---| | readText() | 读取剪贴板文本 | | writeText(text) | 写入剪贴板 | | clear() | 清空剪贴板 |

notification - 系统通知

import { notification } from "vokex.app";

| 方法 | 说明 | |---|---| | show(options) | 发送系统通知 |

NotificationOptions: title(必填) body

shell - 系统命令

import { shell } from "vokex.app";

| 方法 | 说明 | |---|---| | openExternal(url) | 用默认浏览器打开 URL | | openPath(path) | 用系统默认程序打开文件/目录 | | execCommand(command, options?) | 执行 shell 命令,返回 { code, stdout, stderr, success } | | trashItem(path) | 移到回收站 |

ExecOptions: cwd env

process - 进程信息

import { process } from "vokex.app";

| 方法 | 说明 | |---|---| | getUptime() | 获取进程运行时长(秒) | | getCpuUsage() | 获取 CPU 使用率,返回 { user, system } | | getMemoryInfo() | 获取内存信息,返回 { total, available, used } | | hostname() | 获取主机名 | | env() | 获取所有环境变量 | | kill(pid) | 终止指定进程 |

computer - 系统硬件信息

import { computer } from "vokex.app";

| 方法 | 说明 | |---|---| | getCpuInfo() | CPU 信息:制造商、型号、核心数、频率等 | | getOsInfo() | 操作系统信息:名称、版本、内核版本等 | | getDisplays() | 显示器信息列表 | | getMousePosition() | 鼠标位置 | | getKeyboardLayout() | 键盘布局 |

storage - 本地持久化存储

import { storage } from "vokex.app";

| 方法 | 说明 | |---|---| | setData(key, value) | 存储数据(JSON 序列化) | | getData(key) | 读取数据 | | getKeys() | 获取所有键名 | | has(key) | 检查键是否存在 | | removeData(key) | 删除指定键 | | clear() | 清空所有数据 |

events - 事件总线

import { events } from "vokex.app";

| 方法 | 说明 | |---|---| | on(event, listener) | 监听事件,返回取消监听函数 | | off(event, listener) | 移除监听 | | emit(event, data?) | 触发事件 |

资源嵌入格式

二进制文件尾部追加:

[MAGIC(5B "VOKEX")] [索引长度(4B LE)] [索引JSON] [zlib压缩数据] [偏移量(8B LE)]

索引格式:{ "index.html": [offset, length], "assets/main.js": [offset, length] }

编译壳

如果你需要自己编译壳(而不是使用预编译版本):

cd shell
cargo build --release
# 输出: shell/target/release/vokex-shell.exe (Windows)

许可证

MIT