前言
前段时间趁着空闲时间整理了下之前基于 Node
写的一个 Alfred
工作流, 工作流的主要功能如上图所示,通过关键词、以及搜索词条快速在浏览器上打开 Antd 组件文档; 本文将手把手演示整个工作流的搭建流程, 当然, 这里实现的功能略有删减, 完整代码可参考 GitHub;同时欢迎大家下载使用: alfred-antd
GitHub 参考地址: github.com/KunLunXu0-0…
NPM 包地址: www.npmjs.com/package/alf…
一、初始化项目
复制下列命令, 再终端中执行, 其实注释不删除会有报错, 不过不影响命令执行结果
mkdir alfred-share && \ # 创建项目目录
cd alfred-share && \ # 进入项目目录
npm init -y && \ # 初始化 npm 项目
git init && \ # 初始化 git
echo node_modules > .gitignore # 创建 .gitignore 并添加内容: node_modules
二、添加 Alfred 工作流基础配置
这一步的主要目的是, 为项目添加
Alfred
工作流的配置模板, 这里需要先在Alfred
中创建一个空的工作流, 再复制使用
2.1 获取 info.plist
配置模板
- 创建
Alfred
临时工作流: 偏好设置(Preferences
) -> 工作流(Workflows
) ->点击 +
->Blank Workflow
-> 填写信息 ->create
- 复制
info.plist
至npm
项目下: 选中临时工作流 -> 右键 ->Open in Finder
-> 将目录中的info.plist
复制到npm
项目根目录下即可
- 删除临时工作流: 选中工作流 -> 右键 -> 删除(
Delete
)
三、项目基础搭建
3.1 安装依赖 alfy
alfy
是基于node
实现 一个Alfred
工具库, 能够帮助我们轻松创建Alfred
工作流
npm i alfy
3.2 修改项目配置文件 package.json
- 添加
"type": "module"
配置: 使用ES
模块处理js
文件alfy-init
命令是alfy
带有的一个命令, 用于初始化(安装)
工作流alfy-cleanup
命令是alfy
带有的一个命令, 用于清除(卸载)
工作流postinstall
是npm
中的一个钩子, 在当前项目中执行npm install
结束后, 会自动执行钩子设置的命令(初始化工作流)
{
"name": "alfred-share",
"version": "1.0.0",
"description": "",
"main": "index.js",
+ "type": "module",
"scripts": {
+ "start": "alfy-init",
+ "clear": "alfy-cleanup",
+ "postinstall": "npm run start"
},
"keywords": [],
"author": "",
"license": "ISC"
}
3.3 安装、卸载工作流
从上文可知, 要
安装
工作流, 实际上我们只要执行alfy-init
即可, 我们可以通过执行下面任意一条
命令来进行安装工作流
# 方式一: 通过 npm install 命令, 当执行完后会触发 postinstall 钩子, 执行 npm run start
npm install
# 方式二: 执行我们设置的 npm 脚本, 实际上执行的是 alfy-init
npm start
# 方式三: 直接执行 alfy-init
npx alfy-init
要
卸载
工作流, 有两种方式
- 直接在
Alfred
中将工作流删除即可- 通过执行
alfy-cleanup
进行卸载, 你可以通过执行下面任意一条
命令来进行卸载
# 方式一: 执行我们设置的 npm 脚本, 实际上执行的是 alfy-cleanup
npm run clear
# 方式二: 直接执行 alfy-cleanup
npx alfy-cleanup
四、开胃菜
实现
Alfred
工作流: 快速打开掘金首页、活动中心、资讯中心
4.1 为工作流设置图标
进入工作流 -> 双击工作流 -> 将图标拖拽进来即可
4.1 为工作流新增一个可执行脚本
进入工作流配置页面 -> 选择要配置的工作流 -> 在编辑区右键 -> Inputs -> Script Filter -> 填写信息
- keyword: 工作流关键字, 用于唤醒该工作流
- placeholder Title: 标题
- placeholder Subtext: 子标题
- please Wait Subtext: 脚本执行过程中需要显示的文案
- 可执行脚本内容:
./node_modules/.bin/run-node index.js
调用项目中run-node
命令, 执行index.js
脚本文件- 注意:
Script Filter
因为不需要参数, 所以记得参数设置为No Argument
4.2 新建文件 index.js
项目根目录下新增文件
index.js
通过console.log
打印出如下JSON
字符串 JSON 格式参考: www.alfredapp.com/help/workfl…
console.log(JSON.stringify({
items: [
{
"title": "掘金", // 标题
"subtitle": "打开掘金", // 子标题
"arg": "https://juejin.cn", // 返回参数(链接), 供后面流程使用
// "icon": "./juejin.png", 图标, 可选, 默认为工作流设置的图标
// 定制键盘按键的方法
"mods": {
// 按 alt (option) 后将替换上面的配置
"alt": {
"subtitle": "打开活动中心",
"arg": "https://juejin.cn/events/all",
},
// 按 cmd 后将替换上面的配置
"cmd": {
"subtitle": "打开资讯",
"arg": "https://juejin.cn/news",
},
},
},
]
}))
4.3 测试
唤醒
Alfred
-> 输入关键词share
-> 来回按alt (option)
和cmd
观察下拉项Subtext
的变化
4.4 设置 Action
在上面我们完成了一个简单的工作流, 并成功唤醒, 但是当我们选中下拉项
时, 是不会触发任何操作的; 接下来我们需要为我们的工作流设置一个 Action
:
- 当我们直接选中下拉项, 我们需要打开掘金首页
- 当我们按住
alt (option)
选中下拉项, 我们需要打开掘金活动中心 - 当我们按住
cmd
选中下拉项, 我们需要打开掘金资讯中心
- 进入工作流配置页面 -> 选择要配置的工作流 -> 在编辑区右键 ->
Actions
->Open URL
->Save
- 将工作流的两个步骤关联起来
4.4 测试
唤醒
Alfred
-> 输入关键词share
- 直接选中下列项, 测试是否能够打开
掘金首页
- 按住
alt (option)
选中下拉项, 测试是否能够打开掘金活动中心
- 按住
cmd
选中下拉项, 测试是否能够打开掘金资讯中心
4.5 使用 alfy.output 输出
在上文 index.js
中我们是通过 console.log
输出了 JSON
字符串
该 JSON
作为 下拉项配置
进行输出
实际上 alfy
提供了 output
方法, 我们只需要调用该方法并传入 items
数组即可
import alfy from 'alfy'
alfy.output([
{
"title": "掘金", // 标题
"subtitle": "打开掘金", // 子标题
"arg": "https://juejin.cn", // 返回参数(链接), 供后面流程使用
// "icon": "./juejin.png", 图标, 可选, 默认为工作流设置的图标
// 定制键盘按键的方法
"mods": {
// 按 alt(option) 后将替换上面的配置
"alt": {
"subtitle": "打开活动中心",
"arg": "https://juejin.cn/events/all",
},
// 按 cmd 后将替换上面的配置
"cmd": {
"subtitle": "打开资讯",
"arg": "https://juejin.cn/news",
},
},
},
])
五、进入正题
5.1 修改图标
将上文设置的掘金图标替换为
Antd
图标
5.2 获取 Antd 文档(组件)列表
首先我们第一步是需要知道 Antd 官网 总共有哪些组件, 以及它们对应文档的链接, 这里就有两个方案:
- 方案一就是代码里通过配置文件直接写死, 但是呢这样显然不够 "高级"、"智能"
- 方案二就是通过读取 Antd 官网 解析
hmtl
拿到所有组件名以及它们对应的链接并自动生成一份配置
这里我们选择方案二, 具体流程如下:
- 首先需要安装下
jsdom
依赖, 我们需要用它来解析html
npm i jsdom
- 创建文件
updateConfig.js
开始我们的编码
import fs from 'fs'
import util from 'util'
import process from 'child_process'
import { JSDOM } from 'jsdom'
const exec = util.promisify(process.exec);
const PAGE_URL = 'https://ant.design/components/overview-cn/'
// 1. GET 请求拿到官网 HTML
const { stdout: body } = await exec(`curl ${PAGE_URL}`)
// 2. 使用 jsdom 解析 HTML
const { window } = await new JSDOM(body);
// 3. 获取所有菜单节点, 拿到我们想要的数据
const res = [...window.document.querySelectorAll('.main-menu-inner a')].map(ele => {
const [first, second] = ele.querySelectorAll('span');
return {
arg: `https://ant.design/${ele.getAttribute('href')}`,
title: first?.textContent? `${first?.textContent} ${second?.textContent}`: ele.textContent,
}
})
// 4. 生成配置文件 config.js
fs.writeFileSync('./config.js', `export default ${JSON.stringify(res, null, 4)}`)
// 5. 输出日志
console.log('更新配置成功!')
- 测试: 执行代码, 看是否生成配置文件
node ./updateConfig.js
- 这里我们并不希望
git
上传生成的配置文件config.js
, 因为我们希望每次安装工作流
的同时, 都能够生成最新的配置, 并支持手动更新 (这个后面会进行详细讲解), 这里就需要修改下.gitignore
文件
node_modules
+ config.js
- 修改
package.json
并每次安装工作流
同时自动更新配置
"scripts": {
+ "start": "node ./updateConfig.js && alfy-init",
"clear": "alfy-cleanup",
"postinstall": "npm run start"
},
- 测试: 卸载并重新安装工作流, 测试是否成功安装工作流、并生成配置文件 (为了方便测试, 如果你项目下有配置文件请一并删除)
rm ./config.js # 删除配置文件
npm run clear # 卸载工作流
npm run start # 安装工作流
5.3 手动更新配置文件
倘若我们已经安装完工作流, 但是呢, 官网添加了新的组件, 这时候就有了手动更新配置的需求, 所以我们希望能够通过 Alfred
并输入关键词 updateShareConfig
来完成配置的更新
完整的工作流流程如下
- Inputs / Keyword: 关键词, 用于唤醒工作流
- Actions/Run Script: 执行脚本, 执行脚本
updateConfig.js
- Outputs/Post Notification: 消息提示, 更新成功后会有消息提示
Inputs/Keyword 配置如下:
- keyword: 关键词, 这里其实不区分大小写
- Title: 显示标题
- Subtext: 子标题
- 注意: 因为不需要参数, 所以记得参数设置为
No Argument
Actions/Run Script 配置如下: Script: 脚本,
./node_modules/.bin/run-node updateConfig.js
脚本调用项目中run-node
命令, 执行updateConfig.js
Outputs/Post Notification 配置有:
- Title: 提示信息的标题
- Text: 提示信息的文本内容,
{query}
为上一个流程输出的内容, 也就是执行脚本时, 脚本打印的内容, 即updateConfig.js
最后console.log
输出的日志
- 测试: 删除项目中生成的配置文件
config.js
-> 唤醒Alfred
-> 输入关键词updateShareConfig
-> 选择下拉项, 查看是否生成配置文件、是否有消息提示
5.3 获取参数
我们需要有个筛选的功能, 故而第一步我们需要先获取到参数
修改
Script Filter
:
- 修改脚本内容, 可通过
"$1"
向脚本传递参数- 修改参数模式为
Argument Optional
修改
index.js
尝试让下拉项标题实时展示我们输入的内容 **注意: **同node
脚本,process.argv[2]
开始为执行脚本时输入的参数
import alfy from 'alfy'
alfy.output([
{
"title": process.argv[2] || '请输入文本', // 标题
"subtitle": "打开掘金", // 子标题
"arg": "https://juejin.cn", // 返回参数(链接), 供后面流程使用
},
])
**测试: **唤醒
Alfred
-> 输入关键词share
-> 随意输入文本 -> 观察下拉项标题的变化
5.4 基础功能实现
修改 index.js
- 读取配置文件
- 根据「检索参数」进行过滤
- 处理过滤后数据: 过滤后数据为空, 则返回全部、并追加额外字段
subtitle
- 输出下拉项
import alfy from 'alfy'
// 1. 读取配置文件
import config from './config.js'
// 2. 根据「检索参数」进行过滤
const filterData = config
.filter(v => v.title.toLocaleLowerCase().includes(process.argv[2] || ''))
// 3. 处理过滤后数据: 过滤后数据为空, 则返回全部、追加额外字段 subtitle
const items = (filterData.length !== 0 ? filterData : config)
.map(v => ({
...v,
subtitle: `打开组件: ${v.title}`
}))
// 4. 输出下拉项
alfy.output(items)
测试: 唤醒 Alfred
-> 输入关键词 share
-> 进行搜索 -> 选中下拉项
5.4 按住 com 打开 API
上文基本已经实现我们想要的功能, 但是我们大部分的场景可能是想要直接跳转到组件的 API 模块 , 下面我们来实现这么一个功能, 当我们按住 cmd
的同时选择下拉项, 将直接跳转到对应组件的 API
模块
import alfy from 'alfy'
// 1. 读取配置文件
import config from './config.js'
// 2. 根据「检索参数」进行过滤
const filterData = config
.filter(v => v.title.toLocaleLowerCase().includes(process.argv[2] || ''))
// 3. 处理过滤后数据: 过滤后数据为空, 则返回全部、追加额外字段 subtitle
const items = (filterData.length !== 0 ? filterData : config)
.map(v => ({
...v,
+ subtitle: `打开组件: ${v.title}, 按住 cmd 打开 API`,
+ // mod 可以设置通过控制不同按键, 来修改覆盖默认参数
+ mods: {
+ cmd: {
+ arg: `${v.arg}#api`,
+ subtitle: `打开组件: ${v.title}, 并跳转至 API`,
+ },
+ },
}))
// 4. 输出下拉项
alfy.output(items)
到此我们所有功能都已经实现, 下面是完整的功能演示
六、发布
最后的最后我们可以将我们的包上传到 NPM , 供别人下载使用
# 在这之前你可能还需要注册、登录
npm publish
测试: 卸载工作流 -> 全局安装发布的 NPM 包 -> 测试是否正常使用
npm run clear # 卸载工作流
npm i alfred-share -g # 全局安装我们发布的 npm 包
如果需要卸载工作流, 只需要卸载全局安装的包即可
npm uninstall alfred-share -g
根据 NPM 规定, 发布的包在 24 小时内是允许进行撤销的, 对于测试包, 为了不占用资源最后还是尽可能的进行撤销
npm unpublish --force
七、参考资料
八、Q & A
7.1 Alfred 如果关闭预览: 按 Shift 默认会打开预览弹窗
修改 Features-> Previews 里设置即可
7.2 Outputs Post Notification 无法发起通知
需要注意消息通知那儿是否禁止 Alfred
进行消息提示
大家好, 我是墨渊君, 如果您喜欢我的文章可以:
- 关注公众号: 「昆仑虚F2E」获取最新文章。
- GitHub: github.com/MoYuanJun
- 个人网站(昆仑虚, 虽然现在没啥东西): www.kunlunxu.cc