Frontend ๐Ÿ“š/React

[์ฝ”๋”ฉ์• ํ”Œ] ์‡ผํ•‘๋ชฐ ํ”„๋กœ์ ํŠธ Part11 - PWA ์…‹ํŒ…

leejaejae 2023. 11. 1. 00:01

โœ๏ธ PWA๋ž€

- ๊ตฌ๊ธ€์—์„œ ๋ฐ€๊ณ  ์žˆ๋Š” Progressive Web App์ด๋ผ๋Š”๊ฑด๋ฐ ์ด๊ฑด ์›น์‚ฌ์ดํŠธ๋ฅผ ์•ˆ๋“œ๋กœ์ด๋“œ/iOS ๋ชจ๋ฐ”์ผ ์•ฑ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“œ๋Š” ์ผ์ข…์˜ ์›น๊ฐœ๋ฐœ ๊ธฐ์ˆ ์ด๋‹ค.
- ๊ทผ๋ฐ iOS, Android ์•ฑ์œผ๋กœ ๋ฐœํ–‰ํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์›น์‚ฌ์ดํŠธ ์ž์ฒด๋ฅผ ์Šค๋งˆํŠธํฐ ํ™ˆํ™”๋ฉด์— ์„ค์น˜ํ•œ๋‹ค.


โœ๏ธ ์›น์‚ฌ์ดํŠธ๋ฅผ PWAํ™” ์‹œํ‚ค๋Š”๊ฒŒ ๋ญ๊ฐ€ ์ข‹๋ƒ๋ฉด

1. ์Šค๋งˆํŠธํฐ, ํƒœ๋ธ”๋ฆฟ ๋ฐ”ํƒ•ํ™”๋ฉด์— ์›น์‚ฌ์ดํŠธ ์„ค์น˜ ๊ฐ€๋Šฅ.
2. ์˜คํ”„๋ผ์ธ์—์„œ๋„ ๋™์ž‘ ๊ฐ€๋Šฅ.
- service-worker.js ๋ผ๋Š” ํŒŒ์ผ๊ณผ ๋ธŒ๋ผ์šฐ์ €์˜ Cache storage ๋•๋ถ„
3. ์„ค์น˜ ์œ ๋„ ๋น„์šฉ์ด ๋งค์šฐ ์ ์Œ.
- ์›น์‚ฌ์ดํŠธ ๋ฐฉ๋ฌธ์ž๋“ค์—๊ฒŒ ๊ฐ„๋‹จํ•œ ํŒ์—…์„ ๋„์›Œ์„œ ์„ค์น˜์œ ๋„ํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ํ›จ์”ฌ ์ ์€ ๋งˆ์ผ€ํŒ… ๋น„์šฉ


โœ๏ธ PWA ๋ฐœํ–‰ํ•˜๋Š” ๋ฒ•

- ๊ทธ๋ƒฅ ์•„๋ฌด ์‚ฌ์ดํŠธ๋‚˜ ํŒŒ์ผ 2๊ฐœ๋งŒ ์‚ฌ์ดํŠธ ๋กœ์ปฌ ๊ฒฝ๋กœ์— ์žˆ์œผ๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ PWA๋กœ ์ธ์‹ํ•จ(๊ทธ๋ฆฌ๊ณ  HTTPS ์‚ฌ์ดํŠธ์—ฌ์•ผํ•จ!)
- manifest.json๊ณผ service-worker.js๋ผ๋Š” ์ด๋ฆ„์˜ ํŒŒ์ผ ๋‘๊ฐœ๋ฅผ ๋งŒ๋“ค๋ฉด ๋œ๋‹ค.

- ํ•˜์ง€๋งŒ ๊ธฐ๋ณธ ํ”„๋กœ์ ํŠธ๋ฅผ npm build/yarn build ํ–ˆ์„ ๊ฒฝ์šฐ manifest.json ํŒŒ์ผ๋งŒ ์ƒ์„ฑํ•ด์ค€๋‹ค.
- service-worker.js๊นŒ์ง€ ์ž๋™์œผ๋กœ ์ƒ์„ฑ์„ ์›ํ•œ๋‹ค๋ฉด ํ”„๋กœ์ ํŠธ๋ฅผ ์ฒ˜์Œ ๋งŒ๋“ค ๋•Œ ์•„๋ž˜์™€ ๊ฐ™์ด ํ„ฐ๋ฏธ๋„์— ์ž…๋ ฅํ•œ๋‹ค.

npx create-react-app ํ”„๋กœ์ ํŠธ๋ช… --template cra-template-pwa

- ์ฆ‰, ํ”„๋กœ์ ํŠธ๋ฅผ ๋‹ค์‹œ ๋งŒ๋“œ๋Š” ๊ฒƒ!
   1. ๋‹ค๋ฅธ ํดํ„ฐ์— ์œ„ ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•ด ํ”„๋กœ์ ํŠธ ์ƒˆ๋กœ ํ•˜๋‚˜ ๋งŒ๋“  ๋‹ค์Œ์—
   2. ๊ธฐ์กด ํ”„๋กœ์ ํŠธ์˜ App.js App.css index.js ์ด๋Ÿฐ ํŒŒ์ผ๋“ค์„ ์ƒˆ ํ”„๋กœ์ ํŠธ๋กœ ๋ณต๋ถ™ํ•˜๋ฉด ๋œ๋‹ค.(๋‚ด๊ฐ€ ๊ฑด๋“  ํŒŒ์ผ์€ ์ „๋ถ€!)
   3. router, redux ์ด๋Ÿฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜ํ–ˆ๋‹ค๋ฉด ๊ทธ๊ฒƒ๋„ ์ƒˆํ”„๋กœ์ ํŠธ์— ๋‹ค์‹œ ์„ค์น˜

- ๊ทธ๋ฆฌ๊ณ  ํŒŒ์ผ๋“ค ์ค‘์— index.js ํ•˜๋‹จ์„ ์ˆ˜์ •ํ•œ๋‹ค.

// serviceWorkerRegistration.unregister();
// ↓

serviceWorkerRegistration.register();

- ๊ทธ๋Ÿผ ์ด์ œ yarn build/npm run build ํ–ˆ์„ ๋•Œ manifest.json๊ณผ service-worker.js ํŒŒ์ผ์ด ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋œ๋‹ค.


โœ๏ธ manifest.json / service-worker.js ํŒŒ์ผ ์‚ดํŽด๋ณด๊ธฐ

- build ํ•˜๊ณ  ๋‚˜์‹œ๋ฉด build ํด๋” ๋‚ด์— ์ด ํŒŒ์ผ๋“ค์ด ์žˆ์„ ๊ฑฐ๋‹ค.

- manifest.json ํŒŒ์ผ์€ ์›น์•ฑ์˜ ์•„์ด์ฝ˜, ์ด๋ฆ„, ํ…Œ๋งˆ์ƒ‰ ์ด๋Ÿฐ๊ฑธ ๊ฒฐ์ •ํ•˜๋Š” ๋ถ€๋ถ„์ด๋ผ๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.
- ๊ทธ ์•ˆ์— ๋“ค์–ด๊ฐ€๋Š” ๋‚ด์šฉ๋“ค์€ ๋Œ€๋žต ์•„๋ž˜์™€ ๊ฐ™๋‹ค

{
  "version" : "์—ฌ๋Ÿฌ๋ถ„์•ฑ์˜ ๋ฒ„์ „.. ์˜ˆ๋ฅผ ๋“ค๋ฉด 1.12 ์ด๋Ÿฐ๊ฑฐ",
  "short_name" : "์„ค์น˜ํ›„ ์•ฑ๋Ÿฐ์ฒ˜๋‚˜ ๋ฐ”ํƒ•ํ™”๋ฉด์— ํ‘œ์‹œํ•  ์งง์€ 12์ž ์ด๋ฆ„",
  "name" : "๊ธฐ๋ณธ์ด๋ฆ„",
  "icons" : { ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์‚ฌ์ด์ฆˆ๋ณ„ ์•„์ด์ฝ˜ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ },
  "start_url" : "์•ฑ์•„์ด์ฝ˜ ๋ˆŒ๋ €์„ ์‹œ ๋ณด์—ฌ์ค„ ๋ฉ”์ธํŽ˜์ด์ง€ ๊ฒฝ๋กœ",
  "display" : "standalone ์•„๋‹ˆ๋ฉด fullscreen",
  "background_color" : "์•ฑ ์ฒ˜์Œ ์‹คํ–‰์‹œ ์ž ๊น ๋œจ๋Š” splashscreen์˜ ๋ฐฐ๊ฒฝ์ƒ‰",
  "theme_color" : "์ƒ๋‹จ ํƒญ์ƒ‰์ƒ ๋“ฑ ์›ํ•˜๋Š” ํ…Œ๋งˆ์ƒ‰์ƒ",
}


- service-worker.js ํŒŒ์ผ์€ ์˜ˆ๋ฅผ ๋“ค์–ด ์นด์นด์˜คํ†ก ์•ฑ๊ฐ™์€๊ฑฐ ์„ค์น˜ํ•  ๋•Œ ๊ตฌ๊ธ€ํ”Œ๋ ˆ์ด ์Šคํ† ์–ด ๊ฐ€์„œ ์„ค์น˜ํ•˜๋ฉด ๊ทธ๋Ÿผ ์นดํ†ก ๊ตฌ๋™์— ํ•„์š”ํ•œ ์ด๋ฏธ์ง€, ๋ฐ์ดํ„ฐ๋“ค์ด ์ „๋ถ€ ํ•˜๋“œ์— ์„ค์น˜๋œ๋‹ค.
- ๊ทธ๋ฆฌ๊ณ  ์นดํ†ก์„ ์ผœ๋ฉด ์นดํ†ก ๋กœ๊ณ  ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ์นดํ†ก ์„œ๋ฒ„์— ์š”์ฒญํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ํ•˜๋“œ์— ์ด๋ฏธ ์„ค์น˜๋˜์–ด ์žˆ๋Š”๊ฑธ ๊ทธ๋Œ€๋กœ ๊ฐ€์ ธ์™€์„œ ์“ด๋‹ค.

- ์ด๊ฑธ ํ‰๋‚ด๋‚ด๋„๋ก ๋„์™€์ฃผ๋Š” ํŒŒ์ผ์ด ๋ฐ”๋กœ service-worker ๋ผ๋Š” ํŒŒ์ผ์ด๋‹ค.
- ์ด ํŒŒ์ผ์— ์„ค์ •์„ ์ž˜ ํ•ด์ฃผ๋ฉด ์ด์ œ ์›น์•ฑ์„ ์„ค์น˜ํ–ˆ์„ ๋•Œ ์–ด๋–ค CSS, JS, HTML, ์ด๋ฏธ์ง€ ํŒŒ์ผ์ด ํ•˜๋“œ์— ์„ค์น˜๋ ์ง€ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

- ๊ทธ๋Ÿผ ์ด์ œ ๋‹ค์Œ์— ์•ฑ์„ ์ผค ๋•Œ๋งˆ๋‹ค ์„œ๋ฒ„์— CSS,JS,HTML ํŒŒ์ผ์„ ์š”์ฒญํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ Cache Storage์— ์ €์žฅ๋˜์–ด์žˆ๋˜ CSS,JS,HTML ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ๋‹ค.(๊ทธ๋Ÿผ ์ด์ œ ์˜คํ”„๋ผ์ธ์—์„œ๋„ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅ!)


โœ๏ธ ๊ฐœ๋ฐœ์ž๋„๊ตฌ๋กœ PWA ๋””๋ฒ„๊น…ํ•˜๊ธฐ

- ๋‚ด๊ฐ€ build ํ–ˆ๋˜ ํ”„๋กœ์ ํŠธ๊ฐ€ PWA์ธ์ง€ ์•„๋‹Œ์ง€ ์‚ดํŽด๋ณด๊ณ  ์‹ถ์œผ๋ฉด ์ผ๋‹จ ์‚ฌ์ดํŠธ๋ฅผ ํ˜ธ์ŠคํŒ…๋ฐ›์•„ ์˜ฌ๋ฆฌ๊ฑฐ๋‚˜ (Github pages ์ด๋Ÿฐ ๊ฒƒ๋„ ๋จ)
- VScode ์ต์Šคํ…์…˜์ค‘์— live server ์ด๊ฑธ ๊ฒ€์ƒ‰ํ•ด์„œ ์„ค์น˜ํ•œ ๋’ค
   1. build ํด๋”๋ฅผ ์—๋””ํ„ฐ๋กœ ์˜คํ”ˆํ•˜๊ณ 
   2. ๊ฑฐ๊ธฐ ์žˆ๋Š” index.htmldmf ์šฐํด๋ฆญ-live server๋กœ ๋„์šฐ๊ธฐ ๋ˆ„๋ฅด๋ฉด ๋จ

- ๋‚˜์˜ ์‚ฌ์ดํŠธ์—์„œ ํฌ๋กฌ ๊ฐœ๋ฐœ์ž๋„๊ตฌ๋ฅผ ํ‚ค๋ฉด Application์ด๋ผ๋Š” ํƒญ์ด ์žˆ๋‹ค. ์—ฌ๊ธฐ ๋“ค์–ด๊ฐ€๋ฉด PWA์™€ ๊ด€๋ จ๋œ ๋ชจ๋“  ๊ฑธ ์‚ดํŽด ๋ณผ ์ˆ˜ ์žˆ๋‹ค. (๋‚ด ์‚ฌ์ดํŠธ ์—†์œผ๋ฉด flipkart.com ์ด๋Ÿฐ PWA ์‚ฌ์ดํŠธ ๋“ค์–ด๊ฐ€์„œ ๋”ฐ๋ผํ•ด๋„ ๋จ)

- Manifest ๋ฉ”๋‰ด์—์„  manifest.json ๋‚ด์šฉ๋“ค์„ ํ™•์ธ๊ฐ€๋Šฅํ•˜๊ณ 
- Service Worker ๋ฉ”๋‰ด์—์„  service-worker ํŒŒ์ผ์ด ์ž˜ ์žˆ๋Š”์ง€, ์˜คํ”„๋ผ์ธ์—์„  ์ž˜ ๋™์ž‘ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•˜๊ณ  ํ‘ธ์‹œ์•Œ๋ฆผ ๊ธฐ๋Šฅ์„ ๊ฐœ๋ฐœํ•ด๋†จ๋‹ค๋ฉด ํ‘ธ์‹œ์•Œ๋ฆผ๋„ ์ƒ˜ํ”Œ๋กœ ์ „์†กํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.
- Cache Storage ๋ฉ”๋‰ด์—์„  service-worker ๋•๋ถ„์— ํ•˜๋“œ์— ์„ค์น˜๋œ CSS, JS, HTML ํŒŒ์ผ๋“ค์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์บ์‹œ๋œ ํŒŒ์ผ ์ œ๊ฑฐ๋„ ๊ฐ€๋Šฅ.


โœ๏ธ ๋‚˜์˜ PWA๋ฅผ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•˜๋ ค๋ฉด

- ์ง€๊ธˆ PWA ๋ฐœํ–‰์ด ์‰ฝ๊ณ  ๊ฐ„๋‹จํ•œ ์ด์œ ๋Š” ๊ตฌ๊ธ€์˜ workbox ๋ผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋•๋ถ„์ธ๋ฐ
- ์ด๊ฒŒ create-react-app ์„ค์น˜ํ•  ๋•Œ ํ•จ๊ป˜ ์„ค์น˜๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
- ๊ทธ๋ž˜์„œ PWA ๋ฐœํ–‰๋ฐฉ์‹ ๊ฐ™์€๊ฑธ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ํ•˜๊ณ ์‹ถ์œผ๋ฉด workbox ์‚ฌ์šฉ๋ฒ•์„ ์ตํ˜€์•ผ ํ•˜๋Š”๋ฐ ๊ตฌ๊ธ€์˜ ๊ฐœ๋ฐœ๋ฌธ์„œ๋Š” ์กฐ๊ธˆ ์–ด๋ ต๋‹ค.

- ๊ทธ๋ž˜์„œ ๋น ๋ฅด๊ฒŒ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ๋ฐฉ๋ฒ•์œผ๋ก  
Q) ๋งŒ์•ฝ ํ•˜๋“œ์— ์„ค์น˜ํ•  ํŒŒ์ผ ์ค‘์— HTML์„ ์ œ์™ธํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด?
- ๋‚˜์˜ ํ”„๋กœ์ ํŠธ ํด๋” ๋‚ด์˜ node_modules/react-scripts/config/webpack.config.js ํŒŒ์ผ์„ ์ฐพ์•„์„œ ํ•˜๋‹จ์„ ๋ณด๋ฉด

// ๊ตฌ๋ฒ„์ „
new WorkboxWebpackPlugin.GenerateSW({
    clientsClaim: true,
    exclude: [/\.map$/, /asset-manifest\.json$/],
}) 

// ์‹ ๋ฒ„์ „
new WorkboxWebpackPlugin.InjectManifest({
    swSrc,
    dontCacheBustURLsMatching: /\.[0-9a-f]{8}\./,
    exclude: [/\.map$/, /asset-manifest\.json$/, /LICENSE/],

- ์—ฌ๊ธฐ์˜ exclude๋ผ๋Š” ํ•ญ๋ชฉ์ด ์–ด๋–ค ํŒŒ์ผ์„ ์บ์‹ฑํ•˜์ง€ ์•Š์„๊ฑด์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๋ถ€๋ถ„์ด๋‹ค.
- ์ •๊ทœ์‹์œผ๋กœ ์ž‘์„ฑํ•˜๋Š”๋ฐ ์ •๊ทœ์‹๊ณผ ์ผ์น˜ํ•˜๋Š” ํŒŒ์ผ๋ช…์„ ์ œ์™ธํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ์›ํ•˜๋Š” HTML ํŒŒ์ผ์„ ์—ฌ๊ธฐ ๋“ฑ๋กํ•˜๋ฉด ๋œ๋‹ค.

new WorkboxWebpackPlugin.GenerateSW({
    clientsClaim: true,
    exclude: [/\.map$/, /asset-manifest\.json$/, /index\.html/],
})

- ์ด๊ฑฐ ๋ง๊ณ ๋„ "๋ชจ๋“  .css๋กœ ๋๋‚˜๋Š” ํŒŒ์ผ" "a๋ผ๋Š” ๊ธ€์ž๋กœ ์‹œ์ž‘ํ•˜๋Š” ํŒŒ์ผ" ์ด๋Ÿฐ ์‹์œผ๋กœ ์ •๊ทœ์‹์œผ๋กœ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ๋Š”๋ฐ ๊ทธ๊ฒƒ์€ ์ •๊ทœ์‹ ๋ฌธ๋ฒ•์—์„œ ์ฐพ์•„๋ณด๋ฉด ๋œ๋‹ค.

- ๊ทผ๋ฐ ๋งŒ์•ฝ ๋‚˜์˜ ์‚ฌ์ดํŠธ๊ฐ€ ์œ ํŠœ๋ธŒ๋‚˜ ์ธ์Šคํƒ€๊ทธ๋žจ์ฒ˜๋Ÿผ ์ž…์žฅ๊ณผ ๋™์‹œ์— Ajax๋กœ ์ดˆ๊ธฐ๋ฐ์ดํ„ฐ๋“ค์„ ์ „๋ถ€ ๋ฐ›์•„์˜ค๋Š” ์‚ฌ์ดํŠธ๋ผ๋ฉด ๊ตณ์ด HTML์„ ์ˆ˜์ •ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.
 


๋ณธ ํฌ์ŠคํŒ…์€ << React ๋ฆฌ์•กํŠธ ๊ธฐ์ดˆ๋ถ€ํ„ฐ ์‡ผํ•‘๋ชฐ ํ”„๋กœ์ ํŠธ๊นŒ์ง€! >> ๊ฐ•์˜๋ฅผ ์ฐธ๊ณ ํ•ฉ๋‹ˆ๋‹ค.