๐Ÿ„ Angular Hybrid Rendering

@winuss ยท October 27, 2022 ยท 6 min read

์ด์ „ ๊ธ€์—์„œ CSR, SSR, SSG์— ๋Œ€ํ•ด ๊ฐ๊ฐ์˜ ์ฐจ์ด์ ์— ๋Œ€ํ•ด์„œ ๋‹ค๋ค„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค. Angular, React, Vue์—์„œ ๊ฐ๊ฐ์˜ ๋ฐฉ์‹์œผ๋กœ ์ด๋Ÿฌํ•œ ๋ Œ๋”๋ง ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„์„ ํ•  ์ˆ˜๊ฐ€ ์žˆ๋Š”๋ฐ์š”. ๋Œ€ํ‘œ์ ์œผ๋กœ Angular๋Š” Universal, React๋Š” NextJs, Vue๋Š” Nuxt ๋“ฑ์„ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ๊ฐ™๋„ค์š”. Angular๋Š” ๊ตญ๋‚ด์—์„œ ์ธ๊ธฐ๊ฐ€ ๋งŽ์ด ์—†์–ด์„œ์ธ์ง€ ํ•ด๋‹น ๋‚ด์šฉ์„ ๋‹ค๋ฃจ๋Š” ๊ธ€์ด ์—†๋Š”๋“ฏํ•˜์—ฌ ์ด๋ฒˆ ๊ธฐํšŒ์— ์ œ๊ฐ€ ์‚ฌ์šฉ์„ ํ•ด๋ณด๊ณ  ๊ฐ„๋‹จํ•˜๊ฒŒ๋‚˜๋งˆ ์ •๋ฆฌํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ Œ๋”๋ง ์ข…๋ฅ˜์— ๋Œ€ํ•œ ๊ธ€์€ ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ 

๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋ง์”€๋“œ๋ฆฌ๋ฉด ๊ต‰์žฅํžˆ ์‰ฝ์Šต๋‹ˆ๋‹ค!

๋จผ์ € ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ฐœ๋… ์ •๋„๋งŒ ๋‹ค์‹œ ์งš๊ณ  ๋„˜์–ด๊ฐ€๊ฒ ์Šต๋‹ˆ๋‹ค.

PreRendering

์šฐ๋ฆฌ์—๊ฒŒ ๊ฐ€์žฅ ์ต์ˆ™ํ•œ ํด๋ผ์ด์–ธํŠธ ๋ Œ๋”๋ง(CSR) ๋ฐฉ์‹์€ ์ž˜ ์•„์‹ค ํ…Œ๊ณ , ์„œ๋ฒ„์‚ฌ์ด๋“œ ๋ Œ๋”๋ง(SSR)์€ ๊ฐ ํŽ˜์ด์ง€์— ๋Œ€ํ•œ ์š”์ฒญ์„ ๋ฐ›์œผ๋ฉด ๋ธŒ๋ผ์šฐ์ € ์—”์ง„์„ ๋Œ€์‹ ํ•ด์„œ ์„œ๋ฒ„์—์„œ Node๊ฐ€ ๋ Œ๋”๋งํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฌผ์„ ํด๋ผ์ด์–ธํŠธ์—์„œ ์ „๋‹ฌํ•ด์ฃผ๋Š” ๊ฒƒ์ด๊ณ , ์‚ฌ์ „ ๋ Œ๋”๋ง(PreRendering, SSG) ๋ง ๊ทธ๋Œ€๋กœ ๋ฏธ๋ฆฌ ๋ Œ๋”๋ง์„ ํ•ด๋†“๊ณ  ์„œ๋ฒ„์—์„œ ํ•ด๋‹น ํŽ˜์ด์ง€์— ๋Œ€ํ•œ ์š”์ฒญ์ด ์˜ค๋ฉด ๋ฏธ๋ฆฌ ๋ Œ๋”๋งํ•ด๋‘์—ˆ๋˜ ํŽ˜์ด์ง€๋ฅผ ์ „๋‹ฌ!

์ž ์ด์ œ ๋ˆ„๊ตฌ๋„ ์•Œ๋ ค์ฃผ์ง€ ์•Š์•˜๋˜, Angular Universal์„ ์ด์šฉํ•ด ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๋ Œ๋”๋ง์„ ๊ตฌํ˜„ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Universal

hybrid-rendering-app ์ด๋ผ๋Š” ์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  universal package๋ฅผ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.

ng new hybrid-rendering-app

ng add @nguniversal/express-engine

@nguniversal/express-engine์„ ์ถ”๊ฐ€ ํ•ด์ฃผ๋ฉด main.server.ts, app.server.module.ts๊ณผ ๊ฐ™์€ ๋ญ”๊ฐ€ ๋ชป๋ณด๋˜ ํŒŒ์ผ๋“ค์ด ์ƒ๊ฒจ๋‚˜๋Š” ๊ฒƒ์„ ๋ณด์‹ค์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ง€๊ธˆ๊ป ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ์—์„œ ํด๋ผ์ด์–ธํŠธ ๋ Œ๋”๋ง์„ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ, ์ด์ œ ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ์ด ์•„๋‹Œ๊ณณ์—์„œ ๋ Œ๋”๋ง์„ ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— Node๊ฐ€ ์‹คํ–‰ํ•ด์ค„ ํŒŒ์ผ์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

package.json ํŒŒ์ผ์„ ๋ณด๋ฉด ์ฒ˜์Œ ๋ณด๋Š” scripts๋“ค๋„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    "dev:ssr": "ng run hybrid-rendering-app:serve-ssr",
    "serve:ssr": "node dist/hybrid-rendering-app/server/main.js",
    "build:ssr": "ng build && ng run hybrid-rendering-app:server",
    "prerender": "ng run hybrid-rendering-app:prerender"

ํ‚ค๊ฐ’๋ช…์นญ์„ ๋ณด๋ฉด ๋Œ€์ถฉ ์–ด๋–ค๊ฒƒ์„ ํ•˜๋Š”๊ฒƒ์ด๊ฒ ๊ตฌ๋‚˜.. ํ•˜๋Š” ์ •๋„์˜ ๊ฐ์€ ์˜ค์…จ์„ ๊ฒ๋‹ˆ๋‹ค.

๋จผ์ € prerendering์„ ํ•ด๋ณด๊ธฐ ์œ„ํ•ด route ํŽ˜์ด์ง€๊ฐ€ ํ•„์š”ํ•œ๋ฐ, about์™€ contact ๋ชจ๋“ˆ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ๋ผ์šฐํ„ฐ์— ๋“ฑ๋ก ์‹œ์ผœ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฐ๊ฐ์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑํ•ด router์— ๋“ฑ๋กํ•ด๋„ ๋˜์ง€๋งŒ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (Angular ํ”„๋ ˆ์ž„์›์˜ ์žฅ์  ์ด๊ธฐ๋„ ํ•˜์ฃ , ๋ณต์žกํ•ด ๋ณด์ด์ง€๋งŒ ์ฒด๊ณ„์ ์ด๋‹ค? ^^;)

ng g m about --route about --module app

ng g m contact --route contact --module app

Run

๋ฐ”๋กœ ์‚ฌ์ „ ๋ Œ๋”๋ง์„ ํ•ด๋ณด์ฃ !

npm run prerender

01

dist ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋ณด์‹œ๋ฉด server, browser ๋‘๊ฐœ์˜ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ๋‚˜๋ˆ„์–ด์ ธ ์žˆ๋„ค์š”. server/main.js ์ด ํŒŒ์ผ์ด node์—์„œ ์‹คํ–‰ํ•ด์ฃผ๋Š” ํŒŒ์ผ์ด ๋˜๋Š”๊ฒƒ์ด๊ณ ์š”, browser ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด๋ถ€์— ์žˆ๋Š” ํŒŒ์ผ๋“ค์ด ๋ Œ๋”๋ง๋œ ํŒŒ์ผ๋“ค์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ index.html ํŒŒ์ผ๋งŒ ์žˆ๋Š”๊ฒŒ ์•„๋‹ˆ๊ณ  router์— ๋“ฑ๋กํ•œ about, contact์˜ index.htmlํŒŒ์ผ๋„ ๊ฐ๊ฐ์˜ ๋””๋ ‰ํ† ๋ฆฌ์— ์ƒ์„ฑ์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ๊ฐ์˜ ํŽ˜์ด์ง€ ์š”์ฒญ์ด ์˜ค๋ฉด ๋ฏธ๋ฆฌ ๋žœ๋”๋งํ•ด๋‘” index.htmlํŒŒ์ผ์„ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•จ์ด์ฃ .

Options

๊ทธ๋ฆฌ๊ณ  angular.json ํŒŒ์ผ์˜ ์˜ต์…˜์ •๋ณด๋ฅผ ์ด์šฉํ•ด์„œ ์›ํ•˜๋Š” ํŽ˜์ด์ง€๋งŒ ์‚ฌ์ „ ๋ Œ๋”๋ง์„ ํ•ด๋‘˜์ˆ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด about ํŽ˜์ด์ง€๋งŒ ์‚ฌ์ „ ๋ Œ๋”๋ง์„ ํ•ด๋‘๊ณ  ์‹ถ๋‹ค. ๊ทธ๋Ÿผ "guessRoutes": false, "routes" ๋ฐฐ์—ด์— ๋ Œ๋”๋งํ•  ํŽ˜์ด์ง€๋งŒ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.

projects > hybrid-rendering-app > architect > prerender

"options" : {
  "guessRoutes": false,
  "routes": [
    "/about"
  ]
}

"routesFile": "./routes.txt" ํŒŒ์ผ์— ๊ฒฝ๋กœ๋“ค์„ ์„ค์ •ํ• ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋” ์ž์„ธํ•œ options ์ •๋ณด๋Š” ์—ฌ๊ธฐ์—์„œ ํ™•์ธํ•ด ์ฃผ์„ธ์š”

์ด์ œ node๋กœ ํ•ด๋‹น jsํŒŒ์ผ์„ ์‹คํ–‰ํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

Server Start

node dist\hybrid-rendering-app\server\main.js

Node Express server listening on http://localhost:4000

์„œ๋ฒ„๋ฅผ ๊ตฌ๋™ํ•ด์ฃผ๊ณ  ๋ธŒ๋ผ์šฐ์ €์— ์ ‘์†ํ•ด์„œ Network ํƒญ์„ ์‚ดํŽด ๋ณด๋ฉด ๊ฐ ๋ผ์šฐํŒ…์— ์ ‘๊ทผํ•  ๋•Œ๋งˆ๋‹ค ํ•ด๋‹น ๋ฌธ์„œ๋ฅผ ๋‹ค์šด๋ฐ›๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

main main

about about

contact contact

์ตœ์ดˆ ์ ‘์†์‹œ index.html ํŒŒ์ผ์„ ๋ฐ›์•„ ๊ทธ์•ˆ์—์„œ javascript ํŒŒ์ผ์— ์˜ํ•ด ๋™์ ์œผ๋กœ ๋ฌธ์„œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” SPA๋ฐฉ์‹๊ณผ๋Š” ๋‹ฌ๋ฆฌ ๋ผ์šฐํ„ฐ ์ ‘๊ทผ์‹œ ์‚ฌ์ „์— ๋ Œ๋”๋ง๋œ ๋ฌธ์„œ๋ฅผ ์„œ๋ฒ„์—์„œ ์ „๋‹ฌํ•ด์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ฑฐ์˜ ๋ณ€๊ฒฝ์ด ์—†๋Š” ํŽ˜์ด์ง€๋“ค์˜ ๊ฒฝ์šฐ ์ด๋ ‡๊ฒŒ ์‚ฌ์ „์— ๋ Œ๋”๋ง์„ ํ•ด๋‘๋ฉด ์„ฑ๋Šฅ์ ์ธ ๋ถ€๋ถ„์—์„œ ๋งค์šฐ ํšจํœผ์ ์ผ ๊ฒƒ์ด์ง€๋งŒ, ํŽ˜์ด์ง€ ๋‚ด์šฉ์ด ์ž์ฃผ ๋ณ€๊ฒฝ์ด ๋œ๋‹ค๊ฑฐ๋‚˜ ๊ฒŒ์‹œํŒ ๊ฐ™์€ ๋™์ ์ธ ๋ผ์šฐํŒ…์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, options์— ๋ Œ๋”๋งํ•  ํŽ˜์ด์ง€๋งŒ ๋ช…์‹œํ•ด์ฃผ๋ฉด ์„ ํƒ์ ์œผ๋กœ ์‚ฌ์ „ ๋ Œ๋”๋ง์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋Š” ๊ฒƒ ์ž…๋‹ˆ๋‹ค.

@winuss
Hello :) Developer notes!