🎯 Raycast 简介
Raycast 是一款专为 macOS 设计的现代化生产力工具,类似于 Alfred 和 Spotlight 的替代品。与前辈们相比,它更现代化,更符合现代使用和开发习惯。它采用 TypeScript + React 技术栈,为前端开发者提供了优秀(爽歪歪)的扩展开发体验。
核心特点
- 现代化 UI: 原生级别的用户界面体验
- TypeScript 支持: 完整的类型定义和开发体验
- React 组件: 使用 React 构建复杂的用户界面
- AI 集成: 内置 AI 能力支持
- 丰富的 API: 提供大量原生功能接口
🛠️ 开发环境准备
1. 安装 Raycast
bash
# 通过 Homebrew 安装
brew install --cask raycast
# 或直接下载安装包
# 访问 https://www.raycast.com 下载最新版本
2. 安装开发工具(开发文档:developers.raycast.com/)
bash
# 安装 Node.js (建议 v18 或更高版本)
# 安装 npm 或 yarn 或其他工具
npm install -g npm@latest
# 安装 Raycast CLI 工具
npm install -g @raycast/cli
3. 开发环境验证
bash
# 检查 Raycast CLI 是否安装成功
raycast --version
# 查看可用命令
raycast --help
🚀 创建扩展项目
1. 初始化项目
bash
# 创建新的扩展项目
raycast create my-extension
# 进入项目目录
cd my-extension
# 安装依赖
npm install
2. 项目结构解析
perl
my-extension/
├── package.json # 项目配置和依赖
├── tsconfig.json # TypeScript 配置
├── raycast-env.d.ts # Raycast 类型定义
├── src/
│ ├── index.tsx # 主入口文件
│ ├── search.tsx # 搜索命令组件
│ └── preferences.tsx # 偏好设置
├── assets/
│ ├── icon.png # 扩展图标
│ └── screenshots/ # 截图资源
├── metadata/
│ └── raycast.png # Raycast 商店展示图
└── README.md # 项目说明文档
3. 核心文件说明
package.json
json
{
"name": "my-extension",
"title": "My Extension",
"description": "描述你的扩展功能",
"icon": "icon.png",
"author": "your-name",
"license": "MIT",
"commands": [
{
"name": "search",
"title": "Search Command",
"description": "搜索功能的描述",
"mode": "view"
}
],
"dependencies": {
"@raycast/api": "^1.0.0",
"@raycast/utils": "^1.0.0"
}
}
src/index.tsx (基础模板)
typescript
import { List, ActionPanel, Action, showToast, Toast } from "@raycast/api";
import { useState, useEffect } from "react";
interface SearchResult {
id: string;
title: string;
description: string;
}
export default function Command() {
const [searchResults, setSearchResults] = useState<SearchResult[]>([]);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
// 初始化数据加载
loadData();
}, []);
async function loadData() {
try {
setIsLoading(true);
// 这里添加你的数据获取逻辑
const results = await fetchData();
setSearchResults(results);
} catch (error) {
showToast({
style: Toast.Style.Failure,
title: "加载失败",
message: error instanceof Error ? error.message : "未知错误"
});
} finally {
setIsLoading(false);
}
}
async function fetchData(): Promise<SearchResult[]> {
// 模拟数据获取
return [
{ id: "1", title: "结果 1", description: "描述信息" },
{ id: "2", title: "结果 2", description: "另一个描述" }
];
}
return (
<List isLoading={isLoading} searchBarPlaceholder="搜索...">
{searchResults.map((result) => (
<List.Item
key={result.id}
title={result.title}
subtitle={result.description}
actions={
<ActionPanel>
<Action
title="执行操作"
onAction={() => {
showToast({
style: Toast.Style.Success,
title: "操作完成",
message: `执行了: ${result.title}`
});
}}
/>
</ActionPanel>
}
/>
))}
</List>
);
}
📋 开发核心概念
1. 命令 (Commands)
命令是 Raycast 扩展的核心组件,每个扩展可以包含多个命令。
命令类型(mode)
- view: 显示用户界面 (默认)
- no-view: 后台执行,无界面
- menu-bar: 菜单栏扩展
命令配置示例
json
{
"commands": [
{
"name": "search",
"title": "搜索",
"description": "执行搜索操作",
"mode": "view",
"preferences": [
{
"name": "apiKey",
"type": "password",
"title": "API 密钥",
"description": "用于API调用的密钥"
}
]
}
]
}
2. 组件 (Components)
Raycast 提供了丰富的 UI 组件:
基础组件
typescript
import {
List,
Detail,
Form,
ActionPanel,
Action,
Icon,
Color,
showToast,
Toast,
confirmAlert,
Alert
} from "@raycast/api";
常用组件示例
List 组件
typescript
<List
searchBarPlaceholder="搜索项目..."
isLoading={isLoading}
onSearchTextChange={setSearchText}
throttle
>
<List.Section title="分类 1">
<List.Item
title="项目标题"
subtitle="副标题"
icon={Icon.Star}
accessories={[
{ text: "标签", icon: Icon.Tag }
]}
actions={
<ActionPanel>
<Action.OpenInBrowser url="https://example.com" />
<Action.CopyToClipboard content="复制内容" />
</ActionPanel>
}
/>
</List.Section>
</List>
Detail 组件
typescript
<Detail
markdown={markdownContent}
navigationTitle="详情页面"
actions={
<ActionPanel>
<Action
title="刷新"
icon={Icon.ArrowClockwise}
onAction={handleRefresh}
/>
</ActionPanel>
}
/>
Form 组件
typescript
<Form
actions={
<ActionPanel>
<Action.SubmitForm title="提交" onSubmit={handleSubmit} />
</ActionPanel>
}
>
<Form.TextField
id="title"
title="标题"
placeholder="输入标题"
defaultValue="默认标题"
/>
<Form.TextArea
id="description"
title="描述"
placeholder="输入描述"
/>
<Form.Checkbox
id="enabled"
label="启用"
defaultValue={true}
/>
</Form>
3. 钩子 (Hooks)
Raycast 提供了实用的 React Hooks:
typescript
import {
usePromise,
useCachedState,
useFetch,
useFrecencySorting,
useAI
} from "@raycast/utils";
// 异步数据加载
const { isLoading, data, error } = usePromise(fetchData, [query]);
// 本地存储
const [items, setItems] = useCachedState<Item[]>("cached-items", []);
// HTTP 请求
const { data, isLoading, error } = useFetch("https://api.example.com/data");
// AI 集成
const { data, isLoading } = useAI("请总结这段文本", {
creativity: "medium"
});
4. 偏好设置 (Preferences)
typescript
import { getPreferenceValues } from "@raycast/api";
interface Preferences {
apiKey: string;
defaultLanguage: string;
maxResults: number;
}
const preferences = getPreferenceValues<Preferences>();
🔧 高级功能开发
1. 网络请求
typescript
import { useFetch } from "@raycast/utils";
import { showToast, Toast } from "@raycast/api";
interface ApiResponse {
data: any[];
total: number;
}
export default function Command() {
const { data, isLoading, error } = useFetch<ApiResponse>(
"https://api.example.com/items",
{
headers: {
"Authorization": `Bearer ${preferences.apiKey}`,
"Content-Type": "application/json"
},
onError: (error) => {
showToast({
style: Toast.Style.Failure,
title: "API 请求失败",
message: error.message
});
}
}
);
// 使用获取的数据...
}
2. 本地存储
typescript
import { LocalStorage } from "@raycast/api";
// 存储数据
await LocalStorage.setItem("user-preferences", JSON.stringify(preferences));
// 读取数据
const stored = await LocalStorage.getItem("user-preferences");
const prefs = stored ? JSON.parse(stored) : {};
// 删除数据
await LocalStorage.removeItem("user-preferences");
// 清空所有存储
await LocalStorage.clear();
3. 剪贴板操作
typescript
import { Clipboard, showHUD } from "@raycast/api";
// 读取剪贴板
const text = await Clipboard.readText();
// 写入剪贴板
await Clipboard.copy("要复制的内容");
// 复制并显示提示
await Clipboard.copy("已复制到剪贴板");
await showHUD("已复制到剪贴板");
// 复制富文本
await Clipboard.copy({ text: "纯文本", html: "<b>HTML</b>内容" });
4. 文件系统操作
typescript
import { environment, showInFinder } from "@raycast/api";
import { execSync } from "child_process";
// 获取支持目录路径
const supportPath = environment.supportPath;
const cachePath = environment.cachePath;
// 打开文件
await showInFinder("/path/to/file");
// 执行系统命令
try {
const result = execSync("ls -la", { encoding: "utf-8" });
console.log(result);
} catch (error) {
console.error("命令执行失败:", error);
}
🧪 调试和测试
1. 开发模式
bash
# 启动开发模式
npm run dev
# 在 Raycast 中重新加载扩展
# 使用快捷键 Cmd+R 重新加载
2. 日志输出
typescript
// 控制台日志
console.log("调试信息");
console.error("错误信息");
console.warn("警告信息");
// 显示调试信息
showToast({
style: Toast.Style.Success,
title: "调试信息",
message: JSON.stringify(data, null, 2)
});
3. VSCode 调试配置
在 .vscode/launch.json
中添加:
json
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Raycast Extension",
"type": "node",
"request": "launch",
"runtimeExecutable": "raycast",
"runtimeArgs": ["debug"],
"env": {
"NODE_ENV": "development"
},
"console": "integratedTerminal"
}
]
}
4. 错误处理最佳实践
typescript
import { showToast, Toast, Alert, confirmAlert } from "@raycast/api";
// 统一的错误处理
async function handleError(error: unknown, context: string) {
const message = error instanceof Error ? error.message : "未知错误";
console.error(`[${context}]`, error);
await showToast({
style: Toast.Style.Failure,
title: "操作失败",
message: `${context}: ${message}`
});
}
// 用户确认对话框
async function confirmAction(message: string): Promise<boolean> {
return await confirmAlert({
title: "确认操作",
message: message,
primaryAction: {
title: "确认",
style: Alert.ActionStyle.Default
},
dismissAction: {
title: "取消",
style: Alert.ActionStyle.Cancel
}
});
}
📦 扩展打包和发布
1. 构建扩展
bash
# 构建生产版本
npm run build
# 验证构建结果
npm run lint
npm run test
2. 本地测试
bash
# 在 Raycast 中导入本地扩展
# 1. 打开 Raycast
# 2. 输入 "Import Extension"
# 3. 选择扩展目录
3. 发布到 Raycast Store
准备发布材料
markdown
# README.md 模板
## 扩展名称
扩展的简要描述
### 功能特性
- 功能1
- 功能2
- 功能3
### 安装
1. 安装扩展
2. 配置偏好设置
3. 开始使用
### 配置
- API 密钥: 在偏好设置中配置
- 语言设置: 支持多语言
### 截图

### 更新日志
#### v1.0.0
- 初始版本发布
发布流程
- 创建 GitHub 仓库
bash
# 初始化 git 仓库
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/yourusername/my-extension.git
git push -u origin main
- 提交到 Raycast Store
bash
# 使用 Raycast CLI 提交
raycast publish
# 或者通过 GitHub 提交 PR
# 1. Fork raycast/extensions 仓库
# 2. 创建新分支
# 3. 添加扩展目录到 extensions/ 目录下
# 4. 提交 Pull Request
- 等待审核
- Raycast 团队会审核你的扩展
- 通常需要 3-7 个工作日
- 审核通过后会自动发布到 Store
4. 发布要求和最佳实践
技术要求
- 使用 TypeScript 开发
- 遵循 Raycast 编码规范
- 包含完整的错误处理
- 提供清晰的文档
用户体验要求
- 响应式设计
- 加载状态处理
- 错误提示友好
- 快捷键支持
代码质量要求
typescript
// 良好的代码结构
import { useState, useEffect } from "react";
import { List, ActionPanel, Action, showToast, Toast } from "@raycast/api";
import { usePromise, useCachedState } from "@raycast/utils";
interface Item {
id: string;
title: string;
description: string;
}
export default function Command() {
const [searchText, setSearchText] = useState("");
const [cachedItems, setCachedItems] = useCachedState<Item[]>("items", []);
const { isLoading, data, error } = usePromise(
async (query: string) => {
// 数据获取逻辑
return await fetchItems(query);
},
[searchText]
);
// 错误处理
useEffect(() => {
if (error) {
showToast({
style: Toast.Style.Failure,
title: "获取数据失败",
message: error.message
});
}
}, [error]);
return (
<List
isLoading={isLoading}
searchText={searchText}
onSearchTextChange={setSearchText}
searchBarPlaceholder="搜索项目..."
>
{data?.map((item) => (
<List.Item
key={item.id}
title={item.title}
subtitle={item.description}
actions={
<ActionPanel>
<Action
title="查看详情"
onAction={() => {/* 处理逻辑 */}}
/>
</ActionPanel>
}
/>
))}
</List>
);
}
🔄 版本管理和更新
1. 版本号规范
遵循语义化版本控制 (SemVer):
- 主版本号 (MAJOR): 不兼容的 API 修改
- 次版本号 (MINOR): 向下兼容的功能性新增
- 修订号 (PATCH): 向下兼容的问题修正
2. 更新流程
bash
# 1. 更新版本号
npm version patch # 或 minor, major
# 2. 更新 CHANGELOG.md
# 3. 提交更改
git add .
git commit -m "Release v1.1.0"
git push origin main
# 4. 重新发布
raycast publish
3. 更新日志模板
markdown
# Changelog
## [1.1.0] - 2025-10-12
### 新增
- 功能描述
### 修复
- 修复问题描述
### 改进
- 改进描述
📚 常用资源和工具
1. 官方资源
- 开发者文档 : developers.raycast.com/
- API 参考 : developers.raycast.com/api-referen...
- 扩展示例 : github.com/raycast/ext...
- 设计指南 : developers.raycast.com/design
2. 开发工具
- VSCode 扩展: Raycast Extension
- 调试工具: React Developer Tools
- 图标资源: SF Symbols, Feather Icons
3. 社区资源
- Discord 社区 : raycast.com/community
- GitHub 讨论 : github.com/raycast/ext...
- Stack Overflow: 使用 raycast 标签
💡 一些调试技巧
typescript
// 开发模式下的调试信息
if (process.env.NODE_ENV === "development") {
console.log("调试信息:", data);
}
// 使用 Raycast 的调试工具
import { environment } from "@raycast/api";
console.log("运行环境:", environment);
console.log("支持路径:", environment.supportPath);
🎯 开发流程总结
- 环境准备: 安装 Raycast 和开发工具
- 项目创建: 使用 CLI 创建扩展项目
- 功能开发: 实现核心功能逻辑
- 界面设计: 使用 Raycast 组件构建 UI
- 测试调试: 本地测试和调试
- 打包发布: 构建并发布到 Store
- 维护更新: 持续改进和维护
本文章基于 Raycast 最新版本编写,随着平台更新,部分功能可能会有所变化,建议定期查看官方文档获取最新信息。