技術探し

技術探し

JavaScriptを中心に記事を書いていきます :;(∩´﹏`∩);:

Nature RemoのSlackボットを作った

初めてのIoTの記事を書いた!

そういえば、最近Nature RemoのAPIが公開されたのを思い出した。
今まではスマホからしか操作出来なかったのが不便だったので昨日の夜botを書き、PCで操作できるようにした。

Nature Remoとは?

一言でいうと赤外線の中継地点を作ってくれてそこで登録したリモコンとかの信号定義データを擬似的に作ってくれてリモコンになってくれる感じ。

http://morningpitch.com/wp-content/uploads/2017/03/aerg.png

http://morningpitch.com/startups/7485/

今は、google homeとnature remoをIFTTTで繋いでいて音声でエアコンのon/offも行えるようにしている。

また、エアコンに特化しており、登録がすごく簡単にできる。

Nature Remo

Nature Remo

Slackのbotにした

とりあえずエアコンの操作がしたかったので、一旦エアコンのon/offと温度の変更・風量だけ実装した。

github.com

手順

Nature Remoにログインする

home.nature.global

f:id:about_hiroppy:20180206002234p:plain

Go押して、メールで許可したら上の画面にいく。

アクセストークンを作る

home.nature.global

上のページにGenerate access tokenというボタンがあるのでそれを押す。

Slackのbotを作る

https://<workspace-name>.slack.com/services/new/bot に行きbotを作る。

そこで手に入るトークンを記録する。

リポジトリからbotをcloneする

$ cp .env.sample .env

を行い、先ほど手に入れたアクセストークンとslackのトークンを入力する。

動かす

pm2とか使ってデーモンにしてサーバに置いておく。

f:id:about_hiroppy:20180206003252p:plainf:id:about_hiroppy:20180206003259p:plain

これでPCから操作できるようになった!

参考

swagger: https://developer.nature.global/
公式サイト: http://swagger.nature.global/

ニコニコ動画の音楽に特化した動画も見れるよPCアプリを作った

時期的にも機能的にも区切りがついたので、v1.0.0をリリースしました💃

2018年の1月の目標として、このNicoHacoをv1.0.0でリリースしたいと思っていました。(今2月ですので、少し間に合いませんでしたが。。。)

この一ヶ月の間、全くブログを更新出来なかったのはずっとElectronを触っていたからです。

だからと言ってElectronの知見が溜まったかというとIPC周りぐらいで実際Webでやっていることと変わらないため記事を書くほどの知見はなかった気がします。

NicoHacoとは?

f:id:about_hiroppy:20180205015512p:plain

リポジトリ

github.com

サイト

nicohaco.github.io

NicoBoxみたいに音楽再生に特化しているけど、動画も見れるよアプリです。
本当は音楽だけで良かったのですが、動画も見たくなって急遽見れるようにしました。

詳しくはせっかくサイト作ったのでそちらを見てもらえると嬉しいです😘

ニコ動は機能が多く、すべての実装をすると終わらないので、区切りとして自分がほしかった最低限の機能だけ実装しました。

また、今回リリースを優先してたためリファクタリングが終わらなかったのと細かい修正が残っている部分があるためそれもすぐに修正していきたいと思っています。なのでもうすこしこの開発スピードが続きそうです。

良かったこと

1/20ぐらいからほぼ毎日リリースをしていた。

楽しすぎてこれを仕事にしたいぐらいとりあえず楽しかった。
だから一ヶ月でv1まで持っていけたんだと思う。

良くなかったこと・学び

1月の半分ぐらいは仕事8時間、趣味(これ)6時間ぐらいの生活を送っていたけど、PC画面をずっと見ていると気持ち悪くなることが多かった。。。
大体、ずっと連続でコード書いて12時間ぐらい経過するとダメなことを学んだ。

また、デザインセンスがないので勉強しないといけないなと感じた。
一番時間を使ったのはデザインで一日何も進まないこともあった。

悩み

Electronのメインプロセス側は純粋なNode.jsなのでwebpackやらBabelやらに通したくないんだけど、環境変数の埋め込みをやらないといけなくて結局通す事になった。。。
主に自分の場合、環境変数とFlowが影響あった。(結局実行時にはstripしないといけないので。。)
幸いにもFlowにはコメントで型が付けれる(e.g. /*: string */)優秀な機能があるので今はこれでやっているけど、今現在結局、webpackを通しているのでこれもやめてモジュールもCJSからESMに変えようか悩んでいる。。

FYI flow.org

あと、ニコ動の(公式的には)API無いのでHTMLのパースをしている部分が多くて今後追従大変だなって思っているのでパースできるかどうかの定期テストを書かないとだめかな。。(あとパフォーマンス的にも良くない)

知見

Electronの署名周り

# 無理矢理署名をしてautoupdateのみ確認を行う
# debugのみで実際そのパッケージと同じ署名ではないためパッケージの展開はできないです
# (`update-downloaded` のところで Could not locate update bundle for... と怒られる)
$ codesign --deep --force --verbose --sign - electron.app

# ガギ一覧(macの場合)
$ security find-identity -v

GitHubへのリリースノート作成時

GitHubへapp形式のを直でリリースに貼る時、初めてリリースノートを作成時に投げるとなぜか駄目って言われるので一回リリースを作ってしまい、その後Editしてそこで投げるとzipに圧縮してくれる。[要検証]

f:id:about_hiroppy:20180203122320p:plain

Autoupdate

とりあえずElectronのAutoupdateがめんどくさい。。
今回は、一番ラクにできるでだろうと思っている方法で解決しました。

使ったもの

  • now-cli
  • hazel

github.com

やり方

  • now-cliを使って、nowへhazelをデプロイをする
  • アプリのautoupdaterの向き先をnowのデプロイ先に向ける
# 最初にnowのアカウントを作る
$ npm install -g now
$ now -e NODE_ENV=production zeit/hazel
# 終わり

仕組み

zeitのnow上にhazelを使ってリリースしたバイナリをjsonに紐付けしています。
このjsonは各バージョンのpathに切られたところに配置されます。
流れは、hazelがjsonに最新のGitHubのリリースノートのバイナリのurlを書いてくれるのを生成してくれるので、それをアプリが見てGitHubにある最新バイナリをダウンロードします。
また、hazelは自動的にGitHubのリリースノートを見てくれて紐付けしてくれますので、特に一回デプロイしたら何もすることはありません。

nicohaco/nicohaco

ただ、注意点としてファイル名にmacという文字列がないとmacOSのアプリと認識してくれません。(ハマってコード読みました)

github.com

めっちゃ簡単で便利なのでオススメです。

最後に

長くなりましたが、是非使ってみてください:)

package.jsonで値を展開する

🎍今年初の記事です🎍

そういえばこんな機能あったなーって感じだったので記事にしてみました。

本当は今年最初の記事用意していたのですが、まだ終わってないので後ほど。。

github.com

今回は、タスクのstartとbuildに同じ変数をwebpackへ渡すために共通化したくて、量が多くなってきたのでリファクタリングしました。

手順

$npm_package_にpackage.jsonに書いたkeyをつなげるとそれのvalue展開されます。

コンソール上では、展開されませんが、JS上では展開されます。

// 確認用のJS
console.log(process.argv[2]);
$ npm run main
> node main.js $npm_package_foo

bar

文字列の場合

{
  "foo": "bar",
  "scripts": {
    "main": "node main.js $npm_package_foo"
  }
}

オブジェクトの場合

オブジェクトを渡すことはできないので、末端まで指定する必要があります。

{
  "foo": {
    "bar": 1
  },
  "scripts": {
    "main": "node main.js $npm_package_foo_bar"
  }
}

もし、$npm_package_fooと書いた場合は、undefinedとなります。

配列の場合

配列を渡すことはできないので、添字を指定する必要があります。

{
  "foo": ["bar"],
  "scripts": {
    "main": "node main.js $npm_package_foo_0"
  }
}

もし、$npm_package_fooと書いた場合は、undefinedとなります。

まとめ

  • $npm_package_というプレフィックスが使える
  • 必ず値はプリミティブでなければなりません。

2017年を振り返る

激しい一年でした。

振り返り

今年は転職を二回しました。
5月にドワンゴを辞めて、6月にメルカリに入って、12月にドワンゴに戻りました。
個人的には、社会的な多くの経験を積めたと思うし特に後悔とかはしてません。

しかしながら、多くの方々に御迷惑をかけたと思っています。
今年は多くの方に支えていただき感謝しています。
本当にありがとうございました。

コミュニティ

多くのエンジニアの方に会えたと思います。
JSエンジニアはもちろんですが、別分野のエンジニアの方々に多く出会えた年だった気がします。
今年は国内での活動をしていきたいと思っていたので、その目標は達成したのではないかなと思います。

来年もNode学園祭・学園ともよろしくお願いします!

nodefest.jp

nodejs.connpass.com

登壇

buildersconや情報科学若手の会などでも話してきました。
おそらく、10回ぐらい今年は登壇した気がします。

speakerdeck.com

今はNode9.3.0です
そういえば、入社初日にドワンゴインターン生にbuildersconで発表していた方ですよねって言われました。(JS関係なく)

abouthiroppy.hatenablog.jp

若い方々に囲まれての発表でした:)

ブログ

1, 2週間に1回は必ず記事としてアウトプットしていこうと思っていました。
その目標は達成できたかと思います。

アクセス数

このブログは6月から本格稼働し始めて、本当に多くの方の訪問がありました。
ありがとうございます。
来年もJSに関する記事を上げていきたいと思っています。

f:id:about_hiroppy:20171229095715p:plain

記事数

36 + これ

abouthiroppy.hatenablog.jp

人気

abouthiroppy.hatenablog.jp

abouthiroppy.hatenablog.jp

物作り系

abouthiroppy.hatenablog.jp

abouthiroppy.hatenablog.jp

abouthiroppy.hatenablog.jp

GitHub

f:id:about_hiroppy:20171229093112p:plain

今年は、githubの方があまり出来なかったので来年はOSSを頑張りたいと思っています。

旅行・出張

アイコンの変更

絵師さんに書いていただきました。
モーグリみたいなのって言ったらめっちゃかわいいのが出てきた!

f:id:about_hiroppy:20171225002710j:plain

来年に向けて

とりあえずジグソーパズルを完成させます。

来年はもっともっと自分のスキルアップへの時間へ投資したいと思います。
もちろん、プログラミングだけではなく、英語とか諸々。。
あと海外登壇してみたいなとかも思っていたり。。。(CFPは出している状態です)

今後共こんな自分ですが、よろしくお願いします!!!

次のリリースであるwebpack 4の主な変更点まとめ

ドワンゴアドベントカレンダーの17日が空いているので本来その予定で書かれた記事ではないですが、そこに埋めます。
2日連続になってしまった。。

qiita.com

さて、今年は、webpack3.0.0が2017/06にリリースされました🎉 (現在、3.10.0)

medium.com

After we released webpack v2, we made some promises to the community. We promised that we would deliver the features you voted for. Moreover, we promised to deliver them in a faster, more stable release cycle.

ということでv4😎😎😎

v4は来年2018年の2月のどこかでリリース予定です。
一ヶ月前にアナウンスをし、RC上でリリース日が公開されます。


この記事は、rcが出るたびに更新していく予定です。

現在: rc2

使用側目線でまとめていくのでプラグインを作る人はissueを読んで下さい。

webpack 4

RC

変更

Node4のサポートがなくなりました

LTS対象である6, 8を使うか、currentの9を使ってください。

webpack-cli

CLIが移行されました。

The CLI moved into a separate package: webpack-cli.
Please install 'webpack-cli' in addition to webpack itself to use the CLI.
-> When using npm: npm install webpack-cli -D
-> When using yarn: yarn add webpack-cli -D

github.com

もし、webpack みたいにコマンドを実行している場合はcliを入れる必要があります。

CLI経由でプラグインを入れた場合は、設定ファイルのプラグインよりも優先されます。
また、webpack-cliには設定ファイルを自動生成してくれる機能も持ちます。

github.com

詳しくはリポジトリのdocs等を参照してください。

Modeオプションの追加

production, development, noneのモードを提供します。

--mode         Mode to use (production or development)
$ webpack --mode production
// 最低限、必要な設定
const path = require('path');

module.exports = {
  entry: 'index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve('dist')
  }
};

コードは以下 github.com

共通として、optimization.nodeEnvは各Modeの値となります。

production

webpack --mode production
すべての種類の最適化を行ったバンドルファイルが生成されます。
以下の有効化される機能を見るとわかりますが、今までplugins内に書いていたものがデフォルトでオンとなります。
また、ウォッチモードは持ちません。

有効化される機能
  • performance
    • hints: warning
  • optimization
    • flagIncludedChunks
    • occurrenceOrde
    • sideEffects
    • usedExports
    • concatenateModules
    • noEmitOnErrors
    • minimize

development

webpack --mode development

devtoolはevalで実行されます。

https://webpack.js.org/configuration/devtool/#development

また、ウォッチモード時のために差分ビルドの高速化がされています。

有効化される機能
  • output
    • pathinfo
  • devtool: eval
  • cache: true
  • optimization
    • namedModules
    • namedChunks

none

すべての設定を無効にします。

importの変更

コードが破壊される可能性があるので注意

import()は常に名前空間のオブジェクトを返すようになります。 __webpack_require__.r

また、CJS(CommonJS Modules)の場合はデフォルトのexportへラップされます 。
なので、import()を使いCJSをimportしている場合、そのコードはおそらく壊れます。

モジュールタイプのサポート

モジュールタイプは自動的にmjs, json, wasmに対し選択されます。
他のモジュールタイプはmodule.rules[].typeで設定する必要があります。
また、ローダ内の探査順序は以下のようになりました。
.wasm -> .mjs -> .js -> .json

javascript/auto

現行のwebpack3がこれにあたります。

CJS、AMD、ESMのすべてをサポートします。

javascript/esm

ESMのみをサポートし、他のモジュールをサポートしません。(importのみ可能)
javascript/autoよりもより厳密にESMを処理します。

  • importされた名前のものは必ずimportされたコードに存在する
  • ESMでないものはデフォルトのインポートでのみインポートでき、named importはエラーを出します
    • つまり、Node.jsと同じ挙動
.mjs

javascript/esmが使用されます。
また、import時には拡張子が必要です。

json

JSONのデータ。 解析はされません。

webassembly/experimental

WebAssemblyモジュールのサポート。
JSとWASMのモジュールのインポートが可能となります。
WASMからのexportはESMのimportにより検証され、存在しないものをWASMのexportをimportする場合はエラーがでます。

sideEffects

package.jsonsideEffects: falseがサポートされました。
Tree Shakingに優しいモジュールのために作られました。

github.com

importへのマジックコメントの追加

webpackIncludewebpackExcludeがサポートされました。
Dynamic Importをしている時に、ファイルのフィルタリングを可能とします。

変更された機能・プラグイン

追加

  • optimization.minimizer
    • optimization.minimizeに対する設定を書ける
  • module.rules[].resolve
  • loaderContext.rootContext
    • contextオプション

削除

  • module.loaders
    • v2から入ったrulesを使ってください
  • loaderContext.options
  • Compilation.notCacheable
  • NoErrorsPlugin
  • Dependency.isEqualResource
  • NewWatchingPlugin

名前の変更

  • NoEmitOnErrorsPlugin -> optimize.noEmitOnErrors
    • productionモード時は標準で有効
  • ModuleConcatenationPlugin -> optimize.concatenateModules
    • productionモード時は標準で有効

その他

  • ProgressPlugin(--progress)にプラグイン名が出るようになった
  • uglifyjs-webpack-pluginがデフォルトでES2015のサポートとキャッシュと並列処理できるようになった
    • optimization.minimizeで使われている

速度

多くのパフォーマンス改善が行われました。
特にビルド周りが変わったと思います。

parcelとの比較です。

github.com

速いぞ!!!


さいごに

今年最後の技術記事となりましたが、リリースまでは更新していこうと思っています。

それでは、お楽しみに!

botたちの家を作っている

今日が入社日です。

abouthiroppy.hatenablog.jp

この記事は第2のドワンゴ Advent Calendar 2017の18日目です。


12/11に旅行行っててなんとなく現地で作りたいと思ってそこから書いていますので、まだ下地の段階です。今後に期待してください:)

とりあえず最低限のベースの機能実装を行いました。

github.com

これはなに?

Slack Appです!
名前の通り、botたちを収容する施設です。
BotがJSのコードを持っていて、親がそれを動かします。

以下を見てもらえるとわかりやすいかも。
f:id:about_hiroppy:20171218082718g:plain

招待されたのは親botで実行されたのは子供botとなります。

完全にPC用で作っているので、レスポンシブデザインとかないです。

目的

botを書く -> どこかにデプロイする -> slackでbotの設定をする

このフローを毎回やるの辞めたい!(めんどくさい)

ブラウザ上でJSの実行させたいコードを書くだけで後はやってくれる感じにしてほしいのでそれが目的です。

現在の進捗

  • botの登録、実行、編集、削除が行える
  • botからのコマンド

今後やりたいこと

機能面

  • 今現在、botに対する呼び出しの単語が一つなので正規表現を使えるようにする
  • 一つのbotに対して複数のチャンネルを登録できるようにする
  • ストレージ機能の実装(例: TODOアプリ)
  • private機能と権限周り
  • SlackのRTMを使っているため様々なイベントフックができるので、それにも反応できる
  • アイコンの画像対応
    • 表示はできるがアップロード画面作るのめんどくさくてまだやってない

コード面

  • botのeval実行(Functionでも可)に対して、キャンセリングを実装する
  • セキュリティやばい
    • 今はslackチームという身内で使うので優先度が低い
  • 例外処理が雑魚
  • デザインの変更
  • テストを書く
  • NodeのコードもBabelを通すか迷う
    • フロントエンドのコードがFlowで型定義されているため、APIの型を使いたい
  • dockerを真面目な設定に書き換える
  • 連打とかローディングとか

仕組み

親のbot(Slack app)がいて、それが子供のscriptを実行することより、擬似的に子供のbotがいるように見える。
簡単にいうと、postMessageという関数にiconやnameを付けれるのでそれを変更して別botが動いている仕組みです。

なので、web上でJSのコードを書いたらそれが応答で動くbotになります。

ドワンゴ社内slackでも動いているAlfaさんのbot天国のJS版実装です。
github.com

今現在、子供botができること

fetch, dom操作, メッセージを送るができます。(attachmentはまだ)
async/awaitに対応しているので、ある程度のことはできますが、まだキャンセリングの実装してないのでそれも落ち着いたらやろうと思っています。

Cancel Promise pattern (no cancellable promises)

技術スタック

書く量が多くなるので、ピックアップしていきます。
トランスパイラがBabelでバンドラーがwebpackです。

  • react
  • react-loadable
    • JSチャンクを読み込むルーティング時にローディングする
  • react-alert
  • react-ace
    • JSのエディタで補完とかもできる
  • redux
  • redux-saga
  • express
  • sequelize
    • 今回はpostgresqlとsequelize-cliでmigrate等を行う
    • 今後、bookshelfに戻すかも
  • emoji-mart
  • brace
  • riek
    • inlineフォームの実装
  • classnames
  • workbox
    • googleのService Workerライブラリ
  • postcss-cssnext
  • node-slack-sdk

あとはpackage.jsonを見てください。

DB

ORMはsequelizeでDBはpostgresqlを使いました。

github.com

書くまでに実装する時間があまり無かったため、bookshelfよりも慣れているsequelize, sequelize-cli, postgresqlを使います。

基本的には、sequelize-cli経由でマイグレーションを行ったり、シードを差し込んだりします。

docker-compose

当初、docker-compose内で開発を行っていたのですが、どうもnodemonが上手く動かなかったので一旦ローカルでの開発に戻しました。
もちろん、プロダクションではdocker-composeで動きます。

ちなみにdockerでのwebpack-dev-serverのHMR

github.com

.envを使って環境変数を操作しているのですが、プロダクションやディベロップメントとかの.envファイルを読み込ませるのはどうするのが最適解なのだろうか気になります。。。

またherokuへのデプロイが本当に楽でした。

$ heroku container:push web --app bot-house

これでbuildしてpushしてくれて動くので最高です。

node-slack-sdk

github.com

slack社公式のNode.jsクライアント。
基本ドキュメントが無いので、コード読んだほうが明らかに速いです。
コードに書かれたコメントやdocはスゴイ丁寧なのでそれを一番最初に見るべきだと感じました。
RTMはまだ未実装な部分(例えばRTMでattachmentのメッセージを送れない等)が多いのでそういうときはWEBというnode-slack-sdkのメソッドを使うといいです。

また、Slackの認証そのものがよくわからなかったので以下の記事をよみました。

qiita.com

fastify

github.com

速いことで有名なwebフレームワーク。
初めて今回使ってみましたが使いやすかったです。
ただ、やはりexpressと比べるとエコシステムが充実していなくて、アプリケーションを作っていくと大変でした。
view周りや認証(passport対応)が弱いという印象があります。
例えば、webpack-hot-middlewareが使えなかったりします。
github.com

まだまだ始まったばかりのプロジェクトなので、使ってみて使いやすいという印象が強かったので、コミットしていきたいと思った反面、構築ですごい時間がかかったのでやはりプロダクションのコアな部分はエコシステムが充実しているライブラリを使うべきだと思います。
今後周りのエコシステムの作成やコアにコミットしてみたいと思っています。
ググっても情報は基本ないので、最初にissueとコードを読んだほうが速いです。

今回は2日間ぐらいハマった部分があり、結局expressへ乗り換えました。

ちなみにチートシート

devhints.io

クライアント側ルーティング及びチャンク

react-routerを使っています。
また、今回はdynamic importのためreact-loadableを使っています。

github.com

react-loadableはチャンクで切られたパーツを読み込むまでに表示させるローダーの設置などができます。
もちろん、Preloadingもできますが今回はまだやってません。

                                                 Asset       Size  Chunks                    Chunk Names
StratumNo1 Medium-06a6ac1709970857f419dc78aca05353.ttf    62.3 kB          [emitted]
                           BotsShow.bundle.54f65aa8.js     304 kB       0  [emitted]  [big]  BotsShow
                              Index.bundle.54f65aa8.js    10.3 kB       1  [emitted]         Index
                       ChannelsShow.bundle.54f65aa8.js     8.3 kB       2  [emitted]         ChannelsShow
                         UsersIndex.bundle.54f65aa8.js    4.39 kB       3  [emitted]         UsersIndex
                                    bundle.54f65aa8.js    31.2 kB       4  [emitted]         bundle
                                    vendor.54f65aa8.js    1.46 MB       5  [emitted]  [big]  vendor
                  1f42da94f3ff91d479713521dee90778.css     1.5 kB       4  [emitted]         bundle
                                            index.html  326 bytes          [emitted]
import Loadable from 'react-loadable';

export const BotsShow = Loadable({
  loader : () => import(/* webpackChunkName: 'BotsShow' */ '../containers/pages/Bots/Show'),
  loading: () => (<div>Loading...</div>)
});

const Router = () => (
  <App>
    <Switch>
      <Route
        path="/bots/:id"
        component={() => (<BotsShow />)}
      />
    </Switch>
  </App>
);

フロントエンド用のライブラリはvendor.jsへすべてまとめ、ルーティングごとにファイルを切ります。

react-universal-componentとどちらを使うか迷いましたが、react-loadableにしました。

github.com

history

github.com

今回は、browserHistoryではなく一旦hashHistoryにしています。
理由としては、watch時にhtml-webpack-pluginとexpressがルーティング周りで競合するため開発効率が落ちるからです。
普段、SSRの時にhtml-webpack-pluginを使っていなかったため気付かずハマってしまってました。。

SSR

今回は、とくにやる必要がないのでしません。
SSRをやるメリットとしては、SEO対策とFirst Viewに関する速度がありますが2つとも今回は必要の無いことだからです。

そのかわりに表示パフォーマンスの面では、dynamic importとService Workerで補います。

PWAのためのライブラリであるWorkboxを使い、今回はService Workerを扱います。

github.com

今はhtml-webpack-pluginでhtmlファイルを吐き出してますが、今後SSR同様にinlineへと変えたいと思います。

感想

意外と大規模なものを作っていて時間がありませんでした。
特にSlackのデバッグが本当に大変なのとSlack Appというのがなんなのかみたいな部分から知らないといけなくて少しSlackに詳しくなった気がする。

まだまだやることが多いのでもう少しこの開発に楽しもうと思っています。


簡単に導入できるので是非使ってみてください!!

ドワンゴに入社しました

abouthiroppy.hatenablog.jp

12/16(18開始)から新卒で入社したドワンゴへもう一度入社することになりました。

今現在、このような状況ですがニコニコ動画ドワンゴのサービスが好きな1ユーザーとして、また1開発者として微力ながらドワンゴの力になれるように頑張りたいと思います。

今後共、よろしくお願いします。