「俺はあのジョブズのプレゼンを見て、俺もジョブズになるんだと決心したんだわ」
「…でも最近俺はジョブズじゃないって気づいたんだわ…」
先日リリースした個人アプリBlogFeedbackを開発した動機と、開発の時系列、開発してみての感想(ネイティブ開発者から見たPWAとか)を書いていきます。リリースエントリにも書きましたが、このアプリはiOSネイティブアプリからWebアプリへの移植です。
この記事はPWA Advent Calendar 21日目の記事です。
create-react-appのService Workerサポートを使ってお手軽にオフラインキャッシュを組み込んでみたので、調べたことをメモします。とりあえずすぐにオフラインでPWAが動かせるようになって便利です。
create-react-app
でアプリを生成していればindex.js|ts
で
import { register } from './serviceWorker'; register();
するだけ。
以下はcreate-react-appというよりはworkboxの挙動だと思われる
temp領域に入っているアセットはApplicationタブから確認できます。
使いだすと、たぶん以下を熟読することになると思います。
こちらも参考になりました。 qiita.com
この記事はFirebase Adventcalendar #2の13日目の記事です(もう12/17ですが、丁度書けそうなネタがあったので、空いてる日を見つけて埋めることにしました)。
Firabase Cloud Firestoreを使う場合、Security Rulesがアクセス制御全てのかなめと言えます。ここをミスるとデータが漏れて終わる、しかしその割に簡単に変更できてしまう。というわけで自動テストできると安心でしょう。
今回は先日公開した拙作のBlogFeedback(repo https://github.com/ninjinkun/blog-feedback-app/ )で用いているCircleCIによる自動テスト事例を紹介します。
なお、Security Rulesをテストするというアイデアは以下のエントリから頂きました。
Cloud Firestoreのエミュレーターとテスト用のライブラリが提供されているので、これを利用することでテストを記述・実行できます。エミュレーターの利用はこちらの記事を参考にしました。
firebase-toolsが入っていれば以下でインストールして
firebase setup:emulators:firestore
以下で立ち上げられます。
firebase serve --only firestore
公式のサンプルを参考にfirestore.rulesをテストしていきます。
サンプルではテストはmochaで記述されていますが、今回はcreate-react-appに同梱のJestで記述しました。
アプリ内で使っているRepositoryの関数を呼んで書き込みのテストをしているのと、他人のデータや本来書き込めない領域への書き込みが失敗するテストも記述しました。
src/tests/firebase-rulest.test.tsより一部抜粋
describe('/users/:user_id/blogs', () => { it('save blog', async () => { const db = authedApp({ uid: 'ninjinkun' }); // repositoryが内部で使っているdbを差し替える firebaseDB.mockReturnValue(db); await firebase.assertSucceeds( // repositoryに定義した関数で書き込めるか saveBlog( 'ninjinkun', 'https://ninjinkun.hatenablog.com/', "ninjinkun's diary", 'https://ninjinkun.hatenablog.com/feed', 'atom' ) ); }); it('save undefined blog field', async () => { const db = authedApp({ uid: 'ninjinkun' }); firebaseDB.mockReturnValue(db); const user = userRef('ninjinkun'); // 存在しないフィールドに値をセット // rulesでちゃんとフィールドを制御しないと書き込めてしまうので注意 await firebase.assertFails(user.set({ hoge: 'fuga' })); }); });
ローカルでテストが成功するようになったら、CircleCIの設定へ進みます。
CircleCIで実行する際のポイントとしては、エミュレータの実行にJavaが必要なため、OpenJDKとNode.js両方が入ったDocker Imageを選ぶことです。今回はとりあえず適当にcircleci/openjdk:11-jdk-sid-node
を選択しました。
余談ですがCloud FunctionsのビルドにはNode.js v6 or v8が必要なため、デプロイ用のjobの方では circleci/node:8.14
を指定してあります。Cloud Functionsのテストも同時に行う場合は、OpenJDK + Node.js v8の組み合わせが入っているDocker Imageを用意する必要があるでしょう。
テストの実行前にエミュレーターのインストールと実行を追記する必要があります。
.circleci/config.ymlから一部抜粋(インストールしたエミュレーターをキャッシュできるとは思うのですが、そんなに時間がかかっているわけでもないのでさぼっています)
- run: yarn firebase setup:emulators:firestore - run: command: yarn firebase serve --only firestore background: true
CIを実行すると以下の様にローカルと同じようにテストが実行されました。これで一安心。
CI実行結果から抜粋
#!/bin/bash -eo pipefail yarn test:ci yarn run v1.12.3 $ CI=true react-scripts test --env=jsdom PASS src/__tests__/save-count-response.test.ts PASS src/__tests__/firebase-rules.test.ts PASS src/__tests__/App.test.tsx Test Suites: 3 passed, 3 total Tests: 10 passed, 10 total Snapshots: 0 total Time: 3.208s Ran all test suites. Done in 4.68s.
テストケース10個で以下の通りでした。エミュレーターの起動に18秒かかっているので、ここが一番遅いですね。とりあえず許容範囲内としていますが、他のテストでも時間がかかっているとストレスになるかもしれません。
firebase-tools > 6.1.1 ではCircleCIでのエミュレータ起動が失敗するので、.jar
の直接起動が必要になりました。そのうち解消されるとは思いますが
具体的な作業は以下に。
Upgrade firebase tools by ninjinkun · Pull Request #54 · ninjinkun/blog-feedback-app · GitHub
firebase-toolsの最新版でfirestore emulatorがIPv6のアドレス吐かなくなってたのでCircleCIで素直に実行できるようになっていた。FIRESTORE_EMULATOR_HOSTでhostも指定できるようになったらしい https://t.co/9qgSUOOZpC
— にんじんくん (@ninjinkun) 2019年6月14日
ブログについたFacebookいいねやはてなブックマーク数などのシェア数を集計して表示してくれるWebアプリです。ブログを書いた後にシェア数が気になってしまう人におすすめです。
詳しくは以下のデモ動画をご覧ください。
デモ動画
数年前にiOSアプリとして同じ機能を持ったネイティブアプリをリリースしていました。今回はこれをWebブラウザ上で動作するPWA (Progressive Web Application) として再実装したサービスになります。
かつてのiOS版
以前のiOSアプリは100円の有料アプリでしたが、今回のWeb版は無料です。
GitHubでコードを公開しています。MITライセンスなので、コードを何かに利用していただいても構いません。
Issue、PullRequest歓迎です。不具合や要望などあればお寄せください。一応github作法として英語っぽく書いてはいますが、日本語で大丈夫です。
PWAってやつを試してみたくなってな。
ランニングと水泳を毎週一回ずつはやるようにしている。
以前は仕事が忙しくなると運動を止めてしまいがちだったのだが、こうなると
忙しくなる→運動習慣なくなる→ストレス増大、体調不良→余計忙しくなる
という負のループに陥るので、最近は疲れていても運動がゼロにならないように気をつかっている。
「VRはもう確定でしょ、まだやったことない人居るの?まじか〜」「京都は5年遅れてるから。あdisっちゃった(笑)」「シンギュラリティが…」
異なる高校の生徒を集めた合宿中に、謎の怪生命体が発生して、生徒が襲われる。生命体は怪獣のようなロボットのような質感で、最初は人間ほどの大きさだが最終的にはビルくらいになる。様々な形になることができ、手足や触手をナイフやハンマーの形にして人を襲う。
我々はビルや橋を乗り越えて、本州からの脱出を目指す。
しかし合宿のチームメイト(さっき会ったばかりの男1女2)が死んでしまい、自分だけが残される。そこでループが発生して、時間が怪獣発生前に戻る。2ループ目からは怪獣を避けるように行動するが、もちろんまたみんな死んでしまう。
ループが発生する度にNetflixロゴが出る。
毎回チームメイトの天才少女と元気少女の掛け合いがあったような気がするが、内容はうろ覚え、もう一人の男子は何か居たような…というくらいの印象。
何回かループした後に、うまいことループの外側のメタ世界に移動することができ、脱出できた。
なぜか最後は実家に戻っていて、大学受験のためにZ会か予備校に行かせてくれと頼んで終わる。春から高三だしこのままじゃ浪人だ!と必死な気持ちで目が覚めた。