Django PWA化に関するメモ

DjangoをPWA化するために調べたことの備忘録。


PWAとは?

PWA(Progressive Web Apps)はWebアプリケーションをネイティブアプリのようなものにするための仕組みです。

WebアプリケーションをPWA化させることで、オフラインでも動作可能になったり(データの更新を行わない場合)、プッシュ通知(android)を使えるようになったりと、色々なメリットがあります。

スマホユーザーが増えている現状ではこれに対応しておくのが無難だと思われます。


導入するために必要な物

WebアプリケーションをPWAにするためにはいくつか準備することがあります。

・HTTPS

HTTPS通信を使用している場合のみPWA化することができます。

・サービスワーカー

キャッシュファイルの設定と、インストール処理とキャッシュロード処理を設定します。ここで設定したものがオフラインでも動作するようになります。

・マニフェストファイル

アプリをどのようにユーザーに表示させるかの設定ファイル。


Djangoでの導入例

色々と調べてもそんなに情報は出てきませんね。

というより、一般的な導入の仕方から推測すれば、大体実装もできてしまうのかと思います。中上級者は問題ないですが、初学者は大変。

とはいえ、できるようになっておいた方がいいので、自分も勉強しておきます。

PWAの導入

1. HTTPS化

HTTPSへはLet’s Encryptで対応させているので問題ないです。また開発環境ではHTTPでPWAの動作確認ができるみたいなので、ここはOK。


2. Service Workerへの登録

ネイティブアプリでやっていたようなことができるようになる仕組み。必要なファイルをキャッシュさせて読み込めるようにできる。

if ('serviceWorker' in navigator) {
 window.addEventListener('load', function() {
   navigator.serviceWorker.register('/sw.js').then(function(registration) {
     // Registration was successful
     console.log('ServiceWorker registration successful with scope: ', registration.scope);
   }, function(err) {
     // registration failed :(
     console.log('ServiceWorker registration failed: ', err);
   });
 });
}

これをテンプレートにいれればいいようだ。

sw.jsというのがサービスワーカー用のjavascriptでここで処理を決める感じ。ということでこれを共通テンプレートに追加。


<script>
   if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
  navigator.serviceWorker.register('{% static 'sw.js' %}').then(function(registration) {
    // Registration was successful
    console.log('ServiceWorker registration successful with scope: ', registration.scope);
  }, function(err) {
    // registration failed :(
    console.log('ServiceWorker registration failed: ', err);
  });
});
}
</script>

あとはsw.jsの中身。

// Cache name
const CACHE_NAME = 'pwa-k-editor-caches-v1';
// Cache targets
const urlsToCache = [
   'top.css',
   'base.css',
   'logo.png',
   'editor/editor.js'
];
self.addEventListener('install', (event) => {
 event.waitUntil(
   caches
     .open(CACHE_NAME)
     .then((cache) => {
       return cache.addAll(urlsToCache);
     })
 );
});
self.addEventListener('fetch', (event) => {
 event.respondWith(
   caches
     .match(event.request)
     .then((response) => {
       return response ? response : fetch(event.request);
     })
 );
});

installでキャッシュしたいファイルを保存。

fetchでキャッシュしたファイルがあればそれを読み込む感じ。


3. マニフェストファイルの作成と読み込み。

いくつか設定項目があるので埋めていく。上のリンクを参考にしてみた。

{
 "name": "k-editor",
 "short_name": "k-editor",
 "start_url": "../",
 "display": "standalone",
 "background_color": "#fff",
 "theme_color": "#FFDF97",
 "description": "k-editor is an editor for Katsudo Hokoku in syousetuka ni narou.",
 "icons": [
   {
     "src": "Logo192.png",
     "sizes": "192x192",
     "type": "image/png"
   },
   {
     "src": "Logo512.png",
     "sizes": "512x512",
     "type": "image/png"
   }
 ]
}

srcはマニフェストのファイルと同じ場所が基準となる。今回はLogoを同じ場所に置いた。

キャプチャ

なお、サイズは"48x48"、 "72x72"、"96x96"、"144x144"、"168x168"とかあるみたいで、いくつも用意したほうがいいのかもしれない。

最低限192だけでもいいのかもしれない。Qiitaだと48, 96, 192, 512使ってる。

この辺りは後でかえてもいいかも。あとはテンプレートにこれを読み込ませる。

<link rel="manifest" href="{% static 'manifest.json' %}">


4. 動作確認

キャプチャ3

ボタンがついてますね。

サービスワーカーも見てみましょう。開発ツールのApplicationを見てみると、ちゃんと設定できていそうですね。(displayは後でbrowserに変えました)

キャプチャ5

キャッシュもされているようです。


キャプチャ4

思っていたより簡単にできてしまいました。

静的ファイルでJavascriptで動くようなサービスだと、全部キャッシュさせればオフラインでも動くアプリの出来上がりですね。

なるほどなるほど。ということで最低限のPWA化ができました。

キャッシュの設定やら色々と最適化できそうな部分もありそうなのでまた改めて設定したいと思います。

とりあえず目標達成したので今回はこれで終わり。

小説投稿サイトの導入例

小説投稿サイトではどこが導入しているのか気になったので、ちょっと眺めてみました。

色々な小説投稿サイトを見て回りましたが、PWAに対応していたのはプリ小説と檸檬(閉鎖済み)くらいでした。

技術的に難しいのか、単に存在を知らないだけなのかはわかりませんけど、導入率はそんなに良くないみたいです。

アプリを作っていないところとかは導入してもいいかもと思ったり。

そこまで技術的に難しくはないようですけど、あまり新しい技術には興味がないところが多いのかもしれませんね。


追記:サービスワーカのスコープ

色々と調べてみて、ちょっと間違っている部分もあったので追記。

sw.jsの置く場所によって対応を変える必要があります。

サービスワーカーのファイルを置いた場所が基本となり、そこより上位は範囲外になります。

なので、sw.jsを置く場所は、ルートにする必要があります。

なので、project/urls.pyにsw.jsへのパスを作ってサービスワーカーファイルを返すようにして、

  navigator.serviceWorker.register("{% url 'sw.js' %}").then(function(registration) {

resisterにsw.jsへのパスを書けばいい感じ。


好きな場所において、スコープを拡大する方法もあって、Service-Worker-AllowedをHTTPSヘッダに書く必要があるみたい。

まぁ、ルートに配置するほうが楽かな。

良ければサポートお願いします。サポート費用はサーバー維持などの開発費に使わせていただきます。