PWA - dltmdrbtjd/HANG GitHub Wiki

PWA ( Progerssive Web Apps )

ํ”„๋กœ๊ทธ๋ ˆ์‹œ๋ธŒ ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์›น์„ ํ†ตํ•ด ์ „๋‹ฌ๋˜๋Š” ์‘์šฉ ์†Œํ”„ํŠธ์›จ์–ด์˜ ์ผ์ข…์œผ๋กœ

HTML,CSS,JAVASCRIPT๋ฅผ ํฌํ•จํ•œ ์ผ๋ฐ˜ ์›น ๊ธฐ์ˆ ๋“ค์„ ์‚ฌ์šฉํ•˜์—ฌ ๋งŒ๋“ค์–ด์ง„๋‹ค.

ํ‘œ์ค€์„ ์ค€์ˆ˜ํ•˜๋Š” ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์–ด๋– ํ•œ ํ”Œ๋žซํผ์—์„œ๋ผ๋„ ๋™์ž‘ํ•˜๋„๋ก ๊ณ ์•ˆ๋˜์—ˆ๋‹ค.

ํŠน์ง•

  1. PWA์˜ ํŠน์ง•์€ App์Šค๋Ÿฌ์›€์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค. App์ฒ˜๋Ÿผ ํ™ˆ์Šคํฌ๋ฆฐ์— ์•„์ด์ฝ˜์„ ์„ค์น˜ํ•˜์—ฌ App์ฒ˜๋Ÿผ ์‰ฝ๊ฒŒ ๋ฐ”๋กœ๊ฐ€๊ธฐ๋ฅผ ์‹คํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

  2. PWA๋Š” HTTPS์—์„œ๋งŒ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋ฐ˜ ์ธํ„ฐ๋„ท ๋ฐ์ดํ„ฐ์— ๋น„ํ•ด ๋ณด์•ˆ์ด ๊ฐ•ํ™”๋œ ์ƒํƒœ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

  3. PWA๊ฐ€ ์บ์‹ฑ์ด ๋˜๊ธฐ ๋•Œ๋ฌธ์— Offline์ด๊ฑฐ๋‚˜ ์†๋„๊ฐ€ ๋А๋ฆฐ ์ƒํƒœ์—์„œ๋„ ๋ฏธ๋ฆฌ ๋‹ค์šด๋กœ๋“œ ๋˜์–ด ์žˆ๋Š” ์ •๋ณด๋ฅผ ๊ณ„์† ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

pwa ์ œ์ž‘ ๊ธฐ์ˆ 

manifest.json

manifest.json์€ ์„ค์น˜ํ• ๋•Œ ์•„์ด์ฝ˜์€ ๋ฌด์–ผ ์‚ฌ์šฉํ•˜๊ณ  ์•„์ด์ฝ˜์„ ๋ˆŒ๋ €์„๋•Œ ์ ‘์†ํ•  ํŽ˜์ด์ง€๋Š” ๋ฌด์—‡์ธ์ง€, ๋ฐฐ๊ฒฝ์ƒ‰์€ ๋ฌด์Šจ์ƒ‰์œผ๋กœ ํ•  ๊ฒƒ์ธ์ง€ ๋“ฑ๋“ฑ..์— ๋Œ€ํ•œ ์„ค์ •ํŒŒ์ผ์ด๋‹ค.

  • ๋งค๋‹ˆํŽ˜์ŠคํŠธ(Manifest)์˜ ์„ค์ •์€ JSON์œผ๋กœ ์„ค์ •ํ•œ๋‹ค. ํŒŒ์ผ์€ index.html์˜ head์•ˆ์— ๋ฐฐ์น˜ํ•œ๋‹ค.
// index.html
<head>
  <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
</head>

// manifest.json
{
  "short_name": "HANG",
  "name": "Create React App Sample",
  "icons": [
    {
      "src": "favicon.ico",
      "sizes": "64x64 32x32 24x24 16x16",
      "type": "image/x-icon"
    },
    {
      "src": "logo192.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "logo512.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ],
  "start_url": ".",
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff"
}
  1. App icon: ์„ค์น˜์‹œ ์•ฑ์˜ ์•„์ด์ฝ˜ ์ด๋ฏธ์ง€์™€ ํฌ๊ธฐ ์„ค์ •
  2. ์Šคํ”Œ๋ž˜์‹œ(splash screen)ํ™”๋ฉด : ๋กœ๋”ฉํ™”๋ฉด ์„ค์ •
  3. start url : ์›น์•ฑ์ด ์‹คํ–‰๋  ๋•Œ ๊ฐ€์žฅ ์ฒ˜์Œ ๋ณด์—ฌ์งˆ url์„ค์ •
  4. display type: ์›น์•ฑ์˜ ํ™”๋ฉด ํ˜•ํƒœ(browser, standalone, fullscreen)
  5. display orientation : ์›น์•ฑ์˜ ํ™”๋ฉด ๋ฐฉํ–ฅ (๊ฐ€๋กœ/์„ธ๋กœ)
  • short_name ์ง€์ • : short_name์€ ํ•„์ˆ˜ ์ž…๋ ฅ์‚ฌํ•ญ์œผ๋กœ ์ด๊ฒŒ ์žˆ์–ด์•ผ ๋ฐฐ๋„ˆ๋ฅผ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๊ฑด ํ”„๋กœ์ ํŠธ ์ด๋ฆ„์œผ๋กœ ์„ค์น˜๋œ ์•„์ด์ฝ˜์˜ ์ด๋ฆ„์œผ๋กœ ํ‘œ์‹œ ๋œ๋‹ค.
  • name ์ง€์ • : name๋„ ํ•„์ˆ˜ ์ž…๋ ฅ์‚ฌํ•ญ์œผ๋กœ name์ด ์žˆ์–ด์•ผ ๋ฐฐ๋„ˆ๋ฅผ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๊ฑด ์„ค์น˜ ๋ฐฐ๋„ˆ์— ํ‘œ์‹œ๋˜๋Š” ์ด๋ฆ„์ด๋ฉฐ ๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ๋กœ ์‚ฌ์šฉ๋œ๋‹ค.
  • icons์ง€์ • : icons๋Š” ์•ฑ์—์„œ ํ•„์š”ํ•œ ๋‹ค์–‘ํ•œ ํฌ๊ธฐ์˜ ์•„์ด์ฝ˜์„ ์ง€์ •ํ•œ๋‹ค. ๊ทธ์ค‘์—์„œ๋„ 192px(128dp)๋Š” ๊ผญ ์žˆ์–ด์•ผ ํ•˜๋Š” ํฌ๊ธฐ์˜ ์•„์ด์ฝ˜์ด๋‹ค. ์ด ์•„์ด์ฝ˜์ด ์žˆ์–ด์•ผ ์Šคํ”Œ๋ž˜์‹œ ํ™”๋ฉด์ด ํ‘œ์‹œ๋œ๋‹ค.
  • splash screen ์„ค์ • : ์Šคํ”Œ๋ž˜์‹œ ์Šคํฌ๋ฆฐ์€ 3๊ฐ€์ง€์˜ ์„ค์ • ์กฐํ•ฉ์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค. ๋ฐฐ๊ฒฝ์ƒ‰ + ์•„์ด์ฝ˜ + short_name(์•„์ด์ฝ˜์ด๋ฆ„) ์ด ์„ค์ •๋˜์–ด์žˆ๋‹ค๋ฉด ์Šคํ”Œ๋ž˜์‰ฌ ํ™”๋ฉด์ด ๋‚˜์˜จ๋‹ค.
  • start_url ์„ค์ • : start_url์€ ํ•„์ˆ˜ ์š”์†Œ๋กœ ์›น์•ฑ์ด ์‹คํ–‰๋ ๋•Œ ๊ฐ€์žฅ ์ฒ˜์Œ ๋‚˜์˜ค๋Š” ํ™”๋ฉด์„ ์ง€์ •ํ•œ๋‹ค. ์ฆ‰ ์Šคํ”Œ๋ž˜์‹œ ํ™”๋ฉด ๋‹ค์Œ์— ๋‚˜์˜ค๋Š” ํ™”๋ฉด์ด๋‹ค. ๊ธฐ๋ณธ ์„ค์ •์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์ด์šฉํ•˜๊ณ  ๊ทธ ์™ธ์— Query String์„ ์‚ฌ์šฉํ•  ์ˆ˜ ๋„ ์žˆ๋‹ค.
"start_url": "./index.html",

"start_url": "./index.html?name=names1123",
  • display ์„ค์ • : display์˜ ์„ค์ •์€ ์›น์•ฑ์ด ์–ด๋–ค ๋ชจ์–‘์œผ๋กœ ๋ณด์—ฌ์งˆ์ง€ ์„ค์ •ํ•˜๋Š” ๊ฐ’์ด๋‹ค.
    • browser(normal): ํ•ด๋‹น ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ธฐ๋ณธ ์›น์œผ๋กœ ์‹คํ–‰
    • standalone: ์ƒ๋‹จ์˜ url๋ฐ”๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ๋„ค์ดํ‹ฐ๋ธŒ์•ฑ์ฒ˜๋Ÿผ ๋ณด์ž„(๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ)
    • fullscreen: ํ™”๋ฉด ์ „์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋„ค์ดํ‹ฐ๋ธŒ์ฒ˜๋Ÿผ ๋ณด์ž„
    • iOS์—์„œ standalone์‚ฌ์šฉ์‹œ ํƒœ๊ทธ ์•ˆ์— ์•„๋ž˜์˜ ๋ฉ”ํƒ€ํƒœํฌ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผํ•œ๋‹ค.
<meta name="apple-mobile-web-app-capable" content="yes">
  • theme_color ์„ค์ • : ํ…Œ๋งˆ ์ปฌ๋Ÿฌ๋Š” ๋ฐ”๋ผ์šฐ์ € ์ƒ๋‹จ์˜ url์ž…๋ ฅ๋ฐ”์™€ ์‹œ์Šคํ…œ ๋ฐ”๊นŒ์ง€ ํฌํ•จํ•œ ์ƒ‰์ƒ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
"theme_color": "#c4c4c4",
  • orientation ์„ค์ • : orientation์€ ๊ธฐ๊ธฐ์˜ ๋ฐฉํ–ฅ์„ ๊ฐ€๋กœ๋กœํ• ์ง€ ์„ธ๋กœ๋กœํ• ์ง€ ์ง€์ •ํ•˜๋Š” ๊ฐ’์ด๋‹ค. ๊ฒŒ์ž„์ด ์•„๋‹ˆ๋ผ๋ฉด ๊ฑฐ์˜ ์„ธ๋กœ๋ชจ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.
// ์„ธ๋กœ๋ชจ๋“œ : portrait , ๊ฐ€๋กœ๋ชจ๋“œ : landscape
"orientation": "portrait",

service-worker

service-worker๋Š” pwa์˜ ํ•ต์‹ฌ์œผ๋กœ ์บ์‹ฑ์€ ์–ด๋–ป๊ฒŒ ํ•  ๊ฒƒ์ธ์ง€ ์š”์ฒญ์‹œ ์บ์‹œ๋ฅผ ๋จผ์ € ๋ณด์—ฌ์ค„์ง€ ์›น์„œ๋ฒ„๋ฅผ ํ†ตํ•ด์„œ ๋จผ์ € ๋ณด์—ฌ์ค„์ง€, push๋“ฑ๋“ฑ์— ๋Œ€ํ•œ ํ”„๋กœ๊ทธ๋ž˜๋ฐํ•˜๋Š” ๊ธฐ์ˆ ์ด๋‹ค. pwa์˜ ๊ฑฐ์˜ 8ํ• ์— ํ•ด๋‹นํ•˜๋Š” ๊ธฐ์ˆ ์ด๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

service-worker ํŒŒ์ผ์€

npx create-react-app my-app --template cra-template-pwa-typescript

์œ„์™€ ๊ฐ™์ด cra๋ฅผ ์‹คํ–‰ํ•˜๋ฉด root์ตœ์ƒ๋‹จ์— ์ƒ์„ฑ๋˜๊ณ  ํ•ด๋‹นํŒŒ์ผ๋“ค๋กœ ์บ์‹ฑ๋ฐ ์˜คํ”„๋ผ์ธ์ž‘์—… ๋“ฑ๋“ฑ์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ถœ์ฒ˜ : https://create-react-app.dev/docs/making-a-progressive-web-app/

๊ธฐ์กด์— JS๋กœ ์ž‘์—…ํ–ˆ์„๋•Œ์—๋Š” ์บ์‹ฑํ•  ํŒŒ์ผ๋“ค์„ ์ •๋ฆฌํ•˜๊ณ  ์—ฐ๊ฒฐํ•˜๋Š”๋“ฑ์˜ ๊ณผ์ •์ด ๋ณต์žกํ–ˆ์—ˆ๋Š”๋ฐ TS๋กœ ๋ฆฌํŒฉํ† ๋ง์„ ์ง„ํ–‰ํ•˜๋ฉด์„œ ์–ด๋–ค์‹์œผ๋กœ ์ž‘์„ฑํ•˜๋ฉด ์ข€ ๋” ํšจ์œจ์ ์œผ๋กœ ์ด๊ฑธ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„๊นŒ์— ๊ณ ๋ฏผํ•˜๋ฉด์„œ ์ฐพ์•„๋ณด๋‹ค๊ฐ€ workbox๋ผ๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ–ˆ๋‹ค.

workbox

pwa์˜ ์บ์‹ฑ(caching)๊ธฐ๋Šฅ์„ ํŽธํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›๋˜๋Š” ํ‘œ์ค€ PWA ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ. [sw-precaching],[sw-toolbox]๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ง€์›ํ•˜๋˜ ๊ธฐ๋Šฅ๋“ค์„ ํ†ตํ•ฉํ•˜์—ฌ ์ œ๊ณตํ•œ๋‹ค.

npm install workbox-cli --global

์œ„ ๋ช…๋ น์–ด๋กœ ์„ค์น˜๋ฅผํ•˜๊ณ 

worbkox wizard

๋ฅผ ํ†ตํ•˜์—ฌ ์„ค์น˜๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด

  • ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฃจํŠธ๊ฐ€ ์–ด๋””์ธ์ง€? app/
  • ์–ด๋–ค ํŒŒ์ผ ์œ ํ˜•๋“ค์„ ํ”„๋ฆฌ์บ์‹ฑ(pre-caching)ํ•  ๊ฒƒ์ธ์ง€? html, css, js, jpg, png
  • ์œ„ ์˜ต์…˜๋“ค์ด ์ ์šฉ๋œ ์„œ๋น„์Šค ์›Œ์ปค ํŒŒ์ผ์ด ์ƒ์„ฑ๋  ์œ„์น˜? dist/sw.js
  • ์œ„ ๊ตฌ์„ฑ ์ •๋ณด๋“ค์„ ์–ด๋””์— ์ €์žฅํ•  ๊ฒƒ์ธ๊ฐ€? workbox-config.js ์œ„์™€ ๊ฐ™์€ ์งˆ๋ฌธ๋“ค์— ๋Œ€ํ•ด ๋‹ต์„ํ•˜๋ฉด workbox-config.js ํŒŒ์ผ์ด ์ƒ์„ฑ๋œ๋‹ค.
workbox generateSW ./workbox-config.js

์ด๋ ‡๊ฒŒ ์ƒ์„ฑ๋œ ์„œ๋น„์Šค ์›Œ์ปค ํŒŒ์ผ์—๋Š” ์›Œํฌ๋ฐ•์Šค์˜ ํ”„๋ฆฌ์บ์‹ฑ๊ณผ ๋Ÿฐํƒ€์ž„ ์บ์‹ฑ๊ธฐ๋Šฅ์ด ํฌํ•จ๋˜์–ด ์žˆ๋‹ค. ( ๋‹ค๋งŒ ์›นํ‘ธ์‰ฌ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•œ๊ฒฝ์šฐ์—๋Š” injectManifest ์˜ต์…˜์„ ํ™œ์šฉํ•ด์•ผํ•œ๋‹ค.

์›Œํฌ๋ฐ•์Šค CLI์˜ injectManifest ๋ชจ๋“œ

์›Œํฌ๋ฐ•์Šค injectManifest ๋ชจ๋“œ๋Š” generateSW ๋ชจ๋“œ์™€๋Š” ๋‹ค๋ฅด๊ฒŒ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ข€ ๋” ์„œ๋น„์Šค์›Œ์ปค ํŒŒ์ผ์„ ์ง์ ‘ ์กฐ์ž‘ํ•˜๊ฑฐ๋‚˜ ๋‚ด์šฉ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŒŒ์ผ ์บ์‹ฑ ์ด์™ธ์— ์›น ํ‘ธ์‹œ API์™€ ๊ฐ™์€ ๋„ค์ดํ‹ฐ๋ธŒ API ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์ ํ•ฉํ•œ ๋ชจ๋“œ์ž…๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ์ž๊ฐ€ ๊ตฌํ˜„ํ•ด๋†“์€ ์„œ๋น„์Šค ์›Œ์ปค ํŒŒ์ผ์„ ์ฝ์–ด ์„ค์ • ํŒŒ์ผ(workbox-config.js)์— ์„ค์ •๋œ ์บ์‹ฑ ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์ƒˆ ์„œ๋น„์Šค ์›Œ์ปค ํŒŒ์ผ์„ ์ƒ์„ฑํ•ด์ค๋‹ˆ๋‹ค. ๋ช…๋ น์–ด๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

workbox injectManifest ./workbox-config.js

์ถœ์ฒ˜ : https://joshua1988.github.io/vue-camp/pwa/workbox.html#%E1%84%8B%E1%85%AF%E1%84%8F%E1%85%B3%E1%84%87%E1%85%A1%E1%86%A8%E1%84%89%E1%85%B3-cli%E1%84%85%E1%85%A9-%E1%84%89%E1%85%A5%E1%84%87%E1%85%B5%E1%84%89%E1%85%B3-%E1%84%8B%E1%85%AF%E1%84%8F%E1%85%A5-%E1%84%89%E1%85%A2%E1%86%BC%E1%84%89%E1%85%A5%E1%86%BC%E1%84%92%E1%85%A1%E1%84%80%E1%85%B5

โš ๏ธ **GitHub.com Fallback** โš ๏ธ