9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

「Develop fun!」を体現する Works Human Intelligence #2Advent Calendar 2020

Day 10

SlackのBlock Kitをより便利にするモジュールを作った話

Last updated at Posted at 2020-12-09

本記事は、株式会社Works Human Intelligenceのアドベントカレンダー、「Develop fun!」を体現する Works Human Intelligence #2の10日目の記事です。

はじめに

今年は、Slackアプリを作りまくった1年でした。
Slackアプリ開発の知識がない状態から、2つのアプリを作り、現在、さらに1つのアプリを実装中です。

そこで、これらのアプリ開発の効率化のために独自に作成した、SlackのUIフレームワーク(Block Kit)を扱うためのモジュールの紹介をしたいと思います。

Block Kitとは

Block Kitとは、SlackアプリのUIフレームワークです。

Slackでは、ボタンやセレクトメニュー、日付セレクターなどのコンポーネントを組み合わせてUIを構成しますが、これらのコンポーネントはBlock Kitによって提供されています。

また、ボタンなどのコンポーネントをユーザーが操作した際に、UIの表示を変更したり、アプリ(Bot)からメッセージを送信したりするなど、ユーザーとアプリ間で対話的なコミュニケーションを行うことができます。

さらに、Block Kit Builderというツールを利用することによって、コードを記述することなく、Slackのメッセージやモーダルのデザインを簡単に作成することができます。
これは、具体的なアプリのイメージを作成する際に、大変役に立ちます!

詳しい説明は、Block Kitのページに記載してあるので、参照してください!

Block Kitの欠点

しかし、こんな素晴らしいBlock Kitでも、(多分)1つだけ、欠点があります。

それは、Block KitのUI定義はJSONで記述されるため、ソースコードの中で扱いにくいということです。

作ったもの

このBlock Kitの唯一の欠点を補うべく、作ったものが「block-kit-handler」です。
block-kit-handlerは、npmで公開しているため、Node.jsでSlackアプリのバックエンドを実装する場合に利用することができます!

block-kit-handlerでは、SlackのBlock Kitで提供されている各コンポーネント(テキストやボタン、セレクトメニューなど)を返す関数を実装しています。
そのため、これらのコンポーネントを(JSONとしてではなく、)オブジェクトとして扱うことができます。

block-kit-handlerのおすすめの使い方

ここでは、block-kit-handlerを使った、効率的なSlackアプリのUI実装の方法をご紹介します。

block-kit-handlerの使い方は、下記のページや公開プロジェクトでも説明をしています。
とにかく、実装例を見たいという方は、下記ページをご参照ください!

とりあえずインストールする

まずはインストール方法です。
Node.jsのプロジェクトでblock-kit-handlerを利用するためには、下記コマンドを実行します。

npm install block-kit-handler

UIを作成してみる

次に、頭に思い描いているUIを実際に作ってみます。
こんなときには、前述のBlock Kit Builderがとても便利です。
今回は、モーダルで下記のようなUIを作成してみることにします。

modal.png

ちなみに、このUIをJSONで記述すると、こんな感じになります。
意外と行数が多く感じるのではないでしょうか?

JSONで記述した場合
{
	"title": {
		"type": "plain_text",
		"text": "App menu",
		"emoji": true
	},
	"submit": {
		"type": "plain_text",
		"text": "Submit",
		"emoji": true
	},
	"type": "modal",
	"close": {
		"type": "plain_text",
		"text": "Cancel",
		"emoji": true
	},
	"blocks": [
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": "*Hi <fakelink.toUser.com|@David>!* Here's how I can help you:"
			}
		},
		{
			"type": "divider"
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": ":calendar: *Create event*\nCreate a new event"
			},
			"accessory": {
				"type": "button",
				"text": {
					"type": "plain_text",
					"text": "Create event",
					"emoji": true
				},
				"style": "primary",
				"value": "click_me_123"
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": ":clipboard: *List of events*\nChoose from different event lists"
			},
			"accessory": {
				"type": "static_select",
				"placeholder": {
					"type": "plain_text",
					"text": "Choose list",
					"emoji": true
				},
				"options": [
					{
						"text": {
							"type": "plain_text",
							"text": "My events",
							"emoji": true
						},
						"value": "value-0"
					},
					{
						"text": {
							"type": "plain_text",
							"text": "All events",
							"emoji": true
						},
						"value": "value-1"
					},
					{
						"text": {
							"type": "plain_text",
							"text": "Event invites",
							"emoji": true
						},
						"value": "value-1"
					}
				]
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": ":gear: *Settings*\nManage your notifications and team settings"
			},
			"accessory": {
				"type": "static_select",
				"placeholder": {
					"type": "plain_text",
					"text": "Edit settings",
					"emoji": true
				},
				"options": [
					{
						"text": {
							"type": "plain_text",
							"text": "Notifications",
							"emoji": true
						},
						"value": "value-0"
					},
					{
						"text": {
							"type": "plain_text",
							"text": "Team settings",
							"emoji": true
						},
						"value": "value-1"
					}
				]
			}
		},
		{
			"type": "actions",
			"elements": [
				{
					"type": "button",
					"text": {
						"type": "plain_text",
						"text": "Send feedback",
						"emoji": true
					},
					"value": "click_me_123"
				},
				{
					"type": "button",
					"text": {
						"type": "plain_text",
						"text": "FAQs",
						"emoji": true
					},
					"value": "click_me_123"
				}
			]
		}
	]
}

block-kit-handlerでUIを実装する

最後に、Block Kit BuilderでデザインしたUIを、block-kit-handlerで実装します。
今回は、モーダルに描画するUIを作成しますが、ここではモーダルのことは一旦忘れて、とりあえず、UIに含めたいコンポーネント達をリストに詰め込んでいきます。

import { Block } from '@slack/types';
import { Modal, actions, section, button, divider, staticSelect, option, mrkdwnText, plainText } from 'block-kit-handler';

const blocks: Block[] = [
        section({ text: mrkdwnText('*Hi <fakelink.toUser.com|@David>!* Here\'s how I can help you:')}),
        divider(),
        section({
            text: mrkdwnText(':calendar: *Create event*\nCreate a new event'),
            accessory: button(plainText('Create event'), 'create', { value: 'click_me_123', style: 'primary' })
        }),
        section({
            text: mrkdwnText(':clipboard: *List of events*\nChoose from different event lists'),
            accessory: staticSelect('chose-list', plainText('Choose list'), [
                option(plainText('My events'), 'value-0'),
                option(plainText('All events'), 'value-1'),
                option(plainText('Event invites'), 'value-2')
            ])
        }),
        section({
            text: mrkdwnText(':gear: *Settings*\nManage your notifications and team settings'),
            accessory: staticSelect('edit-settings', plainText('Edit settings'), [
                option(plainText('Notifications'), 'value-0'),
                option(plainText('Team settings'), 'value-1')
            ])
        }),
        actions([
            button(plainText('Send feedback'), 'send-feedback', { value: 'click_me_123' }),
            button(plainText('FAQs'), 'faqs', { value: 'click_me_123' })
        ])
];

次に、作成したUIをモーダルに組み込みます。
block-kit-handlerでは、モーダルとホームタブのクラスを提供しているため、これらもオブジェクトとして扱うことができます。

const modal = new Modal(
        plainText('App menu'), 
        blocks, 
        { close: plainText('Cancel'), submit: plainText('Submit') }
);

モーダルでは、作成したUIの他に、タイトルやキャンセルボタンのテキスト、送信ボタンのテキストを自由に設定することができます。

メッセージやホームタブでの実装例は、block-kit-handlerのnpmページに記述しています。
是非、ご参照ください。

モーダルを表示する

Slackでは、メッセージを送信したり、モーダルを表示したり、その他様々なことを行うためのAPIが提供されています。
今回は、モーダルを表示するためのviews.open APIを実行します。

await app.client.views.open({
        token: botToken,
        trigger_id: trigger_id,
        view: modal.getView()
});

tokentrigger_idは、views.openAPIを実行するために必要なパラメータです。
詳しくは、views.open APIをご確認ください。

viewパラメータには、モーダルのJSON(をstring化したもの)を設定する必要があります。
これは、既に作成したblock-kit-handlerのModalクラスのオブジェクトのgetViewメソッドを実行することで取得することができます。

これでモーダルの表示ができました!

※ 今回は、Slackのアプリ開発のフレームワーク Bolt for JavaScript を利用しています。

補足

今回の例では、「Block Kit Builderで作成したJSONをそのまま使ったほうが楽じゃん」と思われた方も多いかと思います。
しかし、もし下記のようなUIを実装したい場合、

  • セレクトメニューに1~10のオプションを設定したい場合
  • 条件によって表示を変更したいとき

block-kit-builderを利用した上で、for文やif文を用いたコードの記述を行うことで、より効率的に、また動的にUIの実装を行うことができます。

まとめ

SlackアプリのUIを実装を行うためのモジュール「block-kit-handler」を作成しました。
block-kit-handlerを利用することで、以下のようなメリットがあります。

  • JSONで記述するより、少ないコード量でUIの実装ができる
  • UIのコンポーネントをオブジェクトとして扱うので、for文やif文などを利用して、効率的に、また動的にUIを作成することができる

是非、使ってみてください!

おまけ

最後に、この一年、Slackアプリ開発を1から学んだ際に、参考になったサイトや、普段のSlackアプリ開発でよく参照するサイトをご紹介します!
これからSlackアプリ開発を始める方の役に立てば嬉しいです。

9
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?