コンテンツへ移動

Workboxを使ってPWAのキャッシュを作成する

Googleが提供するWorkboxはService Workerを使う上で必須とも言える機能を提供してくれます。特にキャッシュ周りの面倒な操作を手軽に行ってくれるのが利点です。

今回はそんなWorkboxでキャッシュを作成する方法を紹介します。

インストール

Workboxのインストールはローカルにファイルを設置することもできますが、importScriptsでリモートファイルを指定するのが最も簡単です。

これで workbox というグローバル変数が定義されます。

パターンで登録する

一般的にキャッシュを作成する場合、URL単位で指定します。しかしWorkboxの場合は正規表現パターンで指定できます。

このように定義することで、 *.js のリクエストに対してはキャッシュファーストで返してくれるようになります。他にも workbox.strategies.networkFirst()workbox.strategies.staleWhileRevalidate() も用意されています。


キャッシュを正規表現で指定することで、多数のファイルをまとめてキャッシュ化できます。特定ファイルはキャッシュしないというポリシーであっても、正規表現で指定すれば問題ありません。WorkboxはService Worker利用時には欠かせないツールと言えます。ぜひ使いこなしてください!

Workbox  |  Google Developers

PWAでキャッシュされているファイルを確認する

PWAではService WorkerのCACHE APIを使ってファイルをキャッシュできます。それを使えばオフライン時にもリソース(画像やJavaScriptファイルなど)を返せるので、ネットワークに繋がっていなくともWebアプリケーションが使い続けられます。

PWAを開発している際に、ファイルがキャッシュされているか、さらにキャッシュされてしまったファイルを簡単に削除する方法を紹介します。

キャッシュファイルの確認

Google Chromeを使っている場合、開発者ツールのApplicationタブにあるCache Storageからキャッシュされているコンテンツであったり、キャッシュされている内容の確認もできます。

これを使えば正しくキャッシュされているかどうか、すぐに確認できます。

キャッシュの削除

キャッシュの一覧を右クリックすると、リフレッシュと削除が表示されます。プログラムでキャッシュを更新することもできますが、開発中であれば開発者ツールから行うのが簡単です。


CACHE APIは非常に強力で、キャッシュの更新や削除をしないと恒久的に残り続けてしまいます。開発中、最初から更新や削除の仕組みがある訳ではないと思いますので、開発者ツールを使う方法を覚えておくと便利です。

GoではじめるWebAssebmly その5「ウィンドウオブジェクト、localStorageを使う」

WebAssebmlyはWebブラウザ上でバイナリファイル(テキスト形式もあり)を実行できる環境です。JavaScriptと異なりコードの漏洩がなく、実行速度も高速というのがメリットです。

WebAssebmlyは元々Rustで開発することが多かったですが、最近では様々なプログラミング言語が対応しています。その一つがGoです。Go 1.11からWebAssembly向けにもコンパイルできるようになっています。

一般的なWebAssemblyはDOMやネットワーク操作が行えません。それに対してGo 1.11ではJavaScript APIを使えるようにした syscall/js パッケージを用いることで、DOMやネットワーク操作を可能にしています。

そこで今回はさらに面白い、ウィンドウオブジェクトやlocalStorageをWebAssemblyから使ってみます。

オンライン、オフラインを検知する

Webアプリケーションのネットワーク状態を受け取るには window オブジェクトの online または offline イベントを使います。これももちろんGoのWebAssemblyの中に記述できます。

そしてオンライン、オフラインの値は navigator.onLine で取れますので、この値も使います。

 

これでWebAssembly側でもオンライン、オフラインの判定ができるようになります。

localStorageを使う

さらにWebブラウザとWebAssemblyでデータの送受信をする際に使ってみたいのがlocalStorageを経由したデータ授受です。

 

 

このようなコードで localStorage に触って、データをセットしたり、値の取得を行えます。localStorageの場合、setItemやgetItemではなくSet/Getで値の授受ができるのが特徴です。 localStorage.Call("setItem", "Hello", "World") ではうまくいきませんが、 localStorage.Get("getItem", "JavaScript") は利用できます。


syscall/js は非常によくできており、同時に利用する wasm_exec.js と組み合わせることでWebAssemblyからDOMやJavaScriptのAPIを透過的に扱えます。ちょっとした使い方さえ覚えてしまえばJavaScriptと変わらず使えるようになりそうです。

オンライン、オフライン判定などWebAssemnly単体では難しいことも容易に実現できます。ぜひGoでWebAssemblyを使ってみてください。

GoではじめるWebAssebmly その4「POST系ネットワーク処理」

WebAssebmlyはWebブラウザ上でバイナリファイル(テキスト形式もあり)を実行できる環境です。JavaScriptと異なりコードの漏洩がなく、実行速度も高速というのがメリットです。

WebAssebmlyは元々Rustで開発することが多かったですが、最近では様々なプログラミング言語が対応しています。その一つがGoです。Go 1.11からWebAssembly向けにもコンパイルできるようになっています。

一般的なWebAssemblyはDOMやネットワーク操作が行えません。それに対してGo 1.11ではJavaScript APIを使えるようにした syscall/js パッケージを用いることで、DOMやネットワーク操作を可能にしています。

そこで今回はネットワーク処理(POST処理)の書き方を解説します。

使いどころ

POSTやPUT、DELETEはREST APIを扱うのに使われるでしょう。今回はPOSTリクエストでJSONを送信する方法を解説します。

ボタンを押したタイミングで処理

例えば今回はボタンを押したタイミングで入力されている内容をJSON化して送信します。そこでボタンのクリックイベントを設定します。

goroutineに注意

ネットワーク処理は非同期なのでデータを安全に送受信するためにgoroutineが使われています。そして単純にPOST処理を書くと、WebAssebmly全体で設定しているgoroutineが終了してデッドロックが発生してしまいました。

そこで処理全体を無名関数化して、それをgoで実行(goroutine化)します。

via runtime: wasm: all goroutines asleep and no JavaScript callback pending – deadlock · Issue #26382 · golang/go

この問題は 1.12 で直る予定です。

CORSに注意

Goでhttp.Postを使っていますが、実際にはWebブラウザのメインスレッド側でリクエスト処理が行われます。CORSは通常のJavaScriptと変わらず行われます。また、ネットワーク接続内容などは開発者ツールで見られますので、隠蔽できる訳ではありません。


Goを使ったWebAssemblyは他の言語では見られないDOM操作とネットワークアクセスが可能です。これは大きなメリットと言えるでしょう。ぜひこの特徴を活用し、高速で安全なWebアプリケーションを開発してください。

GoではじめるWebAssebmly その3「GET系ネットワーク処理」

WebAssebmlyはWebブラウザ上でバイナリファイル(テキスト形式もあり)を実行できる環境です。JavaScriptと異なりコードの漏洩がなく、実行速度も高速というのがメリットです。

WebAssebmlyは元々Rustで開発することが多かったですが、最近では様々なプログラミング言語が対応しています。その一つがGoです。Go 1.11からWebAssembly向けにもコンパイルできるようになっています。

一般的なWebAssemblyはDOMやネットワーク操作が行えません。それに対してGo 1.11ではJavaScript APIを使えるようにした syscall/js パッケージを用いることで、DOMやネットワーク操作を可能にしています。

そこで今回はネットワーク処理(GET処理)の書き方を解説します。

使いどころ

GET処理の使いどころはもちろん、Web APIからのデータ取得になるはずです。今回は文字列が配列で返ってくるケースを紹介します。

JSONを利用するためには構造体を定義する必要あり

Goの若干面倒な部分として、JSONを利用するためには構造体を定義する必要があるという点があげられます。例えば以下のような形です。

ネットワークは net/http で行う

Goでネットワーク処理を記述する場合には net/http ライブラリを使います。

処理について

例えばあるドメイン domain からJSON文字列を取得するデモコードです。

後はこの関数を実行します。


これでJSONの取得とパースが完了します。なお、見ての通り、このコードはネットワーク部分を同期的に処理しています。関数の頭に go をつけることで非同期処理になりますが、描画部分を考えると同期(または描画を含めて非同期)処理にしなければなりません。

また、このネットワーク接続はWebAssemblyの中で行われているのではなく、メインスレッド側で行われます。そのため開発者ツールなどでリクエスト内容は確認できます。ネットワーク接続を秘匿にするのは困難なので、注意してください。

hifive と Onsen UIを組み合わせてスマートフォン/タブレット向けのUIを簡単に実現する(タブ & ナビゲーション)

Onsen UIというモバイルアプリ向けのUIフレームワークがあります。HTML5とJavaScript、CSSを使ってスマートフォンアプリを作るハイブリッドアプリ用のUIフレームワークになります。UIをネイティブアプリ風にしてくれるのはもちろん、画面のスワイプであったり、リスト表示などをネイティブアプリ風の操作にしてくれます。

そんなOnsen UIをhifiveと組み合わせて使う方法を紹介します。今回はタブバーとナビゲーションを組み合わせた使い方を紹介します。

利用するソフトウェア/ライブラリ

  • Bower
  • hifive
  • Onsen UI
  • jQuery

インストール

まず各ライブラリをインストールします。インストールはBowerを使って行います。

今回は .bowerrc という設定ファイルを作成し、ライブラリのインストール先を指定しています。

index.htmlの作成

次に public/index.html を作成します。タブバーを定義します。

タブバーの画面

まず最初に表示される tab1.html の画面を用意します。タブ1の中身でナビゲーションを行いますので、ここではナビゲーションだけを定義します。

そして最初に表示するのは tab1-main.html です。

JavaScriptの実装

まずメイン画面でボタンを押したら詳細画面に移動する部分を作ります。 tab1MainController を定義します。そしてナビゲーションのpushPageを使って画面遷移します。

ここでヘッダー部の文字を詳細に変えるようにイベントを設定します。コントローラのトリガーを使います。

トリガーは js/app.js 内に定義する全体のコントローラに実装します。 {rootElement} changeTitle でイベントを受け取ることができます。

なお、 Tab1Controller と Tab2Controller は別な画面に定義されています。そのため、変数が定義されているかどうかを確認する必要があります。今回は以下のような仕組みで回避しています。変数があるかどうか調べて、なければ100ms待って変数の確認をしています。

画面遷移を戻る

詳細画面に移動したら、逆に戻ってくる処理を作ります。これは tab1-detail.html に実装します。こちらでもトリガーを使っています。

ここまでの処理でタブバーとナビゲーションバーを組み合わせた処理が実現します。


タブバーとナビゲーションバーを組み合わせた動きはスマートフォンアプリでよくある実装だと思います。hifiveのコントローラ連携を使うことで、機能を画面毎に分けつつ、分かりやすい実装が実現します。

コードはhifiveWithOnsenUI/tabbar_navigation at master · hifivemania/hifiveWithOnsenUIにアップロードされています。実装時の参考にしてください。

13.コントローラの連携 – hifive

jQueryの代わりにdocument.querySelectorを使う

jQueryはIDやクラスを指定してDOMエレメントが取得できるので便利に使っている人は多いかと思います。しかし、DOMの取得だけであれば素のJavaScriptでも簡単にできます。それがdocument.querySelectorです。

他にもIDを指定する document.getElementById 、クラスを指定する document.getElementsByClassName 、タグ名を指定する document.getElementsByTagName など何種類もあるのが分かりづらさを感じさせる原因ですが、document.querySelector と document.querySelectorAll はすべてを兼ね備えます。

ということで今回は document.querySelector / document.querySelectorAll の使い方を紹介します。

document.querySelector と document.querySelectorAll の違い

二つのメソッドの違いは返ってくるのが複数かどうかです。 document.querySelector は最初の一つしか返ってきません。クラスやリストを指定しても最初の一つだけです。それに対して document.querySelectorAll は一致するDOMすべてが返ってきます。

document.querySelectorの使い方

document.querySelector は引数にCSSセレクタを指定します。これはjQueryで使ってきたものをそのまま使えます。

返ってくるのはDOMです。

ない時には nullが返ってくる

注意点としては該当するDOMがなかった場合には null が返ってくるので、メソッドチェーンが使えません。それに対してjQueryの場合はメソッドチェーンが可能です。

これをいちいち判定しながら作るのはちょっと面倒でしょう。

簡単な関数でラップする

そこで document.querySelector を直接使わず、簡単な関数でラップしてあげます。

これはごくごく簡単な例ですが、存在しないCSSセレクタを指定してもある程度のメソッドチェーンが書けるようになります。


document.querySelectorやdocument.querySelectorAll、そしてそれがエラーを起こさないためのやり方さえ覚えてしまえばjQueryを使うことなくDOM操作を行えるようになります。jQueryは他にもたくさんの機能があって便利ですがAngularやReact、Vueとの相性が良くなかったり、使っていない機能の方が多くなりがちです。jQueryで使っているのがDOM操作ばかりだ…という方はdocument.querySelectorに乗り換えても良いでしょう。