TypeScriptでPipedreamコンポーネントを書く

2020/08/14 16:19:312020/08/14 17:14:37


npmパッケージを公開したよ〜という内容は書いたが、実際どういった感じで使うのかみたいなのは書いていなかったなと思いかける限りで。

https://pipedream.comという、各サービスから発生したイベントを受け取って、それに対してjsの任意のコードを実行することができるというサービスがある。
そもそもjsの任意コードをcron構文で定期的に回し、実行結果に合わせてイベントを発火させることもできるし、コード内ではnpmから任意のパッケージを使うことができるし、サービスに組み込まれたkvストアを用いることもできる。
しかし、型が特徴のAltJSであるTypeScriptを書き慣れた筆者にとっては、型がつかない生のjsを書き連ねるというのは非常に辛い行為であり、かなりやってられない。どうしても型を付けたい。
pipedreamでは、ワークフローの一部としてjsを設定する場面では、ただのasync関数の中身をかけるだけにとどまっているので、prettierのplaygroundで整形ぐらいはできても型精査をすることができない。
が、最近になって公開されたSources(Alpha)では、指定の形式のjs(Component)にさえなっていれば、jsを丸ごと投げ込むことができる。
そこで、筆者が最近これに型をつけるためのironpipeというのをnpmに公開したので、これを用いてComponentをTypeScriptで記述するための手順を軽く説明したい。

セットアップ
基本的なtsプロジェクトをセットアップする。
適当なディレクトリを作成し、yarn init、必要なライブラリをaddする。
今回はコンパイルにrollupを用いるため、それも同時に導入している。
setup.sh
git init # お好み 
yarn init # 連打で良い 
yarn add -D typescript prettier rollup rollup-plugin-esbuild esbuild glob 
yarn add ironpipe # devDepsとの区別は適当。実際にsrcでimportするものをdevから外している
  • tsconfig.jsonこれをそのままコピってきてtargetのみes2018とすればよい。
  • .prettierrcはお好みで。
  • .gitignoreはこことかから引っ張る。
rollup.config.js
const esbuild = require("rollup-plugin-esbuild") 
const glob = require("glob") 
 
export default glob.sync("src/*.ts").map((file) => { 
  return { 
    input: file, 
    output: { 
      dir: "dist", 
      format: "cjs", 
      preferConst: true, 
    }, 
    plugins: [esbuild()], 
    external: [/^(?!.*\.).*$/], // relativeなファイルのみ取り込む 
  } 
})
これで基本的な準備は完了。

Componentを書く
では実際にComponentを書いてみよう。今回はデフォルトでも用意されているrssをよりベターなコードで書き直す。
src/rss.tsを作成し、必要なライブラリを導入する。
rss.sh
yarn add rss-parser
src/rss.ts
import { defineComponent } from "ironpipe" 
import rssParser from "rss-parser" 
 
module.exports = defineComponent({ 
  name: "rss", 
  version: "0.0.1", 
  props: { 
    url: "string", 
    timer: { 
      type: "$.interface.timer", 
      default: { 
        intervalSeconds: 60 * 15, 
      }, 
    }, 
  }, 
  methods: {}, 
  dedupe: "unique", 
  async run() { 
    const parser = new rssParser() 
    const feed = await parser.parseURL(this.url) 
    feed.items?.map((item) => { 
      this.$emit(item, { 
        id: item.guid!, 
        summary: item.title, 
        ts: new Date(item.pubDate).getTime(), 
      }) 
    }) 
  }, 
})
これをやった後にyarn rollup -cをするとdist/rss.jsにComponentとしてはっ付けられるjsが生成されている。
  • 今はrss-parserのdepsに@types/xml2jsが欠如しているのでtscは通らないのだが、esbuildは型検査をしないので通る。
  • VSCodeで型エラーが出てなければいいかなという考え方をしています 今
これだけだとあっけないのでコンポーネント各所の説明を軽くする。Vueのコンポーネントを持ってきたみたいなことがどこかに書いてあった気がする。
  • ドキュメントにはこれから仕様バンバン変える可能性があるみたいなこと書いてあるので随時変わる可能性あり
中身
  • name
  • コンポーネントの名前。なんでもよい
  • version
  • コンポーネントのバージョン。これを変更したことによる挙動の変化は確認できていない。
  • props
  • コンポーネント設定時に利用者から指定できる変数群。今はstring、boolean、$.interface.timer$.interface.http$.service.dbあたりが明示的に使える。thisから生える。
  • methods
  • コンポーネントのthisを用いる関数を生やせる場所。runに置いても同じことだとは思うのだが存在意義は不明。Vueと同じかも。thisから生える。
  • dedupe
  • emitの2引数目のidのダブりを無視する場合はuniqueとなる
  • run
  • メインの処理
thisに予め生えてる特殊関数
  • $emit
  • 1つ目の引数はデータ。このコンポーネントを利用するワークフローからeventとして参照できるようになる。
  • 2つ目の引数はメタデータ。idは必須でこれがないと$emitが無視される。summaryがあるとイベント一覧に表示されるようになり、tsはおそらく時刻情報として使われる?(未検証)

ここらへんで体力尽きた
書いたコンポーネントはgistに貼れるものは貼ってるのでそちらを見てください https://github.com/ci7lus/ironpipe#example-usage


著者の画像

ci7lus

@ci7lus

Caramelize - Made withCaramelizeand / Privacy