Next.js を使って Chrome からインストール可能な PWA(desktop PWA) 環境を2秒で作ります(ついでに now で remote でも動かせるようにします)
10 分くらいはかかると思います
motivation
chrome73 から desktop PWA がきているのでそれを手軽に実感するやつ作ろうと思います
https://developers.google.com/web/updates/2019/03/nic73#pwas-everywhere
engines
$ node -v; npm -v
v11.0.0
6.4.1
set up
$ mkdir -p pwa-app/pages; cd pwa-app
$ npm init -y; npm i -SE next react react-dom
$ echo 'export default () => <div>Welcome to next.js!</div>' > pages/index.js
$ echo 'export default () => <div>pwa start!</div>' > pages/pwa.js
$ next
static resources
Next.js は静的リソースの置き場所として /static
を用意している
https://github.com/zeit/next.js/#static-file-serving-eg-images
$ mkdir static
sw.js
fetch
ハンドラの記述が必須なのでそれだけ書いとく
$ echo 'self.addEventListener("fetch", event => {});' > static/sw.js
manifest.json
generator があり、これを使うと icon とかを用意できるので特に問題なければこれ使えば楽
https://app-manifest.firebaseapp.com/
"display":"standalone"
, "Scope": "/",
, "start_url": "/pwa"
としておけばあとはまあなんでも ok
↑ で出来た zip を解凍してその中身を /static
の下に配置する
$ tree -L 2 static/
static/
├── images
│ └── icons
├── manifest.json
└── sw.js
components
SW の install script と manifest.json
の読み込みタグをぶち込む
$ touch sw-register.js
import React, { PureComponent } from 'react';
class SWRegister extends PureComponent {
componentDidMount() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/sw.js')
.then(() => {
console.log('service worker registration successful');
})
.catch((err) => {
console.warn('service worker registration failed', err.message);
});
}
}
render() {
return <></>;
}
}
export default SWRegister;
import Head from 'next/head';
import SWRegister from '../sw-register';
function IndexPage() {
return (
<>
<Head>
<link rel="manifest" href="/static/manifest.json" />
</Head>
<p>welcome to next.js!</p>
<SWRegister />
</>
);
}
export default IndexPage;
custom server
/
scope で SW を実行させたいので、 /sw.js
の request を /static/sw.js
に routing させる
default の next/server
では /
配下のアクセスは全て /pages/
へ解決されてしまうため、カスタムサーバを作る
$ touch server.js
const { createServer } = require('http');
const { parse } = require('url');
const next = require('next');
const { PORT, NODE_ENV } = process.env;
const port = parseInt(PORT, 10);
const dev = NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
app.prepare().then(() => {
createServer((req, res) => {
const parsedUrl = parse(req.url, true);
const { pathname } = parsedUrl;
if (pathname === '/sw.js') {
handle(req, res, { ...parsedUrl, pathname: '/static/sw.js' });
} else {
handle(req, res, parsedUrl);
}
}).listen(port, (err) => {
if (err) throw err;
console.log(`> Ready on http://localhost:${port}`);
});
});
$ node server.js
うまくいっていると 右上の 縦三点リーダ「pwa-app」をインストール と出ていると思うのでそこから install 出来ます
install 後、起動すると launch 後に start_url
で指定したとこに飛ぶ
now
zeit が提供している Global Serverless Deployments(引用)
詳しく知りたい人はワイの記事みといてください (v1 の時期の記事なので少し古い)
https://qiita.com/lidqqq/items/11722f5e3225f7806f50
ちなみに 利用には signup が必要(無料で利用可)なのでご注意を
まずは package の install
$ npm i -DE now
now 専用の run-script を用意
"scripts": {
"now-build": "./node_modules/.bin/next build"
},
必要な file を作ってきます
$ touch .nowignore now.json next.config.js
.nowignore
deploy から除外する file を記述
.next/
.vscode/
node_modules/
README.md
now.json
now 用の設定 file
routes
のとこで routing を変更しているとこをがミソ
{
"name": "pwa-app",
"version": 2,
"builds": [{ "src": "package.json", "use": "@now/next" }],
"routes": [
{
"src": "/sw.js",
"dest": "/static/sw.js"
}
]
}
next.config.js
now で deploy される先の実行環境では target: "serverless"
の指定が必須
local と remote で同じ file を使うので、実行 context によって target を変更するように修正
YOUR_LOCAL_MACHINE_HOSTNAME
には 適宜 hostname をお願いします
const { hostname } = require('os');
module.exports = {
target:
hostname() !== { YOUR_LOCAL_MACHINE_HOSTNAME } ? 'serverless' : 'server',
};
$ now
deploy された先の URL にアクセスして同じようにインストールできると思います
fin.