背景
ネイティブアプリのご要望が増えるとともにwebアプリとの違いを気にされるお客様も多かったため、 勉強の意味も兼ねてPWA(Progressive Web Apps)の実装を行いました。 PWA自体はwebアプリをネイティブアプリっぽく見せる技術ですが、 webサービスをまだ持っていなかったため今回は自社アプリをPWA化してみました。 (会社ページをスマホのホーム画面に登録するのはおそらく経営陣ぐらいなので全く実用性はないです…笑)
自社アプリはAWS S3 Hostingを使っているので、S3 Hostingでの実装方法という形でお伝えします。 ウェブフレームワークを使用せず静的サイトを提供している場合は同様の方法で導入できるかと思います。
PWAの効果
PWAの特徴を挙げると以下のような特徴があります。
- ホーム画面に追加するとsafariを経由せずアプリのようにサイトを開くことができる
- safariのようなURLヘッダーやフッターが存在せず画面全体を利用することができる
- キャッシュを本体側に残せるためロードが早くなる
弊社のサイトで言うとuikitやvuejsを導入している影響でサイトが遅かったので、 PWA化による影響が一番感じられたのは読み込みスピードでした。
実装方法
基本的には こちらのページ を参考に作成させていただきました。 具体的に追加・変更したファイルは以下ディレクトリ構成において「<=」をつけている4ファイルです。
frontend
├── img
│ └── ...
├── index.html <=
├── js
│ ├── app.js <=
│ ├── sw.js <=
│ └── ...
├── manifest.json <=
└── ...
index.html
元々ホーム画面追加時のアイコンなどは設定していたので、 headerに以下2行を追加するだけで適応することができました。
<link rel="manifest" href="/manifest.json">
<script src="/js/app.js"></script>
app.js
参考ページに載っていたものからパスを修正して作成しました。
<em>if</em>('serviceWorker' in navigator){
navigator.serviceWorker.register('/js/sw.js')
.then(reg => console.log('service worker registered'))
.catch(err => console.log('service worker not registered', err));
}
ちなみに最初ここのパスを間違えてしまい、 エラー文も以下のようなわかりづらいものが出るためしばらくハマっていました。 エラー文の解釈としてはおそらく存在しないパスを参照してerror.htmlが返されたことにより出ていたのだと思われます。
Uncaught (in promise) DOMException: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/html').
sw.js
こちらは参考ページに載っていたものにキャッシュするファイルを追加して作成しました。 cdnで読み込んでいるものもキャッシュできるのでとても便利です。
const staticCacheName = 'site-static-v1';
const assets = [
'/',
'/index.html',
'/js/settings.js',
'/js/particles.min.js',
'/img/small/home-bg.jpg',
'/img/medium/home-bg.jpg',
'/img/large/home-bg.jpg',
'/img/logo/meiko.jpg',
'/img/service/db_consultant.jpg',
'/img/service/it_consultant.jpg',
'/img/service/taskcross.png',
'/img/service/tsumiki.png',
'/img/sinkcapital_logo.png',
'/img/supportCase/aws.jpg',
'/img/supportCase/education.jpg',
'/img/supportCase/ga.jpg',
'/img/supportCase/gcp.jpg',
'https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/uikit/3.2.3/css/uikit.min.css',
'https://cdnjs.cloudflare.com/ajax/libs/uikit/3.2.3/js/uikit.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/uikit/3.2.3/js/uikit-icons.min.js',
'https://code.jquery.com/jquery-2.2.3.min.js',
'https://fonts.googleapis.com/css?family=Lato:400,700|Noto+Sans+JP:400,700',
];
// install event
self.addEventListener('install', evt => {
evt.waitUntil(
caches.open(staticCacheName).then((cache) => {
console.log('caching shell assets');
cache.addAll(assets);
})
);
});
// activate event
self.addEventListener('activate', evt => {
evt.waitUntil(
caches.keys().then(keys => {
return Promise.all(keys
.filter(key => key !== staticCacheName)
.map(key => caches.delete(key))
);
})
);
});
// fetch event
self.addEventListener('fetch', evt => {
evt.respondWith(
caches.match(evt.request).then(cacheRes => {
return cacheRes || fetch(evt.request);
})
);
});
manifest.json
こちらは参考ページに載っていたコードからアイコンの部分だけ修正して作成しました。
{
"name": "Sink Capital",
"lang": "ja",
"short_name": "SinkCapital",
"start_url": "/index.html",
"display": "standalone",
"background_color": "#F4F4F4",
"theme_color": "#F4F4F4",
"orientation": "portrait-primary",
"icons": [
{
"src": "/img/apple-touch-icon.png",
"type": "image/png",
"sizes": "180x180"
}
]
}
感想
PWAの対応は様々な記事が出ておりほぼコピペで対応できたのでとても楽でした。 自社サイトをPWA化したメリットはほぼ何もないですが、 PWA化によるサイト読み込みスピードの変化は実感することができました。 主にvuejsやuikitのcdnを読み込むスピードが爆速化していました。 アプリとの対比でいうとアプリっぽいUIを作れるのであれば、 PWAでも全然問題なく対応できそうでした。 もし機会があれば次はアプリっぽい見た目のPWAサイトを作成してみようと思います。