๐Ÿ’ป 2024๋…„ ํ•˜๋ฐ˜๊ธฐ ๊ณต์œ 

1. import๋กœ ์ธํ•œ ์ˆœํ™˜ ์ฐธ์กฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•

Intro

ํ”„๋กœ์ ํŠธ ๊ทœ๋ชจ๊ฐ€ ์ ์ฐจ ์ปค์งˆ์ˆ˜๋ก ๋ถ„๋ฆฌ๋˜๋Š” ํŒŒ์ผ๋“ค๋„ ๋Š˜์–ด๋‚˜๊ณ  import export ๊ด€๊ณ„๊ฐ€ ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ ์–ด๋–ค ํ•œ ํŒŒ์ผ์— ๋‹ค๋ฅธ ํŒŒ์ผ์ด ์„œ๋กœ ์ฐธ์กฐํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹ค์ œ๋กœ ํ”„๋กœ์ ํŠธ์—์„œ๋„ ์ €๋Š” ์ •๋ง ๊ฐ€๋”์”ฉ import ๋˜๋Š” ๋ชจ๋“ˆ ํŒŒ์ผ์„ ์ธ์‹ํ•˜์ง€ ๋ชปํ•ด ์•Œ ์ˆ˜ ์—†๋Š” ๋นจ๊ฐ„์ค„ ์—๋Ÿฌ๊ฐ€ ๋œฌ ์ ์ด ์žˆ๋Š”๋ฐ, โ€˜์ˆœํ™˜ ์ฐธ์กฐ (circular dependency) ๋ฌธ์ œโ€™ ์™€ ์—ฐ๊ด€์ด ์žˆ์„์ˆ˜๋„ ์žˆ๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์ˆœํ™˜ ์ฐธ์กฐ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ธ์‹ํ•˜๊ณ  ์ˆœํ™˜ ์ฐธ์กฐ๋ฅผ ํ•ด๊ฒฐ/์˜ˆ๋ฐฉํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ„๋‹จํ•œ ํŒจํ„ด๋“ค์„ ์†Œ๊ฐœํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ˆœํ™˜ ์ฐธ์กฐ๋ž€?

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ˆœํ™˜ ์ฐธ์กฐ๋ฅผ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ˆœํ™˜ ์ฐธ์กฐ๋ž€ ์„œ๋กœ๊ฐ€ ์„œ๋กœ๋ฅผ ์ฐธ์กฐํ•˜๋Š” ์ƒํƒœ๋ฅผ ์ด์•ผ๊ธฐํ•ฉ๋‹ˆ๋‹ค. JS ์—์„œ๋Š” ์ด๋ฅผ ์‹œ์Šคํ…œ์—์„œ ๊ฑธ๋Ÿฌ๋‚ด์ง€ ์•Š๊ณ , ํ•œ์ชฝ์˜ export ๋ฅผ ๋นˆ ๊ฐ์ฒด๋กœ ๋งŒ๋“ค์–ด ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค.

์•„๋ž˜ ์˜ˆ์‹œ๋Š” ์ˆœํ™˜ ์ฐธ์กฐ์˜ ๋Œ€ํ‘œ์  ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

// index.js
import "./a.js";

// a.js
import { sayHello } from "./b.js";

export const NAME = "mike";

console.log("module_a");
sayHello();

// b.js
import { NAME } from "./a.js";

console.log("module_b");

export const sayHello = () => {
  console.log("hello~!", NAME);
};

์—ฌ๊ธฐ์„œ b.js ์—์„œ sayHello() ํ•จ์ˆ˜๋ฅผ ์ฝ๋Š” ํ˜•ํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

export const sayHello = () => {
  console.log("hello~!", aModuleObject.Name);
};

NAME ์„ a ๋ชจ๋“ˆ์˜ ๊ฐ์ฒด๋ผ๊ณ  ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์ด์œ ๋Š” a.js ์—์„œ NAME ๋ณ€์ˆ˜๋ฅผ ๋‚ด๋ณด๋‚ด๋Š” ์‹œ์ ์ด sayHello() ํ˜ธ์ถœ๋ถ€ ์ด์ „ ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋งŒ์•ฝ NAME ๋ณ€์ˆ˜ ๋‚ด๋ณด๋‚ด๋Š” ์‹œ์ ์„ sayHello() ํ˜ธ์ถœ๋ถ€ ์ดํ›„๋กœ ๋ณด๋‚ด๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋“ค์ด ๊ฒน์น˜๊ฒŒ ๋˜๋ฉด, ์ˆœํ™˜ ์ฐธ์กฐ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๊ฒŒ ๋œ๋‹ค๊ณ  ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

์ˆœํ™˜ ์ฐธ์กฐ์—์„œ ๋ฌธ์ œ๊ฐ€ ๋‚ฌ์„๋•Œ ์•Œ์•„์ฐจ๋ฆฌ๊ธฐ ํž˜๋“  ์ด์œ 

  • ESM ์—์„œ๋Š” ๋ชจ๋“ˆ์—์„œ ์—†๋Š” ์†์„ฑ์„ ๊ฐ€์ ธ์˜ฌ๋•Œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. โ‡’ ๋ช…์‹œ์ ์œผ๋กœ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ˆœํ™˜ ์ฐธ์กฐ ์˜ค๋ฅ˜๋ฅผ ๋น ๋ฅด๊ฒŒ ์ธ์‹ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • commonJS ์—์„œ๋Š” ๋ชจ๋“ˆ์—์„œ ์—†๋Š” ์†์„ฑ์„ ๊ฐ€์ ธ์˜ค๋ฉด ์ผ๋ฐ˜์ ์ธ ๊ฐ์ฒด์ฒ˜๋Ÿผ undefined๊ฐ€ ๋ฐ˜ํ™˜๋˜๊ณ  ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. โ‡’ ์ˆœํ™˜ ์ฐธ์กฐ ๋ฌธ์ œ๋ฅผ ์‰ฝ๊ฒŒ ์•Œ์•„์ฐจ๋ฆฌ์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. (commonJS์„ ์‚ฌ์šฉํ•˜๋Š” ์›นํŒฉ์˜ ๊ฒฝ์šฐ ์ˆœํ™˜ ์ฐธ์กฐ ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ•˜๊ธฐ ํž˜๋“ญ๋‹ˆ๋‹ค.)

๊ฐ€์žฅ ๋ช…์‹œ์ ์ธ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• - ๋‚ด๋ถ€ ๋ชจ๋“ˆ ํŒจํ„ด(Internal module pattern)

๊ฐ€์žฅ ๋ช…์‹œ์ ์ธ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ๋ชจ๋“ˆ์˜ ํ‰๊ฐ€ ์ˆœ์„œ๋ฅผ ๋‚ด๋ถ€์ ์œผ๋กœ ์ •์˜ํ•˜๋Š” ํŒŒ์ผ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ ์ž…๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ, ๋ชจ๋“ˆ์„ ๊ฐ€์ ธ์˜ฌ๋•Œ ํ•ญ์ƒ ๊ทธ ํŒŒ์ผ๋กœ๋ถ€ํ„ฐ ๊ฐ€์ ธ์˜ค๋Š” ํ˜•ํƒœ๋ฅผ ๊ฐ–์ถ”๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

ํ•ต์‹ฌ์€ ๋‹ค๋ฅธ ๋ชจ๋“ˆ๋“ค์„ ์ง์ ‘์ ์œผ๋กœ ๋ถˆ๋Ÿฌ์˜ค์ง€ ์•Š๋„๋ก ํ•˜๋Š” ๊ฒƒ ์ž…๋‹ˆ๋‹ค.

์œ„์˜ ์˜ˆ์‹œ์˜ ๋ชจ๋“ˆ์„์˜ ์ˆœ์„œ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด modules.js ํŒŒ์ผ์— ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// modules.js
export * from "./b.js";
export * from "./a.js";

๋ชจ๋“ˆ ํ˜ธ์ถœ๋ถ€๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‹ฌ๋ผ์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

//index.js
import { NAME, sayHello } from "./modules.js";
//a.js
import { sayHello } from "./modules.js";
//b.js
import { NAME } from "./modules.js";

์š”์•ฝ

  • ์ˆœํ™˜ ์ฐธ์กฐ๋Š” ์„œ๋กœ๊ฐ€ ์„œ๋กœ๋ฅผ ์ฐธ์กฐํ•˜๋Š” ํ˜•ํƒœ์ž…๋‹ˆ๋‹ค. (a๋ชจ๋“ˆ โ†” b๋ชจ๋“ˆ)
  • ์ˆœํ™˜ ์ฐธ์กฐ๋Š” CommonJS ํ™˜๊ฒฝ์—์„œ ์‰ฝ๊ฒŒ ๋ฐœ๊ฒฌํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.
  • ๋‚ด๋ถ€์ ์œผ๋กœ ๋ชจ๋“ˆ ํ‰๊ฐ€ ์ˆœ์„œ๋ฅผ ์ •์˜ํ•˜๋Š” ํŒŒ์ผ์„ ๋”ฐ๋กœ ๋งŒ๋“ค์–ด ์ˆœํ™˜ ์ฐธ์กฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

--

2. Cache-Control, Expires๋ฅผ ๋น ๋œจ๋ฆฌ๋ฉด ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚ ๊นŒ?

http ์บ์‹œ๋ฅผ ์ ๊ทน์ ์œผ๋กœ ์„ค์ •ํ•˜๊ณ  ์ œ์–ดํ•จ์œผ๋กœ์จ ์›น ์„ฑ๋Šฅ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์ด ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ์šฐ๋ฆฌ ํ”„๋ก ํŠธ์—”๋“œ ํŠธ๋ž™์—์„œ ์บ์‹œ ์„ค์ •์„ ์ง์ ‘ ๋‹ค๋ฃจ์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€๋งŒ ์•ž์œผ๋กœ์˜ ์›น ์„ฑ๋Šฅ๊ณผ ์ดํ•ด๋ฅผ ์œ„ํ•ด ๋‹ค์–‘ํ•œ ์ƒ๋ช… ์ฃผ๊ธฐ๋ฅผ ๊ฐ€์ง€๋Š” ์บ์‹œ๋ฅผ ๋‹ค๋ฃจ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•„๋Š”๊ฒƒ์€ ๊ผญ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ๋ธŒ๋ผ์šฐ์ € ์บ์‹œ ๊ด€๋ จ ํ—ค๋”์ธ Cache-Control , Exprires ๋ฅผ ๋น ๋œจ๋ฆฌ๋ฉด ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๋Š”์ง€, ๋˜ํ•œ ๋ธŒ๋ผ์šฐ์ € ์บ์‹œ ์„ค์ •์ด ์™œ ์ค‘์š”ํ•œ์ง€ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์›น ์บ์‹œ

  • ์‹ค์ œ ์ž‘์—…์„ ํ•˜๋ฉฐ ๋นŒ๋“œ๋œ ์‚ฌํ•ญ์ด ์ ์šฉ์ด ์•ˆ๋ ๋•Œ ์บ์‹œ ์‚ญ์ œํ•ด๋ผ ๊ฐ•ํ•œ ์ƒˆ๋กœ๊ณ ์นจ ํ•ด๋ผ ๋“ฑ๋“ฑ์˜ ๋ง์„ ๋“ค์€ ์ ์ด ์žˆ์„ ๊ฒ๋‹ˆ๋‹ค.(cc. ์ตœ์›๋นˆ๋‹˜) ์ด๊ฒƒ๋“ค๋„ ๋ธŒ๋ผ์šฐ์ € ์บ์‹œ์™€ ๊ด€๋ จ๋œ ์‚ฌํ•ญ์ด๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ์ฃ .
  • ํด๋ผ์ด์–ธํŠธ๋Š” ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ HTTP ์š”์ฒญ์„ ํ†ตํ•ด ํ•„์š”ํ•œ ๋ฆฌ์†Œ์Šค (HTML, CSS, JS, ์ด๋ฏธ์ง€ ๋“ฑ)๋ฅผ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค. ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ์ด ๊ณผ์ •์„ ์ˆ˜ํ–‰ํ•˜๋Š”๊ฑด ๋А๋ฆฌ๊ณ  ๋น„์šฉ์ด ๋งŽ์ด ๋“ญ๋‹ˆ๋‹ค.
  • ์—ฌ๊ธฐ์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ถˆํ•„์š”ํ•œ ๋„คํŠธ์›Œํฌ ์žฌ์š”์ฒญ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์›น ์บ์‹ฑ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • Cache-Control Expries ๋“ฑ๊ณผ ๊ฐ™์€ ์šฐ๋ฆฌ๊ฐ€ ์ž์ฃผ ๋ด์˜จ ํ—ค๋”๋Š” ์บ์‹œ ๋™์ž‘๊ณผ ๊ด€๋ จ๋œ ํ—ค๋”๋กœ, ์„œ๋ฒ„์˜ ๋น„์šฉ์„ ์ค„์ด๊ณ  ํด๋ผ์ด์–ธํŠธ์˜ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ๋ฐ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

Cache-Control, Expires ํ—ค๋”๋ฅผ ๊ธฐ์ž…ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ

  • ๋ˆ„๊ตฐ๊ฐ€ ์˜๋„ํ–ˆ๋“  ์˜๋„ํ•˜์ง€ ์•Š์•˜๋“  Cache-Control Expires ํ—ค๋” ๋ชจ๋‘ ๊ธฐ์ž…ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ, ๋ธŒ๋ผ์šฐ์ €๋Š” ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ• ๊นŒ์š”?
  • ๋Œ€ํ‘œ์ ์ธ ๋ธŒ๋ผ์šฐ์ €์ธ ํฌ๋กฌ์˜ ์บ์‹œ ๋™์ž‘์„ ์‚ดํŽด๋ณด๊ธฐ ์œ„ํ•ด Chromium์˜ ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.
HttpResponseHeaders::GetFreshnessLifetimes(const Time& response_time) const {
  FreshnessLifetimes lifetimes;
  if (HasHeaderValue("cache-control", "no-cache") ||
      HasHeaderValue("cache-control", "no-store") ||
      HasHeaderValue("pragma", "no-cache")) {
    return lifetimes;
  }
...
if ((response_code_ == net::HTTP_OK ||
       response_code_ == net::HTTP_NON_AUTHORITATIVE_INFORMATION ||
       response_code_ == net::HTTP_PARTIAL_CONTENT) &&
      !must_revalidate) {
    // TODO(darin): Implement a smarter heuristic.
    Time last_modified_value;
    if (GetLastModifiedValue(&last_modified_value)) {
      // The last-modified value can be a date in the future!
      if (last_modified_value <= date_value) {
        lifetimes.freshness = (date_value - last_modified_value) / 10; //์—ฌ๊ธฐ!
        return lifetimes;
      }
    }
  }
  • Chromium์˜ http_response_headers.cc ๋ฅผ ์‚ดํŽด๋ณด๋‹ˆ freshness(์œ ํšจ์„ฑ)์ด (date_value - last_modfied_value) / 10 ๋กœ ํ• ๋‹น๋˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
  • ์ด๋Š” Date์™€ LastModified์˜ ์ฐจ์ด๊ฐ’์˜ 10๋ถ„์˜ 1๋กœ ์ถ”์ •ํ•˜์—ฌ ์œ ํšจ์„ฑ(freshness) ๊ณ„์‚ฐ์„ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. MDN ๋ฌธ์„œ๋ฅผ ๋ณด๋‹ˆ heuristic ์ด๋ผ๋Š” ๋™์ž‘์œผ๋กœ ์บ์‹œ ํ—ค๋”๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ์›น ์ŠคํŒฉ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋Œ€๋žต์ ์œผ๋กœ ์บ์‹œ ์ž‘๋™์„ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ์บ์‹œ๋„ ์•Œ์•„์„œ ๋™์ž‘ํ•˜๋‹ˆ ๋ฌธ์ œ๊ฐ€ ์—†๋Š”๊ฑธ๊นŒ?

ํœด๋ฆฌ์Šคํ‹ฑ ์บ์‹œ๋Š” ๋ฌธ์ œ๊ฐ€ ๋งŽ์ด ์ƒ๊ฒจ๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปจํ…์ธ  ๋ฐฐํฌ๋ฅผ ํ–ˆ๋”๋ผ๋„ ์›น ๋ฐฐํฌํ›„ ํŠน์ • ๊ธฐ๊ธฐ์—์„œ ์ด์ „ ์บ์‹œ ๋œ ์ฝ˜ํ…์ธ ๊ฐ€ ๋…ธ์ถœ๋  ์ˆ˜ ์žˆ๊ณ , ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์‹ค์ œ๋กœ ์ ์šฉ๋˜๋Š”๋ฐ ๋” ๋งŽ์€ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•œ ํ•ด๊ฒฐ์ฑ…์œผ๋กœ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์บ์‹œ๋ฅผ ๋น„์›Œ ๋ฆฌ์†Œ์Šค๋ฅผ ์ƒˆ๋กœ ๊ฐ€์ ธ์˜ค๋„๋ก ํ•˜๋Š” ๊ฒƒ ์ž…๋‹ˆ๋‹ค.

์‹ค์ œ ๊ฐœ๋ฐœ์ž ์ฐฝ์„ ์—ด๊ณ  ์ƒˆ๋กœ๊ณ ์นจ ๋ฒ„ํŠผ์„ ์šฐํด๋ฆญํ•˜๋ฉด โ€˜์บ์‹œ ๋น„์šฐ๊ธฐ ๋ฐ ๊ฐ•๋ ฅ ์ƒˆ๋กœ๊ณ ์นจโ€™ ์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

240329-002458

๊ทธ๋Ÿฌ๋‚˜ ๊ทผ๋ณธ์ ์œผ๋กœ ์บ์‹ฑ์— ๊ด€ํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋ช…์‹œ์ ์œผ๋กœ ํ—ค๋”๋ฅผ ์„ค์ •ํ•˜์—ฌ ์บ์‹œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์ฃผ๋Š”๊ฒŒ ์ข‹๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์บ์‹œ ์œ ํšจ์‹œ๊ฐ„์„ ์‚ฌ์šฉํ•˜์—ฌ ์ •ํ™•ํ•œ ์‹œ๊ฐ„์— ์—…๋ฐ์ดํŠธ๋ฅผ ๋ณด์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์จ๋ณด๋ฉด ์ข‹์„๊ฒƒ๊ฐ™์Šต๋‹ˆ๋‹ค.

์‹ค์ œ ํ† ์Šค์—์„œ๋Š” html์€ ๋ฐฐํฌ ์ฃผ๊ธฐ์— ์ฒดํฌ๋˜์–ด์•ผ ํ•˜๋Š” ๋ฆฌ์†Œ์Šค์ด๊ธฐ ๋•Œ๋ฌธ์— Cache-Control ๊ฐ’์œผ๋กœ max-age=0, s-maxage=31536000 ์„ ์„ค์ •ํ•œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ JavaScript ๋‚˜ CSS ํŒŒ์ผ์€ ํ”„๋ก ํŠธ์—”๋“œ ์›น ์„œ๋น„์Šค๋ฅผ ๋นŒ๋“œํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์ ์šฉ๋  ์ˆ˜ ์žˆ๋„๋ก ์ž„์˜ ๋ฒ„์ „ ๋ฒˆํ˜ธ๋ฅผ ๋ถ€์—ฌํ•ด ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

โ‡’ ๋งŒ์•ฝ ํ† ์Šค์˜ ์บ์‹œ ์„ค์ •์— ๋Œ€ํ•ด ๋” ์ž์„ธํžˆ ์•Œ๊ณ ์‹ถ๋‹ค๋ฉด ์—ฌ๊ธฐ๋ฅผ ํด๋ฆญ

์š”์•ฝ

  1. ๋ธŒ๋ผ์šฐ์ € ์บ์‹œ ์„ค์ •์„ ๋”ฐ๋กœ ํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ํฌ๋กฌ, ์‚ฌํŒŒ๋ฆฌ ๋“ฑ์˜ ๋ธŒ๋ผ์šฐ์ €๋Š” ์•Œ์•„์„œ ์บ์‹œ ๋™์ž‘์„ ํ•ด์ค๋‹ˆ๋‹ค.
  2. ์ž๋™์œผ๋กœ ์บ์‹œ ์„ค์ •์ด ๋œ๋‹ค๋Š”๊ฑด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์ง€์ ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ํ™•์ธํ•ด์ฃผ๋Š”๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.
  3. ๊ฐ๊ฐ์˜ ํŠน์„ฑ์— ๋”ฐ๋ผ ์บ์‹œ๋ฅผ ์„ฌ์„ธํžˆ ์ œ์–ดํ•จ์œผ๋กœ ์•ˆ์ „ํ•˜๊ณ  ๋น ๋ฅด๊ฒŒ HTTP ๋ฆฌ์†Œ์Šค๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํŠธ๋ž˜ํ”ฝ ๋น„์šฉ์„ ์ ˆ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ ์ž๋ฃŒ

ใ…กใ…ก

3. CI/CD๊ฐ€ ํ˜‘์—…์— ํ•„์š”ํ•œ ์ด์œ 

ํ˜‘์—… ๊ฒฝํ—˜์ด ๋ถ€์กฑํ–ˆ์„ ๋•Œ๋Š” ์ž‘์—…ํ•œ ๋‚ด์šฉ์„ ํ•œ ๋ถ„๊ธฐ์— ํ†ตํ•ฉํ•˜๊ณ  ํ•ด๋‹น ์ž‘์—…์ด ๋ฐฐํฌ๋  ๋•Œ๊นŒ์ง€์˜ ํŒŒ์ดํ”„๋ผ์ธ์„ ์ˆ˜๋™์œผ๋กœ ๊ฒ€์ฆํ•ด์•ผ ํ–ˆ๋˜ ๊ธฐ์–ต์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ Github Action์ด๋ผ๋Š” CI/CD ํˆด์„ ํ†ตํ•ด ํ˜‘์—… ๊ฒฝํ—˜์„ ๊ฐœ์„ ํ•˜๋ฉด์„œ, ๋ธŒ๋žœ์น˜๋ฅผ ๋ณ‘ํ•ฉํ•˜๊ธฐ ์ „ CI์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ  ๋ฐฐํฌ ๊ณผ์ •(CD)์„ ์ž๋™ํ™”ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

CI/CD ์„ค๋ช…

CI/CD๋Š” ์ฝ”๋“œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋” ๋น ๋ฅด๊ณ  ์•ˆ์ •์ ์œผ๋กœ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ๋นŒ๋“œ, ํ…Œ์ŠคํŠธ ๋ฐ ๋ฐฐํฌ๋ฅผ ์ž๋™ํ™”ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ง€์†์ ์ธ ํ†ตํ•ฉ๊ณผ ์ง€์†์ ์ธ ๋ฐฐํฌ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์œผ๋ฉฐ, ๊ฐ๊ฐ์˜ ์ •์˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • CI - ๊ณต์œ  ์ €์žฅ์†Œ๋‚ด์—์„œ ์ฝ”๋“œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋Œ€ํ•œ ๋นŒ๋“œ ๋ฐ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ฉํ•œ๋‹ค.
  • CD - ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์— ์ „๋‹ฌ, ์ฝ”๋“œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋ฐฐํฌ ์ž๋™ํ™” ํ•œ๋‹ค.

๋”ฐ๋ผ์„œ CI/CD ํŒŒ์ดํ”„๋ผ์ธ์€ ๋ณดํ†ต ๋‘ ๊ฐ€์ง€ ์„น์…˜์œผ๋กœ ๋‚˜๋‰˜์–ด ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค.

  • build โ†’test โ†’ artifact / staging โ†’ production

CI/CD ์˜ ์ž์„ธํ•œ ์›Œํฌํ”Œ๋กœ์šฐ ์˜ˆ์‹œ๋Š” ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

###CI/CD์˜ ์ด์ 

Google DevOps ๋ณด๊ณ ์„œ์— ๋”ฐ๋ฅด๋ฉด, CI/CD๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์กฐ์ง์€ ๋‹ค๋ฅธ ์กฐ์ง๋ณด๋‹ค ๋ฐฐํฌ๋ฅผ 208๋ฐฐ ๋” ์ž์ฃผํ•˜๊ณ  ๋ฆฌ๋“œ ํƒ€์ž„์ด 106๋ฐฐ ๋” ๋น ๋ฅด๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ์™ธ์˜ ์ด์ ์œผ๋กœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ์ฝ”๋“œ๋ฒ ์ด์Šค๊ฐ€ ์–ธ์ œ๋“ ์ง€ ์•ˆ์ •์ ์ธ ์ƒํƒœ ์œ ์ง€
  • ์ž๋™ํ™”๋˜๊ณ  ์ง€์†์ ์ธ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ (๋น„์šฉ ์ ˆ๊ฐ ํšจ๊ณผ)
  • ๋ฆด๋ฆฌ์Šค ์†๋„ ๋‹จ์ถ•
  • ์˜ค๋ฅ˜ ๊ฒฉ๋ฆฌ, ์žฅ์•  ์ง€์  ๊ฐ์†Œ
  • ์˜ค๋ฒ„ํ—ค๋“œ ๋น„์šฉ ์ ˆ๊ฐ

###ํŒ€์— ๋„์ž…๋˜๊ณ ์žˆ๋Š” cicd ํ˜„ํ™ฉ

์ €ํฌ ํŠธ๋ž™์—์„œ๋Š” Github Actions๋ฅผ ์ด์šฉํ•˜์—ฌ CI/CD๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

Github Actions๋Š” ํŠน์ • ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์—์„œ ํŠธ๋ฆฌ๊ฑฐ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ GitHub Action Runner์—์„œ ์ž‘์—…์„ ์‹คํ–‰ํ•˜๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

Runner ๋จธ์‹  ๊ตฌ์ถ• ์ดํ›„, ๋ฆฌํฌ์ง€ํ† ๋ฆฌย .github/workflowsย ๋””๋ ‰ํ† ๋ฆฌ์— ์›Œํฌํ”Œ๋กœ์šฐ YAML ํŒŒ์ผ์„ ์ž‘์„ฑํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ณ„๋„์˜ ์„ค์น˜๋‚˜ ์„ธํŒ… ์—†์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ๊นŒ์ง€ ์ •์˜๋œ ์›Œํฌํ”Œ๋กœ์šฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. Lint Check

์ฝ”๋“œ ๋ฒ ์ด์Šค์˜ ์•ˆ์ •์„ฑ, ๋ฐฐํฌ ๊ณผ์ •์—์„œ์˜ ์—๋Ÿฌ๋ฅผ ์ตœ์†Œํ™”ํ•˜๊ธฐ ์œ„ํ•ด ๋„์ž…๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Pull Request๊ฐ€ ๋“ฑ๋ก๋˜๋ฉด ์ž๋™์œผ๋กœ eslint ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๊ณ  eslint๋ฅผ ํ†ต๊ณผํ•˜์ง€ ๋ชปํ•œ PR์€ merge ํ•˜์ง€ ๋ชปํ•˜๋„๋ก ์ œ์–ด๋ฉ๋‹ˆ๋‹ค.

  1. Type Check

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ฝ”๋“œ ๋ฒ ์ด์Šค์˜ ์•ˆ์ •์„ฑ, ๋ฐฐํฌ ๊ณผ์ •์—์„œ์˜ ์—๋Ÿฌ๋ฅผ ์ตœ์†Œํ™”ํ•˜๊ธฐ ์œ„ํ•ด ๋„์ž…๋˜์—ˆ์Šต๋‹ˆ๋‹ค. TypeScript ํŒŒ์ผ์— ๋Œ€ํ•ด ํƒ€์ž… ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ , ์ฝ”๋“œ์— ์˜ค๋ฅ˜๊ฐ€ ์—†๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์ด๋˜ํ•œ ํ…Œ์ŠคํŠธ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด merge ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

  1. Pick Reviewer

PR ๋ฆฌ๋ทฐ์–ด๋ฅผ ์ปค์Šคํ…€ํ•˜๊ธฐ ์œ„ํ•ด ๋„์ž…๋˜์—ˆ์Šต๋‹ˆ๋‹ค. PR์ด ์—ด๋ฆฌ๋ฉด ์ •ํ•ด์ง„ ๊ตฌ์„ฑ ์•ˆ์—์„œ ๋žœ๋ค์œผ๋กœ ๋ฆฌ๋ทฐ์–ด๊ฐ€ ๋ฐฐ์ •๋˜๋ฉฐ, ์ด ๊ณผ์ •์€ ์Šฌ๋ž™์œผ๋กœ ์•Œ๋ฆผ์ด ์—ฐ๋™๋ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ๋Š” ๊ฐ™์€ ๋„๋ฉ”์ธ ํŒ€ 1๋ช…๊ณผ ๋‹ค๋ฅธ ๋„๋ฉ”์ธ ํŒ€ 1๋ช… ๊ตฌ์„ฑ์œผ๋กœ ์„ค์ •๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค.

์ดˆ๊ธฐ์—๋Š” PR Lint test ์‹คํ–‰์„ ์ฃผ๋ชฉ์ ์œผ๋กœ ๋„์ž…๋˜์—ˆ์ง€๋งŒ, ์ด ๊ณผ์ •์—์„œ Runner ๋จธ์‹  ๊ตฌ์ถ• ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ PR์— ์ปค๋ฐ‹์ด ์ถ”๊ฐ€๋  ๋•Œ๋งˆ๋‹ค ์ค‘๋ณต ์‹คํ–‰๋˜๊ฑฐ๋‚˜, PR ๋ณธ๋ฌธ์ด ๋ณ€๊ฒฝ๋˜์–ด๋„ ๋ฆฐํŠธ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๋“ฑ ๊ฐœ์„ ์ด ํ•„์š”ํ•œ ๋ถ€๋ถ„์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ Lint Test ์ด์™ธ์˜ ๊ฐœ๋ฐœ ํšจ์œจ์„ฑ์„ ๋†’์—ฌ์ค„ ๋งŒ ํ•œ ๋‹ค์–‘ํ•œ Action๋“ค์„ ์ฐพ์•˜๊ณ , ๊ฒ€ํ† ํ•ด๋ณด๋ฉด ์ข‹์„ ๊ฒƒ๋“ค์„ ๋ชจ์•„๋ดค์Šต๋‹ˆ๋‹ค.

  • develop ๋ธŒ๋žœ์น˜์— ์ฝ”๋“œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด merge๋˜๋Š” ์ฆ‰์‹œ ์ž๋™์œผ๋กœ ์  ํ‚จ์Šค ๋นŒ๋“œ ํŠธ๋ฆฌ๊ฑฐ
  • ์บ์‹ฑ ๋ฐ์ดํ„ฐ ํ™œ์šฉํ•˜์—ฌ ์›Œํฌํ”Œ๋กœ์šฐ ๋ถˆํ•„์š”ํ•œ ์ž‘์—… ์ตœ์ ํ™”
  • ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ฝ”๋“œ ์ž๋™ ๋ ˆ๊ฑฐ์‹œ ์ฒดํฌ

์š”์•ฝ

  • CI/CD ์ „๋žต์€ ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ ๋ผ์ดํ”„์‚ฌ์ดํด ์ „๋ฐ˜์—์„œ ํšจ์œจ์„ฑ๊ณผ ์•ˆ์ •์„ฑ์„ ์ฆ๋Œ€์‹œํ‚ต๋‹ˆ๋‹ค.
  • ์ €ํฌ ํŒ€์—์„œ๋Š” Lint Check๋ฅผ ์œ„์ฃผ๋กœ ์‚ฌ์šฉํ•˜๊ณ ์žˆ์ง€๋งŒ, ๋” ํšจ์œจ์ ์ธ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋„์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

References CI/CD(CI CD, ์ง€์†์  ํ†ตํ•ฉ/์ง€์†์  ๋ฐฐํฌ): ๊ฐœ๋…, ํˆด, ๊ตฌ์ถ•, ์ฐจ์ดCI/CD๋ž€?

https://resources.github.com/ci-cd/

https://www.martinfowler.com/articles/originalContinuousIntegration.html

https://it.donga.com/101955/

https://medium.com/naver-place-dev/github-actions๋ฅผ-ํ™œ์šฉํ•œ-๊ฐœ๋ฐœ-ํšจ์œจํ™”-7df7a14b8843

--