2021年7月2日金曜日

denoでPWAを使ってGUIアプリを作成する

PWAはhttp://localhost/からも作成できることが確認できましたので、昨日のサンプルよりも、より実用的なサンプルを作成しました。



ソース


<html>
<meta charset="utf-8">
<title>PWA</title>
<script src="外部.js"></script>
<body>あいうえお</body>
</html>
view raw index.html hosted with ❤ by GitHub
import { listenAndServe } from "https://deno.land/std/http/server.ts";
const server = listenAndServe({port:8080}, httpリクエスト処理)
async function httpリクエスト処理(リクエスト:any){
console.log(リクエスト.url)
let url = リクエスト.url
if(url == '/'){ url = '/index.html' }
// そのままだと「/index.html」のように「/」から始まる文字列な場合があるので先頭に「.」をつけて相対Pathとして使える形式にする。
url = url.replace(/^\//,'./')
// 「外部.js」が「%E5%A4%96%E9%83%A8.js」となるのをブラウザ側で避けられないので、サーバ側でデコードする。
url = decodeURI(url)
const ファイルの有無 = await fileExists(url)
if(!ファイルの有無){
console.log(リクエスト.url + ' > not found')
return リクエスト.respond({ status: 404 })
}
const file = await Deno.open(url) // ← ここが「/index.html」だとエラーになる。「./index.html」ならok
リクエスト.respond({
status : 200,
headers : new Headers({'content-type' : 拡張子2contentType(url)}),
body : file
})
}
async function fileExists(filePath: string): Promise<boolean> {
try {
await Deno.lstat(filePath);
return true;
} catch (err) {
if (err instanceof Deno.errors.NotFound) {
return false;
}
throw err;
}
}
function 拡張子2contentType(url: string):string{
const m = url.toLowerCase().match(/\.([^.]+)$/)
switch(m![1]){
case 'htm' :
case 'html': return 'text/html'
case 'css' : return 'text/css'
case 'js' : return 'text/javascript'
default : return ''
}
}
view raw pwa.ts hosted with ❤ by GitHub
// キャッシュ名とキャッシュファイルの指定
var CACHE_NAME = 'pwa-sample-caches';
var urlsToCache = [
'/', '/外部.js'
];
// インストール処理
self.addEventListener('install', function(event) {
event.waitUntil(
caches
.open(CACHE_NAME)
.then(function(cache) {
return cache.addAll(urlsToCache);
})
);
});
// リソースフェッチ時のキャッシュロード処理
self.addEventListener('fetch', function(event) {
event.respondWith(
caches
.match(event.request)
.then(function(response) {
return response ? response : fetch(event.request);
})
);
});
view raw sw.js hosted with ❤ by GitHub
onload = ()=>{
document.body.innerText = 'ok!'
}
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('sw.js').then(function(registration) {
console.log('登録成功 scope: ', registration.scope);
}).catch(function(err) {
console.log('登録失敗 ', err);
});
}
view raw 外部.js hosted with ❤ by GitHub



起動





edgeで「localhost:8080」を開きます。






サーバ停止後


コマンドラインの画面で「Ctrl + C」を入力してサーバを停止します。



この状態ではブラウザがhttpリクエストを送っても対応する相手が居ないので、edgeの更新ボタンを押すと



通常は以下のような表示になりますが



ServiceWorkerを使うとキャッシュが読み込まれるため、以下のようになります。



キャッシュを無視して強制的に更新したい場合


ServiceWorkerを使うとサーバが応答できない場合でもキャッシュから起動できる、というメリットがある反面、サーバ側に新しいファイルが用意してあるのにキャッシュが優先されてしまい最新の表示状態が確認できなくて困る、という場合もあります。
強制的に更新をかけたい場合は以下の操作で、できます。
  • ショートカットキーを使う場合: Ctrl + Shift + R
  • GUI操作で行う場合:F12を押して開発者ツールの画面を開いた状態で、更新ボタンを長押しして「ハード リフレッシュ」をクリック



ServiceWorkerを解除したい場合


ServiceWorkerを使っているとソースファイルを更新したりするタイミングで新旧が混在してしまう場合があります。



複数のServiceWorkerが混在している状態では、どの時点のキャッシュが有効になっているのか怪しくなってしまいますので、そのような時は一旦ServiceWorkerの登録を解除するのが良いです。
まず、「アプリケーション」タブを開きます。



アプリケーションカテゴリ内の「Service Workers」を開くと、localhost:8080に紐づけられているService Workerの一覧が表示されます。
その一覧の中にある「登録解除」というリンクをクリックします。



全てのService Workerの登録を解除すると以下のようになります。

お世話になったサイト





欲を言えば


PWAは権限がかなり強いので、使い方を誤るとセキュリティリスクは大きそうです。
だから、仕方がないことだとは思いますが、現状では「Webブラウザで対象ページを開いて、PWAとしてインストールする」という操作がどうしても必要なようです。
その操作をコマンドラインとかPowerShellなどで自動化できるば、もう最高なのですが…。
MicrosoftStoreにアプリとして公開すれば、手段はあるのかもしれませんが、公開したくないアプリの方が多いので…。

0 件のコメント:

コメントを投稿