AlfredのワークフローをNode.jsを使って作成します。
AlfredのワークフローはデフォルトでNodeをサポートしていないため、

NodeでAlfredのワークフローを開発出来るようにする Alfy
というパッケージを使います。
sindresorhus/alfy: Create Alfred workflows with ease

2020/11/10現在 バージョンが 0.10.0
と1.0.0以下なのが気になりますが、スター数も1k超えていて使いやすいパッケージになってます!
Alfy
を使うことでAlfredのワークフローをNodeで作ることができます。
またGitでの管理もしやすく出来るようなかゆいところに手が届く工夫がされています!(素晴らしい。。😭)
作成の手順や Alfy
を使った際の仕組みで理解が難しい部分があったため細かく書いていきます。
また、作成したものをGitで管理したいのでその手順も合わせて記載します。
検証した環境
1 | yarn | 1.22.4 |
2 | node | 14.13.1 |
3 | Alfy | 0.10.0 |
作成手順
先に大まかな作成手順を
- 1.GitHubのリポジトリ作成(Git管理しない場合はスキップ)
- 2.ダミーのワークフローを作成
- ワークフローの核となる
info.plist
を作成するため
- ワークフローの核となる
- 3.リポジトリのフォルダでAlfy導入
- 合わせて2.で作った
info.plist
を移動
- 合わせて2.で作った
- 4.
index.js
に処理を追加 - 5.
alfy-init
を実行してワークフローを管理するフォルダにシンボリックリンクを貼る
理解しづらいのが2と5かな、と思います。
Alfredはワークフローを「info.plist」というもので管理していて、
2でinfo.plistを作る
↓3でinfo.plistをGit管理するフォルダに移動
↓5でAlfredのワークフローを管理するフォルダ内にシンボリックリンクを貼ってinfo.plistを戻す
という流れになります。
今回作るもの
今回はこのようなものを作ります

まず一般的なAlfredのワークフローようにキーワードを入力し起動させ、
jsで処理(Alfyを使用)を実行
処理した内容を画面に出力します
1.GitHubのリポジトリ作成
Git管理しない人はスキップして下さい。
本題とそれるので簡単に。
先にリポジトリの作成とクローンをしておきます。

この段階でREADME.mdを作ってfirst commitしておくとブランチ切ることも出来るようになるのでおすすめ
2.ダミーのワークフローを作成
ダミーのワークフローを作成します。
なぜダミーを作るかというと、Alfredの全ての設定が書かれているinfo.plistを手にいれるため。
空白のワークフローを作成
左下の「+」ボタンから Blank Workflow
を選択して空白のワークフローを作成します

Node.jsを使用する、というのを分かりやすくするためにNode.jsのアイコンを拝借してみました。
Bundle Idが必須になります、設定しないと以下のようなエラーが出るためです。
This script must be called from Alfred, $alfred_workflow_cache is missing. Make sure a Bundle ID is set.
Workflowの流れを作成
作成したワークフローで 右クリック → Inputs → Script Filter
を選択し、

以下のように入力
- Keyword・・alfredのアクションを起こすための好きな文字列(ここでは
hoge
で起動) - Placeholder Title・・Keyword(この場合
hoge
)入力後に表示されるテキスト、必須- なくても大丈夫やろ、と思ったらないと表示されません、注意
- Language・・
/bin/bash
- Script・・
./node_modules/.bin/run-node index.js "$1"
- AlfyでNodeを実行する際の定型文、と思って下さい

またjsで処理した値をテキスト表示したいため Outputs → Large Type
を選択しScript Filterとつなげます。

Large Typeの内容はシンプルにScript Filterで選択した内容を表示するだけでいきます。

info.plistの確認
作成したワークフローを選択し「Open in Finder」で該当ワークフローのフォルダを開くと「info.plist」が作成されています。
(アイコンを設定したため、 icon も一緒に存在しています)

info.plistをのぞいてみるとワークフローがどのように処理され作られているか、イメージがつきやすいです。
3.リポジトリのフォルダでAlfy導入
いよいよAlfredの処理の部分をNodeで書ける環境を作っていきます!
info.plistをリポジトリフォルダにコピー
Gitで管理するリポジトリフォルダにinfo.plistをコピーします

私のようにアイコンなど何かしら追加のファイルがある人はそのファイルも含めてコピーします
alfred-workflow-node-sample/
icon
info.plist
README.md
ダミーのワークフローを削除
先程Alfredで作ったダミーのワークフローを削除します!!
後々$ alfy-init
というコマンドを叩いて復活するのでいったん今は削除!

Alfyの導入
肝心のAlfyを導入します!
Git管理するリポジトリフォルダで yarn init
か npm init
を実行
$ yarn init -y
Alfyをインストール
$ yarn add alfy
パッケージを追加したので「node_modules」フォルダが作られます。
git管理したくないので「.gitignore」を作成しGit管理対象から外します
node_modules/
ここまででフォルダ構成はこのようになってます
alfred-workflow-node-sample/
icon
info.plist
node_modules/
package.json
README.md
yarn.lock
4.index.jsに処理を追加
Prettier導入(お好みで)
Prettierを使うと自動フォーマットしてくれてコーディングで考えることが減るので、jsを書く前のこのタイミングでの導入がおすすめ!
本題とそれるので簡単に。
Prettierをインストール
$ yarn add -D prettier
設定をpackage.jsonに追記(設定内容はお好みで)
{
"name": "alfred-workflow-node-sample",
・・・
"prettier": {
"singleQuote": true,
"semi": false,
"arrowParens": "avoid"
}
}
index.jsを追加
ここまでくれば後一息!
Alfredの核となる処理の部分を「index.js」に書いていきます。
簡単なリスト表示するコードです
const alfy = require('alfy')
const items = [
{ title: 'hello, Alfred', subtitle: 'alfred subtitle', arg: 'alfred' },
{ title: 'hello, Node', subtitle: 'node subtitle', arg: 'node' },
]
alfy.output(items)
最終的な成果物を実行した際のイメージを見ると、コードで何をやっているか分かりやすいです

「hoge a」と謎な a
が付いているのは、ワークフローを作る際に「Argument Required」で設定したからですな。😎笑

arg
は次のアクションに渡される値です。
例えば、argにURLを設定して次のアクションとして「Open URL」を設定すれば、Webページを開く、ということが出来ます。
Alfyのコードについて
公式GitHubのREADME.mdが充実しているので1度目を通すのがおすすめ!
sindresorhus/alfy: Create Alfred workflows with ease
alfy.output()
の引数に渡した値が一覧で表示されます。
outputは以下のように定義されていて
output(list, options?)
listにはオブジェクトの配列を渡す必要があります。
listに渡すオブジェクトで定義出来るものはAlfred公式ページに書かれています
Script Filter JSON Format - Workflow Input Objects - Alfred Help and Support
{"items": [
{
"uid": "desktop",
"type": "file",
"title": "Desktop",
"subtitle": "~/Desktop",
"arg": "~/Desktop",
"autocomplete": "Desktop",
"icon": {
"type": "fileicon",
"path": "~/Desktop"
}
}
]}
最低限 title
があれば成り立つため以下のコードでも動作します
const alfy = require('alfy')
const items = [{ title: 'hello, Alfred' }, { title: 'hello, Node' }]
alfy.output(items)
5.alfy-initを実行
Alfyのパッケージの中には alfy-init
というコマンドが含まれています。
alfy-init
はAlfredのワークフローを管理するためのフォルダにシンボリックリンクを貼ってくれる、というもの。
#!/usr/bin/env node
'use strict';
const execa = require('execa');
(async () => {
try {
await execa('alfred-link', {
preferLocal: true,
localDir: __dirname
});
} catch (error) {
console.error(error);
process.exit(1);
}
})();
exaca
というライブラリでシンボリックリンクを貼ってくれてそうですね
実行してみると、
$ npx alfy-init

ワークフローのフォルダにシンボリックリンクが作られてます。
この状態でAlfredを見てみると、

!!
削除したワークフローが復活してる。。
つまり、Alfredは workflows/<ワークフローのフォルダ>/info.plist
でワークフローの管理をしてるんですね。
Alfredを実行する
いよいよ実行してみます
できた!😍
文字でかいなw