Next.js 에서 PWA 를 통한 웹푸시 설정하기
사용스택 : Next.js, firebase
리액트로 시도..했었다..
환경 : 리액트
애초에 pwa 를 사용할것이라면 서비스워커가 포함된 템플릿을 설정해줘야함.
🚨 만약 미리 설정을 하지않았다면?
18버전이 후 CRA 로 받더라도 service-worker 가 없으므로 인스톨을 해주어야 하는데
이미 프로젝트를 만든 상태라면 템플릿을 따로 추가할 방법이 없으니, pwa가 적용된 프로젝트를 새로 만들어 서비스워커 관련 코드를 복붙해주는게 제일 간단한 방법인듯 하다.
- service-worker.js , serviceWorkerRegistration.js 그대로 복붙하여 기존프로젝트에 넣는다.
- package.json 의 dependencies 에 아래의 항목 추가
- 기존 프로젝트에서 npm install
- serviceWorkerRegistration.register() 를 추가한다.
🎄 PWA 를 위한 Next.js 환경 설치하기
혹시몰라 리액트 , 리액트라우터 돔 17.0.2 버전, 넥스트 12.0.1 버전으로 install
폴더구조
next.config.js
manifest.json
public 안에 manifest.json 파일을 직접 추가할 수 있지만, manifest generator 를 이용하여 다운로드 가능.
- Short name : 앱 이름을 표시할 공간이 충분하지 않을 때 나타나는 이름
- Display : homescreen icon을 통해 실행될 때 app 화면이 보여지는 형태
- browser : 일반 브라우저와 동일하게 보입니다.
- standalone : 다른 앱들처럼 최상단에 상태표시줄을 제외한 전체화면으로 보입니다.
- fullscreen : 상태표시줄도 제외한 전체화면으로 보여줍니다.(ex. 게임)
- minimul-ui : fullscreen과 비슷하지만 뒤로가기, 새로고침등 최소한의 영역만 제공합니다.(모바일 크롬 전용)
- Description : app의 description 정보
- Application Scope(=scope) : app 내에서 PWA 기능을 적용할 범위
- Start url : app이 최초 실행 될 때 load되는 file의 경로
- Background color : 스플래시 배경색
다운받은 후 manifest.webmanifest 이름을 manifest.json 으로 변경한 후 public 디렉토리 내부에 넣어둔다.
파비콘 디렉토리생성
밑의 사이트에서 파비콘 생성하여 public 폴더 내 생성
ios 아이콘 메타태그
IOS 스플래시 메타태그
스플래시 : 앱을 열 때 나오는 로딩화면.
스플래시 제너레이터를 통해 만든 후 Appscope 에 적용하여 폰 화면 별 다운로드를 받을 수 있다.
해당 다운로드 받는 항목들을 public 내 삽입한다.
메타태그 적용
브라우저가 PWA라는것을 알아채고 manifest에 접근할 수 있도록 메타태그를 적용해야하므로 _document.jsx 파일을 생성한다.
해당파일의 Head 태그 내부에 manifest.json 의 경로와 meta 태그, 아이콘을 넣어주도록 한다.
yarn build
+ yarn dev
빌드 및 start 시 [PWA] 가 반드시 나와야 제대로 적용된것이라고 할 수 있다.
다음 화면과 같이 나오면 서비스워크 연결 성공!
🎄 파이어베이스 환경설정
파이어베이스 사이트에서 로그인 후 웹앱을 생성한다.
웹앱에 firebase 추가까지 완료하였으면 콘솔창으로 넘어간다.
이때 톱니바퀴모양을 눌러 설정을 들어간 후 클라우드 메시징을 클릭한다.
처음에 아무설정을 안해놨다면 colude Messaging API 가 사용중지됨으로 표시될텐데, 닷버거를 눌러
google cloude console 에서 관리를 클릭한다.
클라우드 메세징의 사용설정을 변경하면 활성화가 된 것을 확인할 수 있다.
파이어베이스 인스톨 후 _app.js 에 파이어베이스에서 받은 SDK 를 삽입하도록 한다.
npx create-react-app test --template cra-template-pwa
"workbox-background-sync": "^6.5.4",
"workbox-broadcast-update": "^6.5.4",
"workbox-cacheable-response": "^6.5.4",
"workbox-core": "^6.5.4",
"workbox-expiration": "^6.5.4",
"workbox-google-analytics": "^6.5.4",
"workbox-navigation-preload": "^6.5.4",
"workbox-precaching": "^6.5.4",
"workbox-range-requests": "^6.5.4",
"workbox-routing": "^6.5.4",
"workbox-strategies": "^6.5.4",
"workbox-streams": "^6.5.4"
npx create-next-app@latest
//-> 13버전이므로 yarn add next@12.1.0 react@17.0.2 react-dom@17.0.2 다운그레이드함
//-> 버전문제가 아니었던걸로.
yarn add next-pwa
//추가플러그인 사용시 설치. 나같은경우 설치는 했지만 결국 사용하지 않았다.
yarn add --dev next-compose-plugins
C:\USERS\{username}\NEXT-PWA
├─Pages
│ └─index.tsx
│ └─_app.tsx
│ └─_document.tsx
├─Public
│ └─Images
│ └─manifest.json
│ └─sw.js
│ └─sw.js.map
│ └─workbox.js
│ └─workbox.js.map
└─next.config.js
const withPWA = require('next-pwa')({
dest: 'public'
// disable: process.env.NODE_ENV === 'development',
// register: true,
// scope: '/app',
// sw: 'service-worker.js',
//...
})
module.exports = withPWA({
// next.js config
})
{
"theme_color": "#57c9d1",
"background_color": "#57c9d1",
"display": "standalone",
"orientation": "portrait",
"scope": "/",
"start_url": "/",
"name": "\uc815\ud574\uc918\ub0b4\uc2dd\uc0ac",
"short_name": "\uc815\ud574\uc918 \ub0b4\uc2dd\uc0ac",
"description": "\uc2dd\uc0ac\uc815\ud558\uae30 \ud798\ub4dc\uc2dc\uc8e0? \uadf8\ub7f4\ub550 \uc815\ud574\uc918\ub0b4\uc2dd\uc0ac",
"icons": [
{
"src": "images/icons/icon-48x48.png",
"sizes": "48x48",
"type": "image/png"
},
{
"src": "images/icons/icon-72x72.png",
"sizes": "72x72",
"type": "image/png"
},
{
"src": "images/icons/icon-96x96.png",
"sizes": "96x96",
"type": "image/png"
},
{
"src": "images/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "images/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "images/icons/icon-256x256.png",
"sizes": "256x256",
"type": "image/png"
},
{
"src": "images/icons/icon-384x384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "images/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
]
}
<link rel="apple-touch-icon" href="images/icons/icon-192x192.png"></link>
<meta name="theme_color" content="#57c9d1"></meta>
import { Html, Head, Main, NextScript } from "next/document";
export default function Document() {
return (
<Html lang="ko">
<Head>
<meta name="theme-color" content="#57c9d1"/>
<link rel="manifest" href="/manifest.json" />
<link
href="images/favicons/favicon-16x16.png"
rel="icon"
type="image/png"
sizes="16x16"
/>
...
<link
rel="apple-touch-startup-image"
href="/images/splashscreens/ipadpro2_splash.png"
media="(min-device-width: 1024px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)"
></link>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}