Nuxt.js #2 Advent Calendar 2018の4日目の投稿となります。
Nuxt.jsにTypeScriptを適用したプロジェクトとして下記をよく利用させてもらっています。そちらがまだPWA化していなかったので、対応してみました。
jeehyukwon/nuxt-serverless: Nuxt.js Serverless SSR Starter on AWS (Lambda + API Gateway + S3) with Serverless Framework
https://github.com/jeehyukwon/nuxt-serverless
Progressive Web App(PWA)とは
Googleが力を入れるプログレッシブウェブアプリ(PWA)とはなにか? | SEO研究所サクラサクラボ
https://www.sakurasaku-labo.jp/blogs/pwa
PWAとはなにか?という問いに、非常に簡単に答えるとすると「アプリのようなウェブサイト」になります。
前提
- AWSアカウントがある
- serverlessがインストール・設定済み
- node.js、npm(、yarn)がインストール済み
手順
環境構築
今回はPWAに対応して動作確認することを目的としますので、上記リポジトリをベースにS3を利用しないようにしたリポジトリを用います。
kai-kou/nuxt-serverless at feature/no-use-s3
https://github.com/kai-kou/nuxt-serverless/tree/feature/no-use-s3
ベースにするリポジトリに関しては下記に利用方法をまとめています。
Nuxt.js(v2.2.0)+TypeScriptなアプリをAWS Lambda+αにデプロイしてみた(S3なし版) - Qiita
https://qiita.com/kai_kou/items/ffc4b7780e61f740e5d2
今回のソースはGitHubにもアップしていますので、ご参考ください。
https://github.com/kai-kou/nuxt-serverless/tree/feature/add-pwa
> mkdir 任意のディレクトリ
> cd 任意のディレクトリ
> git clone https://github.com/kai-kou/nuxt-serverless.git
> cd nuxt-serverless
> git checkout feature/no-use-s3
> npm install
PWAライブラリの導入
Nuxt.jsの場合、@nuxtjs/pwa
というモジュールが提供されていますので、それを利用します。
nuxt-community/pwa-module: ⚡ Supercharge Nuxt with a heavily tested, updated and stable PWA solution
https://github.com/nuxt-community/pwa-module
> npm install --save @nuxtjs/pwa
利用方法については下記を参考にさせていただきました。
Nuxt.js で作った静的サイトを PWA 化する - Qiita
https://qiita.com/QUANON/items/880eaa43c1d2f55f5b4d
PWAをNuxt.jsで簡単に体験する - SCOUTER開発者ブログ
https://techblog.scouter.co.jp/entry/2017/12/07/080416
両方の記事ともにTypeScriptを利用していないため、プロジェクトに合わせて設定する必要がありました。
handler.js
にapplication/manifest+json
を追加します。
const awsServerlessExpress = require('aws-serverless-express')
const app = require('./server')
const binaryMimeTypes = [
'application/javascript',
'application/json',
'application/manifest+json',
'application/octet-stream',
'application/xml',
'font/eot',
'font/opentype',
'font/otf',
'image/jpeg',
'image/png',
'image/svg+xml',
'text/comma-separated-values',
'text/css',
'text/html',
'text/javascript',
'text/plain',
'text/text',
'text/xml'
]
const server = awsServerlessExpress.createServer(app, null, binaryMimeTypes)
module.exports.render = (event, context) => awsServerlessExpress.proxy(server, event, context)
nuxt.config.js
のmodules
に@nuxtjs/pwa
を追加、pwaのオプションmanifest
とworkbox
を追加します。
modules: [
'@nuxtjs/pwa',
],
manifest: {
name: 'Nuxt.js+TypeScriptアプリをPWA化する',
lang: 'ja',
start_url: '/dev/',
icons: [
{
src: "static/icon.png",
sizes: "512x512",
type: "image/png",
}
]
},
workbox: {
swDest: 'static/sw.js',
},
}
server.js
に/sw.js
のルーティング設定を追加します。
PWAで利用するのにstatic/icon.png
を指定していますので、適当に用意してください。
const express = require('express')
const {Nuxt} = require('nuxt')
const path = require('path')
const awsServerlessExpressMiddleware = require('aws-serverless-express/middleware')
const app = express()
app.use(awsServerlessExpressMiddleware.eventContext())
app.use('/_nuxt', express.static(path.join(__dirname, '.nuxt', 'dist', 'client')))
app.use('/static', express.static(path.join(__dirname, 'static')))
app.use('/sw.js', express.static(path.join(__dirname, 'static', 'sw.js')))
let config = require('./nuxt.config.js')
const nuxt = new Nuxt(config)
app.use((req, res) => {
req.url = `${config.router.base}${req.url}`.replace('//', '/')
nuxt.render(req, res)
})
module.exports = app
デプロイして動作確認
Expressでパス指定しており、ローカルでの検証ができませんので、デプロイして確認してみます。
デプロイ前にserverless.yml
の設定service
やregion
など、適宜変更してください。
> npm run build
> serverless deploy
ブラウザで確認するとsw.jsが読み込まれていることが確認できました。
スマホ(Android)では、Google Chromeの「ホーム画面に追加」機能で、アプリっぽく利用できることが確認できました。
やったぜ。
ポイント
PWAのmanifest設定を変更する
TypeScriptを利用しているので、nuxt.config.js
で諸々パスを変更する必要がありました。
manifest.start_url
は初期設定だと.
となり、かつpublicPath
が_nuxt
となるため、/dev
とします。カスタムドメインを利用する場合には、/
となります。
manifest: {
start_url: '/dev',
},
アイコンについてもstatic/icon.png
が参照されるように指定します。
manifest: {
icons: [
{
src: "static/icon.png",
sizes: "512x512",
type: "image/png",
}
]
},
sw.js
の出力先が初期設定だと、src/static/sw.js
となるため、static/sw.js
としています。
workbox: {
swDest: 'static/sw.js',
},
また、sw.jsのパスがstatic
以下のままですと、PWAのスコープ(対象範囲)がstatic
以下となってしまい、使い勝手が悪くなるため、/sw.js
でアクセス可能になるようにします。
app.use('/sw.js', express.static(path.join(__dirname, 'static', 'sw.js')))
スコープやmanifest
やworkbox
の設定については下記が参考になりました。
Service Worker、はじめの一歩 - Service Workerとは | CodeGrid
https://app.codegrid.net/entry/2016-service-worker-1
Workbox Build | Workbox | Google Developers
https://developers.google.com/web/tools/workbox/modules/workbox-build
Workbox Module - PWA Module
https://pwa.nuxtjs.org/modules/workbox
Webアプリケーションマニフェスト| MDN
https://developer.mozilla.org/en-US/docs/Web/Manifest
タイムアウトエラーが発生したらyarn
を利用する
npm
でライブラリをインストールしていると、デプロイできても、URLへアクセスするとタイムアウトエラーになることがありました。その場合には、yarn
でライブラリをインストールし直すとうまく動きました。
その際にpackage-lock.json
が含まれたままだと、Serverlessでデプロイ時にnode_modules
以下すべてが含まれてパッケージングされてしまうので、注意しましょう。
package-lock.jsonがある状態でyarn installするとServerlessのデプロイで痛い目にあう
TODO: あとでURLを貼る
> rm -rf node_modules/
> rm package-lock.json
> npm install -g yarn # yarnがインストールされていなかったら
> yarn
> yarn build
> serverless deploy
参考
Googleが力を入れるプログレッシブウェブアプリ(PWA)とはなにか? | SEO研究所サクラサクラボ
https://www.sakurasaku-labo.jp/blogs/pwa
Service Worker、はじめの一歩 - Service Workerとは | CodeGrid
https://app.codegrid.net/entry/2016-service-worker-1
Workbox Build | Workbox | Google Developers
https://developers.google.com/web/tools/workbox/modules/workbox-build
Workbox Module - PWA Module
https://pwa.nuxtjs.org/modules/workbox
Nuxt.js で作った静的サイトを PWA 化する - Qiita
https://qiita.com/QUANON/items/880eaa43c1d2f55f5b4d
PWAをNuxt.jsで簡単に体験する - SCOUTER開発者ブログ
https://techblog.scouter.co.jp/entry/2017/12/07/080416
Webアプリケーションマニフェスト| MDN
https://developer.mozilla.org/en-US/docs/Web/Manifest
package-lock.jsonがある状態でyarn installするとServerlessのデプロイで痛い目にあう
TODO: あとでURLを貼る