THE DEVLOG

scribbly.

Next.js+형태소분석 CS퀴즈앱 만들기

2023.03.06 10:16:45

sw.js 만들기 (next-pwa)

pwa를 배포하기 위해서는 service-worker.js 파일에 이벤트 리스너를 추가해주어야 한다. 여기에는 'install', 'activate', 'fetch' 등이다.

이러한 작업을 zero-config로 도와주는 라이브러리가 next-pwa이다.

  1. 설치
    yarn install next-pwa

  2. next.config.js

const withPWA = require("next-pwa")({
  dest: "public",
});

const nextConfig = withPWA({
  reactStrictMode: true,
  compiler: {
    styledComponents: true,
  },
});

module.exports = nextConfig;

withPWA를 만든 후, 이를 통해 기존 config를 감싸면 간단하게 sw.js를 만들어준다.

manifest.json

서비스 워커에서 핵심적인 것은 manifest이다.
어플리케이션처럼 동작하기 위한 메타데이터를 저장한 파일이다.

{
  "name": "CS 퀴즈풀기",
  "short_name": "CS 퀴즈풀기",
  "icons": [
    {
      "src": "/favicon.jpg",
      "sizes": "256x256",
      "type": "image/png",
      "purpose": "any maskable"
    }
  ],
  "theme_color": "#FFFFFF",
  "background_color": "#FFFFFF",
  "start_url": "/",
  "display": "standalone",
  "orientation": "portrait"
}

아이콘을 설정하고, 아이콘이 작게 표기될 때 백그라운드에 표시될 색깔, 어플리케이션 이름 등을 설정한다.

여기서 "display": "standalone", 부분이 중요한데, 이 설정을 통해 웹 페이지가 모바일 어플리케이션처럼 보이게 된다.

메타태그 작성하기

메타 태그는 _document.tsx나 _app.tsx에 작성하면 된다.
_document.tsx에서는 메타데이터에서 title을 설정할 수 없기 때문에 편의상 _app.tsx에서 작성하였다.

대표적인 메타 태그는 아래와 같다.
<link rel="manifest" href="/manifest.json" />: 메니페스트 파일을 연결시킨다.
meta name="viewport" content="initial-scale=1, viewport-fit=cover, width=device-width"></meta> : viewport를 가득 채운다. standalone 모드가 제대로 작동하지 않을 때 보조적인 역할을 한다.
<meta name="apple-mobile-web-app-capable" content="yes"></meta>
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"></meta> : 노치 디자인을 채우기 위해 뻘짓하다 발견한 돗이다. bar-style를 black-translucent로 지정하면 웹의 배경화면 설정으로 노치를 채우게 된다. default값은 노치 부분을 가려서 화면이 제한된다. 다음 글을 참조하자. Make your pwa look handsome on ios

이것저것 쳐내고 남은 메타태그는 아래와 같다.

      <Head>
        <title>CS 문제 풀기</title>
        <meta name="description" content="CS 문제를 자유롭게 풀어봐요" />
        <link rel="icon" href="/favicon.ico" />
        <link rel="manifest" href="/manifest.json" />

        <meta name="application-name" content="CS 퀴즈풀기" />
        <meta
          name="viewport"
          content="initial-scale=1, viewport-fit=cover, width=device-width"
        ></meta>
        <meta name="apple-mobile-web-app-capable" content="yes"></meta>
        <meta
          name="apple-mobile-web-app-status-bar-style"
          content="black-translucent"
        ></meta>
        <meta name="apple-mobile-web-app-title" content="CS 퀴즈풀기" />
        <meta name="description" content="CS 문제를 마음대로 풀어보세요" />
        <meta name="format-detection" content="telephone=no" />
        <meta name="mobile-web-app-capable" content="yes" />

        <meta name="msapplication-TileColor" content="#2B5797" />
        <meta name="msapplication-tap-highlight" content="no" />
        <meta name="theme-color" content="#000000" />

        <link rel="apple-touch-icon" href="/favicon.jpg" />

        <link rel="mask-icon" href="/favicon.jpg" color="#5bbad5" />
        <link rel="shortcut icon" href="/favicon.ico" />
      </Head>

노치 화면 채우기

앞서 언급했듯, 애플은 PWA에서 노치 화면을 감추거나(default), 완전히 열어두게(translucent) 된다.
black-translucent로 노치를 열어두고, 노치의 높이만큼 padding을 채우면 원하는 디자인으로 노치를 꾸밀 수 있다.

export const StyledTextHeader = styled.div`
  position: sticky;
  top: 0;
  padding: 0.5rem 1rem;
  padding-top: calc(0.3rem + env(safe-area-inset-top));

설치 안내 문구 띄우기

랜딩 페이지에서 PWA를 설치하는 버튼을 만들고자 했는데,
안드로이드에서도 아이폰에서도 설치 버튼이 작동되지 않았다.

PWA 여부와 OS 종류를 감지하여 그에 맞는 문구를 띄워주기로 했다.
components\common\molecules\HomeScreenMessage.tsx

import { useEffect, useState } from "react";

const HomeScreenMessage = () => {
  const isAndroid =
    typeof window !== "undefined" &&
    /android/i.test(window.navigator.userAgent);
  const isiOS =
    typeof window !== "undefined" &&
    /iphone|ipad|ipod/i.test(window.navigator.userAgent);

  const [msg, setMsg] = useState("");
  useEffect(() => {
    if (isiOS) {
      setMsg(
        '아이폰 브라우저에서는 "공유" 버튼을 눌러 홈 화면에 추가할 수 있습니다.'
      );
    } else if (isAndroid) {
      setMsg(
        '안드로이드 브라우저에서는 "홈 화면에 추가" 또는 "추가" 버튼을 눌러 홈 화면에 추가할 수 있습니다.'
      );
    }
  }, []);

  if ((isAndroid || isiOS) && !window.navigator.standalone) {
    return (
      <div style={{ fontSize: "x-small", color: "gray" }}>
        <div>
          <b>홈 화면에 바로가기를 추가해보세요. </b>
        </div>
        <span>{msg}</span>
      </div>
    );
  }

  return null;
};

export default HomeScreenMessage;

declare global {
  interface Navigator {
    standalone?: boolean;
  }
}

pages\index.tsx

        <Description>
          <HomeScreenMessage></HomeScreenMessage>
        </Description>
      </Main>
    </Container>
  );
}

배포하기

vercel로 배포하면 된다.
배포된 주소는 이곳이다. (나름 희귀한 도메인을 얻었다.)

모바일로 접속하면 아래에 홈 화면에 추가하라는 문구가 나온다.

'홈 화면에 바로가기 만들기'를 하면 pwa가 설치된다.



이렇게 해서 완성이 완료됐다.