
前言
是的,我已经将 Alfred 换为 Raycast 了,后者的免费功能足够好用。
但也没有完全丢掉 Alfred,还在用它的剪贴板历史功能。
此前看到一个帖子说:Alfred 用户一定要试试 Raycast。当时我不以为意。
用了七、八年的 Alfred 几乎没怎么"变过",有种不思进取的感觉。特别是近几年 AI 的发展,它好像还没反应过来一样。
对比
在使用 Alfred 时,用得最多的功能是:
- Web Search - 快速跳转,通常用于搜索文档等。
- Clipboard History - 剪贴板历史,没什么好说的,用过都说好用。
- Workflow - 工作流,比如翻译、打开项目等,写过一两个插件,开发体验不好,能做的有限。
这些在 Raycast 都有替代方案,甚至更好。除此之外,Raycast 的界面更现代一些,跟最新的 macOS 风格更加契合。并且可以完全通过键盘完成一系列操作。
最重要的是,Raycast Extension 的开发体验比 Alfred 好太多了。官方有提供很多了 API,统一的 UI 风格,有统一的分发 Store,不用网上到处搜索。活跃度很高,目前扩展数量 2200+。
比较麻烦的是,在 Raycast 发布扩展,需要经过官方审核,通过后才会上传到 Store,审核周期较慢。好处是能在一定程度上把控整体的风格,避免各扩展之间外观上参差不齐,能从官方角度提一些更好的交互建议。
开始之前
技术栈
Node.js + TypeScript + React
虽然使用 React 构建,但只能使用官方提供的一些 API 或内置组件,不能过多地自定义(可能是 React to macOS Native 的缘故吧),好处是 UI 风格较为统一。
安装扩展
- 键入 Store 搜索安装
- 键入 Import Extension 在本地导入
键入 Manage Extensions 可以管理本地扩展。
卸载扩展
- 键入关键词,选中要卸载的扩展,在 Action Panel 选择 Uninstall Extension 操作即可,快捷键「⌃ + X」。
- 键入 Manage Extension 可管理本地扩展。
在 Raycast 中卸载本地扩展(即非通过 Store 安装的扩展)时,本地扩展文件不会被删除。
扩展路径~/Library/Application Support/com.raycast.macos/extensions
。
创建扩展
键入 Create Extension 回车输入必要信息,便创建好了。

官方提供了多个模板,可以选择简单的 Show Detail 模板。
接着:
shell
$ cd <your-extension-path>
$ npm install
$ npm run dev
调试扩展
当我们执行 npm run dev
(即 ray develop
)时,它会自动安装扩展,并以开发模式启动 Raycast 应用。
为了方便调试,在 Preferences - Advanced - Developer Tools 下勾选几个选项:
- Auto-reload on Save
- Open Raycast in development mode
- Keep window always visible during development
这对开发体验尤为重要。一是开发过程中文件修改可以自动重载,二是使 Raycast 始终显示,以避免切换其他应用时窗口关闭。
在开发模式下,使用 console.log()
可以在终端上显示打印信息。

如果没有正确使用 API、组件或快捷键冲突,此处也会有 Warning 显示。
发布扩展
如果想要将你的扩展发布到 Store 上,是需要官方审核的。
为避免审核不通过,你的扩展应满足 Prepare an Extension for Store 要求。
二选一:
- Fork 官方仓库,将你的扩展放在仓库
extensions
目录下,提交 PR。 - 创建独立仓库,然后通过 ray publish 提交。
提交 PR 时,建议附上视频,或许可以更快地审核。我之前写了一个微信开发工具的扩展,由于他们没有小程序项目,流程上它们跑不通,可能会要求附上视频辅助审核,例如这个。
If you add a new extension or command, include a screencast (or screenshot for straightforward changes). A good screencast will make the review much faster - especially if your extension requires registration in other services.
提交 PR 之后,机器人 greptile-apps 可能会提一些 Review 意见,按需调整即可。
想要吐槽的是,审核很慢,看 commit 记录一天只处理几个。
开发
命名规范
遵循 Apple Style Guide,详见这里。
示例:
- 扩展标题:尽量使用名词,而不是动词,比如 WeChat DevTool。
- 扩展描述:一句话准确、简洁地描述扩展程序的功能。
- 命令标题:动名词组合,尽可能具体地描述命令的作用,比如 Open Project。
- 命令副标题:为标题提供上下文信息。如果副标题几乎与命令标题重复,那么你可能不需要它。不指定时,该位置会显示扩展标题。
- 示例:命令标题 Search Package,命令副标题 NPM,
- 示例:命令标题 Search NPM Package,无命名副标题。
- 以上示例,对于使用者来说,都是非常清晰明确的。
- 命令描述:一句话准确、简洁地描述命令的功能。
本地化
很遗憾,目前 Raycast 扩展仅支持美式英文,不支持本地化语言,更多请看这里。
不上传到 Store 可忽略。
扩展信息
基本上都在 package.json
声明,列举一些基本字段:
json
{
"name": "wechat-devtool", // 包名
"title": "WeChat DevTool", // 扩展标题
"description": "Quickly open WeChat Mini Program projects via official CLI.", // 扩展描述
"icon": "icon.png", // 扩展图标 512 × 512 的 PNG 图片
"author": "tofrankie", // Raycast 账户用户名
"contributors": ["someone"], // 贡献者 Raycast 用户名
"license": "MIT", // 协议
"categories": ["Developer Tools"], // 扩展分类
"commands": [ // 命令列表
{
"name": "open-project", // 名称,跟入口文件同名
"title": "Open Project", // 标题
"description": "Open Mini Program projects via WeChat DevTool.", // 描述
"mode": "view" // 模式
},
{
"name": "configure-projects",
"title": "Configure Projects",
"description": "Configure Mini Program projects.",
"mode": "view"
}
],
"preferences": [ // 扩展偏好设置
{
"name": "wechat-devtool-path", // 名称
"type": "textfield", // 类型
"title": "WeChat DevTool Path", // 标题
"description": "The path to the WeChat DevTool executable.", // 描述
"required": false // 是否必需
}
],
"keywords": [ // 关键词,可供 Store 搜索使用
"Developer Tools",
"WeChat",
"WeChat DevTool",
"WeChat Mini Program"
],
// ...
}
目录结构:
txt
.
├── assets # 静态资源目录
│ └── icon.png
├── CHANGELOG.md # 变更日志
├── metadata # 扩展截图
│ ├── wechat-devtool-1.png
│ └── wechat-devtool-2.png
├── package.json # 扩展信息等
├── README.md # About This Extension 会显示这个
├── src
│ ├── configure-projects.tsx # 入口文件(跟 commands name 同名)
│ └── open-project.tsx # 入口文件
└── tsconfig.json
一些注意点:
- name :不能与 Store 已有扩展重复,可以在这里搜索一下。将用于发布后的扩展链接,比如:
https://www.raycast.com/tofrankie/wechat-devtool
。 - icon :图标放在
/assets
目录。其他需要跟扩展一同打包的静态资源都要放在此目录下。 - author:是 Raycast 用户名,不是 GitHub 用户名。
- license:若要发布到 Store,只能是 MIT 协议。
- categories :至少选择一个,可选分类看这里。
- commands :
- mode :可选值
view
、no-view
、menu-bar
。比如,打开链接等不需要界面的命令操作,可以选择no-view
。
- mode :可选值
- preferences :偏好设置时可以同步的。
- required :当设为
true
时,用户设置后才能使用其他命令。
- required :当设为
更多请看 Extension Properties 或 Extension Schemas。
命令入口文件
入口文件放在 /src
目录下,文件名要与 commands[].name
保持一致。
命令为 view 模式,可以用官方提供的组件来构建界面,详见 User Interface。
- List 列表类型
- Grid 网格类型
- Detail 渲染 Markdown 内容、展示图片
- Form 表单类型
虽然是用 React 编写的界面,但不能自由使用类似 div
或第三方组件库来构建复杂界面。
Action Panel
当我们使用 List、Detail、Form 等构建命令界面时,通常需要声明 Action Panel 来提供更多选项。
jsx
<List.Item
// others...
actions={
<ActionPanel>
<Action
title="Open Project"
icon={Icon.Terminal}
onAction={() => {
// do something...
}}
/>
<Action.Push
title="Go to Configuration"
icon={Icon.Gear}
target={<ConfigureProjects />}
/>
<Action.CopyToClipboard
title="Copy Project Path"
content={project.path}
shortcut={{ modifiers: ["cmd", "shift"], key: "," }}
/>
<Action
title="Delete Project"
icon={Icon.Trash}
style={Action.Style.Destructive}
onAction={() => {
// do something...
}}
/>
</ActionPanel>
}
/>
Raycast 提供了 Action.Open
、 Action.Push
、Action.CopyToClipboard
、Action.OpenInBrowser
等一系列内置命令以轻松完成常用操作,更多请看这里。
对于危险操作,可以声明为 Action.Style.Destructive 以高亮显示,可以配合 confirmAlert 二次确认。
Action 快捷键
在 Action Panel 中,将第一、第二个操作作为 Primary Action 和 Secondary Action,它们会自动分配快捷键。
- 在 List、Grid、Detail 页面分别 Enter、⌘ + Enter
- 在 Form 页面分别是 ⌘ + Enter、⌘ + ⇧ + Enter
设定 Action 快捷键时,可以参考 Raycast 官方推荐的常用快捷键,以便使用各插件有一致的用户体验,更多请看这里。
Name | macOS | Windows |
---|---|---|
Copy | ⌘ + ⇧ + C | ctrl + shift + C |
CopyDeeplink | ⌘ + ⇧ + C | ctrl + shift + C |
CopyName | ⌘ + ⇧ + . | ctrl + alt + C |
CopyPath | ⌘ + ⇧ + , | alt + shift + C |
Save | ⌘ + S | ctrl + S |
Duplicate | ⌘ + D | ctrl + shift + S |
Edit | ⌘ + E | ctrl + E |
MoveDown | ⌘ + ⇧ + ↓ | ctrl + shift + ↓ |
MoveUp | ⌘ + ⇧ + ↑ | ctrl + shift + ↑ |
New | ⌘ + N | ctrl + N |
Open | ⌘ + O | ctrl + O |
OpenWith | ⌘ + ⇧ + O | ctrl + shift + O |
Pin | ⌘ + ⇧ + P | ctrl + . |
Refresh | ⌘ + R | ctrl + R |
Remove | ⌃ + X | ctrl + D |
RemoveAll | ⌃ + ⇧ + X | ctrl + shift + D |
ToggleQuickLook | ⌘ + Y | ctrl + Y |
图标、图片
开发扩展免不了使用图片,Raycast 已经内置了很多图标可直接使用,详见这里。
还可以指定远程图片、本地文件等。
ts
type ImageLike = URL | Asset | Icon | FileIcon | Image
type ImageSource = URL | Asset | Icon | { light: URL | Asset; dark: URL | Asset }
- URL:如 HTTP 链接
- Asset :
assets
目录的图片文件 - Icon:Raycast 内置的图标
- FileIcon:该文件/目录在 Finder 所显示的图标
- Image :类型如 ImageSource,还可以指定浅色、深色主题的图片,命名形式
icon.png
和icon@dark.png
。
图片着色:
tsx
import { Color, Icon, List } from "@raycast/api"
const tintedIcon = { source: Icon.RaycastLogoPos, tintColor: Color.Blue }
export default function Example() {
return (
<List>
<List.Item title="Blue" icon={tintedIcon} />
</List>
)
}
本地 svg 图片同样也是可以着色的。
导航
- 在 Action Panel 可以用
Action.Push
跳转目标页 - 在页面可以使用
const { push, pop } = useNavigation()
跳转下一页或返回上一页 - 使用
popToRoot()
可以返回 Raycast 根界面 - 使用
closeMainWindow()
可以主动关闭 Raycast 窗口
搜索
使用 List 构建的页面带有一个搜索栏用于筛选,来源是 List.Item 的 title
和 keywords
字段。
我发现,它没有根页面输入框那么智能,对筛选中文或拼音不太灵光的样子。
这种情况下,有两种解决方法:
- 自定义搜索规则:searchText + onSearchTextChange
- 丰富 keywords 内容
已后者为例,可以将项目名称、项目路径、项目名称拼音(若有中文)添加到 keywords 字段,参考 pinyin.ts。
图片展示
若要展示一张图片,似乎只有 Detail + Markdown 的方式了。
tsx
export default function ImageView({ url }: { url: string }) {
// 可通过 example.png?raycast-width=250&raycast-height=250 指定宽高
const markdown = ``;
return <Detail markdown={markdown} />;
}
表单
没什么好说的,文档很详尽了,请看这里。
Toast、Loading、Alert
提供的 API 有:
- showToast 有 Success、Failure、Animated 三种,后者为 Loading 圈圈。如果 Raycast 窗口关闭了,会回退到 showHUD
- showFailureToast 显示错误信息优先选择这个
- showHUD Raycast 窗口时在屏幕下方显示一条信息
- confirmAlert 用于危险操作的二次确认弹窗
环境信息
可以在 environment 获取:
js
import { useNavigation, showToast, Toast, showHUD, environment } from "@raycast/api";
environment.raycastVersion // 1.102.5
environment.ownerOrAuthorName // tofrankie
environment.extensionName // wechat-devtool
environment.commandName // open-project
environment.commandMode // view
environment.assetsPath // /Users/frankie/.config/raycast/extensions/wechat-devtool/assets
environment.supportPath // /Users/frankie/Library/Application Support/com.raycast.macos/extensions/wechat-devtool
environment.isDevelopment // true
environment.appearance // light
environment.textSize // medium
environment.launchType // userInitiated
扩展相关文件
- assetsPath 扩展安装到 Raycast 的产物路径
- supportPath 扩展相关文件,比如扩展记录一个配置文件,可以放在该目录下
需要注意的是,Raycast 不会同步 supportPath
目录的文件。
之前我想着把一些配置写入 supportPath 的文件,使其在 Raycast 中进行同步。但这是不行的,对扩展来说,只同步 preferences 的配置,而 preferences 又没办法动态更新。
Shell 环境
有时我们要在 Raycast 扩展中执行一些 Shell 命令。
下面是默认情况下的一些变量值。
shell
$ echo $SHELL
/bin/zsh
shell
$ echo $PATH
/usr/gnu/bin:/usr/local/bin:/bin:/usr/bin:.
shell
$ printenv
SUPPORT_PATH=/Users/frankie/Library/Application Support/com.raycast.macos/extensions/wechat-devtool
TMPDIR=/var/folders/z4/nxcp1z415jgff4rwrrf8v3y00000gn/T
ASSETS_PATH=/Users/frankie/.config/raycast/extensions/wechat-devtool/assets
LC_ALL=en_CN-u-hc-h23-u-ca-gregory-u-nu-latn
__CF_USER_TEXT_ENCODING=0x1F5:0x19:0x34
EXTENSION_NAME=wechat-devtool
RAYCAST_VERSION=1.102.5
PWD=/
FAVICON_PROVIDER=legacy
NODE_PATH=/Applications/Raycast.app/Contents/Resources/RaycastNodeExtensions_RaycastNodeExtensions.bundle/Contents/Resources/api/node_modules
NODE_ENV=development
SHLVL=1
HOME=/Users/frankie
COMMAND_NAME=open-project
RAYCAST_BUNDLE_ID=com.raycast.macos
_=/usr/bin/printenv
通常我们会在 ~/.zshrc
中配置 export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:$PATH"
以使用 Homebrew 安装的命令,但 Raycast 扩展执行 Shell 不会加载 ~/.zshrc
因此无法直接使用里面的命令。
可以这样处理(仅供参考):
ts
import { exec } from "child_process";
import { promisify } from "util";
const execAsync = promisify(exec);
function execCommand(command: string, cwd?: sting) {
const env = getEnv();
await execAsync(command, { cwd, env });
// do something...
}
function getEnv() {
return { ...process.env, PATH: joinHomebrewPath() };
}
function joinHomebrewPath() {
return [process.env.PATH, "/opt/homebrew/bin", "/opt/homebrew/sbin"].filter(Boolean).join(":");
}
Change Log
开发完成后,需要在 CHANGELOG.md 补充一条变更记录。
遵循 Keep a Changelog 写法,要求如下:
- 格式必须是
## [xxx] - {PR_MERGE_DATE}
[]
内的为本次变更的标题{PR_MERGE_DATE}
为合并日期。因为从提交 PR 到审核通过可能要好几天,被合并时会自动替换
更多请看这里
text
# WeChat DevTool Changelog
## [New Version] - {PR_MERGE_DATE}
- Add something
- Improve something
- Fix something
## [First Release] - 2025-07-11
- **Open Project** - Open configured mini program project via WeChat DevTool CLI.
- **Graphical Configuration** - Complete graphical interface for dynamic project management.
截图
存放在 metadata
目录下,可提供 1 ~ 6 张截图。
Raycast 内置提供了截屏功能,在 Raycast Settings - Advanced - Window Capture 中设置快捷键(如 ⌥ + ⇧ + ⌘ + M)。
在 npm run dev
模式下启动扩展,按下快捷键,便可调出截屏窗口,并勾选上「Save to Metadata」,就会自动保存到扩展的 metadata
目录,更多请看这里。
Raycast 提供了一些高清壁纸,请看这里。
贡献
如果想对已发布的扩展作出贡献:
- fork raycast/extensions
- 功能调整...
- 将你的 Raycast 用户名添加到 package.json 的
contributors
字段 - 提交 PR,等待审核发布
由于审核较慢,如果同时多个扩展做出贡献,可以创建不同的分支去处理,如 ext/extension-a、ext/extension-b。