はじめに
今までslack用のbotを開発するのにhubotやerrbotを利用してきたのですが、昨年slackがリリースしたBoltフレームワークのチュートリアルをいくつかやってみて簡単にbot実装ができそうだなと思ったので、それをTypeScriptで実装する場合の方法を紹介します。
Bolt開発時に参考にしたサイト
Boltを使ったslack botアプリの作成方法や実装サンプルなどは、下記を参考にさせて頂きました。
開発環境
主に下記の開発環境で実装及び動作確認をしました。
- VSCode
- node.js
- Glitch
Glitchは、ウェブ上で動くIDEを持っているのですが、ローカルでVSCodeを使うことでコード補完やESLintなども使えるようになるのでローカル環境でVSCodeを利用して実装します。
プロジェクトの作成
Bolt入門ガイドに記載のある通り、下記を実行しプロジェクトを作成します。
$ mkdir first-bolt-app
$ cd first-bolt-app
$ npm init -y
$ npm install @slack/bolt
typescript実装のために必要なパッケージをインストールします。
$ npm install -D typescript @types/node
その他ローカルで開発する上で利用するパッケージをインストールします。
$ npm install dotenv # .envファイルを読み込ませる為に追加
$ npm install -D eslint eslint-config-prettier eslint-plugin-prettier prettier @types/eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser
各種設定ファイルの作成
slackアプリのbot tokenとsigning secretを記載した.env
ファイルを作成します。
SLACK_SIGNING_SECRET=<your-signing-secret>
SLACK_BOT_TOKEN=xoxb-<your-bot-token>
Typescriptプロジェクトをコンパイルするのに必要なコンパイラのオプションを指定するtsconfig.json
ファイルを作成します。
{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"target": "es6",
"noImplicitAny": true,
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist",
"baseUrl": ".",
"paths": {
"*": [
"node_modules/*",
"src/types/*"
]
}
},
"include": [
"src/**/*"
]
}
ESLintの設定ファイル.eslintrc
と.eslintignore
を作成します。
{
"parser": "@typescript-eslint/parser",
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
"prettier/@typescript-eslint"
],
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
},
"rules": {
"semi": [
"error",
"always"
],
"quotes": [
"error",
"double"
],
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-explicit-any": 1,
"@typescript-eslint/no-inferrable-types": [
"warn",
{
"ignoreParameters": true
}
],
"@typescript-eslint/no-unused-vars": "warn"
}
}
# /node_modules/* in the project root is ignored by default
# build artefacts
dist/*
coverage/*
# data definition files
**/*.d.ts
# 3rd party libs
/src/public/
# custom definition files
/src/types/
tscコンパイルやbot実行の為に、package.json
を下記の通りに変更します。
{
〜省略〜
"scripts": {
"start": "npm run build && npm run serve",
"build": "npx tsc",
"serve": "node --require dotenv/config dist/app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
〜省略〜
}
コード作成と実行
ソースコードはsrc/
以下に作成します。
下記はBolt入門ガイドの「メッセージのリスニングと応答」にあるコードをTypescriptコードにしたものです。
ファイル拡張子が.js
から.ts
に変わったのとrequireをimport文に変えただけですね(笑)
もう少し複雑なサンプルコードを持ってくるとTypescriptの型エラーが発生し、適宜修正が必要になってきます。
import { App } from "@slack/bolt";
const app = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET
});
// Listens to incoming messages that contain "hello"
app.message("hello", ({ message, say }) => {
// say() sends a message to the channel where the event was triggered
say(`Hey there <@${message.user}>!`);
});
(async () => {
// Start your app
await app.start(process.env.PORT || 3000);
console.log("⚡️ Bolt app is running!");
})();
Typescriptのコードをコンパイルします。
$ npm run build
> first-bolt-app@1.0.0 build /Users/xxxx/first-bolt-app
> npx tsc
Javascriptに変換されたdist/app.js
が作成されます。
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const bolt_1 = require("@slack/bolt");
const app = new bolt_1.App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET
});
// Listens to incoming messages that contain "hello"
app.message("hello", ({ message, say }) => {
// say() sends a message to the channel where the event was triggered
say(`Hey there <@${message.user}>!`);
});
(() => __awaiter(void 0, void 0, void 0, function* () {
// Start your app
yield app.start(process.env.PORT || 3000);
console.log("⚡️ Bolt app is running!");
}))();
//# sourceMappingURL=app.js.map
botを実行します。⚡️ Bolt app is running!
が出力されれば成功です!
$ npm run serve
> first-bolt-app@1.0.0 serve /Users/xxxx/first-bolt-app
> node --require dotenv/config dist/app.js
⚡️ Bolt app is running!
コンパイルと実行を同時に行う場合は、npm run start
を実行します。
$ npm run start
> first-bolt-app@1.0.0 start /Users/xxxx/first-bolt-app
> npm run build && npm run serve
> first-bolt-app@1.0.0 build /Users/xxxx/first-bolt-app
> npx tsc
> first-bolt-app@1.0.0 serve /Users/xxxx/first-bolt-app
> node --require dotenv/config dist/app.js
⚡️ Bolt app is running!
ここまで動作確認ができたらGlitchに作成したファイルアップすることでローカルマシンまでのトンネルするアプリの公開URLを用意できないと確認ができないslackからのevent受信などの確認もできるようになります。
first-bolt-app/
├── .env
├── package.json
├── src
│ └── app.ts
└── tsconfig.json
Glitch上でbotが起動するときは、npm run start
が実行されるのでコンパイル済みのdist/app.js
はアップしなくても動作します。
おまけ
Bolt フレームワークを使って Slack Bot を作ろうの「Learn More」の「もうちょっと複雑な Glitch サンプル」をTypescript実装したソースコードは下記においてますので参考になれば、幸いです。