** ๐Ÿ“Œ8-1๋‹จ๊ณ„: Ajax + SPA ์•„ํ‚คํ…์ฒ˜ ์„ค๊ณ„ ์ „๋žต ์™„์ „์ •๋ณต **

๋‹จ์ˆœํ•œ ์›นํŽ˜์ด์ง€๊ฐ€ ์•„๋‹ˆ๋ผ, ์ˆ˜์‹ญ ๊ฐœ ํ™”๋ฉด / ๋ณต์žกํ•œ ์ƒํƒœ / SEO๊นŒ์ง€ ๊ณ ๋ คํ•ด์•ผ ํ•˜๋Š” ๋Œ€ํ˜• ์„œ๋น„์Šค๋ผ๋ฉด

Ajax์™€ SPA๋ฅผ ์–ด๋–ป๊ฒŒ ์—ฐ๊ฒฐํ•˜๊ณ  ๊ด€๋ฆฌํ• ์ง€์— ๋Œ€ํ•œ ์ „๋žต์ด ๊ผญ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.


โœ… 1. SPA์™€ Ajax๋Š” ์™œ ํ•ญ์ƒ ๊ฐ™์ด ๋‹ค๋‹๊นŒ?

๐Ÿ“ฆ SPA (Single Page Application)

HTML ์ „์ฒด๋ฅผ ๋งค๋ฒˆ ๋‹ค์‹œ ๋ฐ›์ง€ ์•Š๊ณ ,

ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋งŒ Ajax๋กœ ๊ฐ€์ ธ์™€์„œ ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ์‹


๐Ÿ‘ฆ๐Ÿป ์‰ฌ์šด ์„ค๋ช…

์›๋ž˜๋Š” ํŽ˜์ด์ง€ ์ด๋™๋งˆ๋‹ค ์ „์ฒด ๊ฐˆ์•„์—Ž๊ธฐ (MPA)

โ†’ SPA๋Š” ํ™”๋ฉด์€ ๊ทธ๋Œ€๋กœ ๋‘๊ณ  ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ Ajax๋กœ ๊ฐฑ์‹ !


โœ… 2. Ajax ๋ฐ์ดํ„ฐ๋Š” ์–ด๋””์— ์ €์žฅํ• ๊นŒ?


โœ… ์ƒํƒœ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ ํ™˜๊ฒฝ
Redux React + ๋ณต์žกํ•œ ์ƒํƒœ
Vuex Vue ์ „์šฉ ์ „์—ญ ์ƒํƒœ๊ด€๋ฆฌ
Recoil React + ๊ฐ„๋‹จํ•œ ์ƒํƒœ / ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ๋” ์‰ฝ๊ฒŒ
Zustand / Pinia ์‹ ์„ธ๋Œ€ ๊ฒฝ๋Ÿ‰ ์ƒํƒœ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

๐Ÿ“ฆ ์˜ˆ์‹œ ๊ตฌ์กฐ (React + Redux)

๐Ÿ“ฆ store
 โ”ฃ ๐Ÿ“„ userSlice.js   โ† ์‚ฌ์šฉ์ž ๊ด€๋ จ Ajax + ์ƒํƒœ
 โ”ฃ ๐Ÿ“„ productSlice.js โ† ์ƒํ’ˆ ๊ด€๋ จ Ajax + ์ƒํƒœ

โœ… Redux + Ajax ์—ฐ๋™ ์˜ˆ์‹œ (Thunk ์‚ฌ์šฉ)

// userSlice.js
export const fetchUser = createAsyncThunk("user/fetch", async () => {
  const res = await fetch("/api/user");
  return await res.json();
});

โ†’ Ajax ์š”์ฒญ์€ dispatch(fetchUser())

โ†’ ๊ฒฐ๊ณผ๋Š” ์ž๋™์œผ๋กœ state.user.data์— ๋“ค์–ด๊ฐ

โ†’ ์ปดํฌ๋„ŒํŠธ์—์„  useSelector๋กœ ์‚ฌ์šฉ


โœ… 3. SSR๊ณผ CSR์˜ ์กฐํ™” ์ „๋žต


๋ฐฉ์‹ ํŠน์ง• Ajax ์œ„์น˜
CSR (Client Side Rendering) ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋ชจ๋“  ๋ Œ๋”๋ง Ajax๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ง์ ‘ ์‹คํ–‰๋จ
SSR (Server Side Rendering) ์„œ๋ฒ„์—์„œ HTML ์ƒ์„ฑ ํ›„ ์ „๋‹ฌ ์„œ๋ฒ„๊ฐ€ Ajax ์š”์ฒญ ๋ฏธ๋ฆฌ ์ฒ˜๋ฆฌํ•ด์„œ ๊ฒฐ๊ณผ๋งŒ ์ „์†ก
Hybrid (Next.js ๋“ฑ) ๋‘˜ ๋‹ค ์‚ฌ์šฉ (์ดˆ๊ธฐ SSR + ์ดํ›„ CSR) ์ดˆ๋ฐ˜์—” ์„œ๋ฒ„, ์ดํ›„์—” ํด๋ผ์ด์–ธํŠธ Ajax ์‚ฌ์šฉ

๐Ÿ‘ฆ๐Ÿป ์‰ฌ์šด ์„ค๋ช…

๐Ÿ“ฆ CSR = โ€œ๋นˆ ๊ป๋ฐ๊ธฐ ๋จผ์ € ๋ณด์—ฌ์ฃผ๊ณ , Ajax๋กœ ๋‚ด์šฉ ์ฑ„์šฐ๊ธฐโ€

๐Ÿ“ฆ SSR = โ€œ์„œ๋ฒ„์—์„œ ๋‚ด์šฉ๊นŒ์ง€ ๋‹ค ๋งŒ๋“ค์–ด์„œ ๋ฐ”๋กœ ๋ณด์—ฌ์ฃผ๊ธฐโ€

๐Ÿง  Hybrid = โ€œ์ฒ˜์Œ๋งŒ ๋น ๋ฅด๊ฒŒ ๋ณด์—ฌ์ฃผ๊ณ , ์ดํ›„์—” SPA์ฒ˜๋Ÿผ ํ–‰๋™โ€


โœ… ์ถ”์ฒœ ์ „๋žต

ํŽ˜์ด์ง€ ์„ฑ๊ฒฉ SSR ๊ถŒ์žฅ? Ajax ์œ„์น˜
๊ฒ€์ƒ‰ ์—”์ง„ ์ตœ์ ํ™” ํ•„์š” โœ… SSR ์„œ๋ฒ„์—์„œ ๋ฏธ๋ฆฌ Ajax
๋กœ๊ทธ์ธ ํ›„ ๊ฐœ์ธํ™” UI โŒ CSR ๋ธŒ๋ผ์šฐ์ €์—์„œ Ajax
์†๋„ + SEO ๋‘˜ ๋‹ค ์ค‘์š” โœ… Hybrid (Next.js) getServerSideProps + ํด๋ผ์ด์–ธํŠธ Fetch ๋ณ‘ํ–‰

โœ… 4. Ajax ์ƒํƒœ๊ด€๋ฆฌ ์ „๋žต ์š”์•ฝ


์ƒํ™ฉ ์ถ”์ฒœ ์ „๋žต
๋กœ๊ทธ์ธ/์‚ฌ์šฉ์ž ์ •๋ณด Redux / Vuex ์ „์—ญ ์ €์žฅ
๊ธ€์“ฐ๊ธฐ/๋Œ“๊ธ€์“ฐ๊ธฐ ์ปดํฌ๋„ŒํŠธ ๋‹จ ๋กœ์ปฌ ์ƒํƒœ ๊ด€๋ฆฌ
์ƒํ’ˆ ๋ชฉ๋ก + ํ•„ํ„ฐ ์ƒํƒœ๊ด€๋ฆฌ + Ajax ์บ์‹ฑ
๋น ๋ฅธ ํƒ์ƒ‰/ํƒญ ์ด๋™ SWR / React Query (์ž๋™ ์บ์‹ฑ, ์‹คํŒจ ์žฌ์‹œ๋„ ๋“ฑ)

โœ… 5. ์‹ค๋ฌด ์•„ํ‚คํ…์ฒ˜ ์˜ˆ์‹œ (Next.js + Recoil + SSR)

๐Ÿ“ฆ pages
 โ”ฃ ๐Ÿ“„ index.tsx         โ† SSR ์ดˆ๊ธฐ ๋ Œ๋”๋ง
๐Ÿ“ฆ recoil
 โ”ฃ ๐Ÿ“„ userAtom.ts       โ† ๋กœ๊ทธ์ธ ์ƒํƒœ ์ „์—ญ ์ €์žฅ
 โ”ฃ ๐Ÿ“„ useUserFetch.ts   โ† Ajax ํ›… (CSR ์ „์šฉ)

๐Ÿ“ฆ lib
 โ”ฃ ๐Ÿ“„ api.ts            โ† fetch wrapper + ๋กœ๊น…

ํ๋ฆ„ ์„ค๋ช…

  1. SSR๋กœ ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ ๋ฏธ๋ฆฌ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
  2. ํด๋ผ์ด์–ธํŠธ ์ „ํ™˜ ์‹œ, Recoil๋กœ ์ƒํƒœ ์œ ์ง€
  3. ์ถ”๊ฐ€ Ajax ์š”์ฒญ์€ useFetch ํ›…์œผ๋กœ ๊ด€๋ฆฌ
  4. ์—๋Ÿฌ/๋กœ๋”ฉ/์„ฑ๋Šฅ์€ Sentry + Web Vitals๋กœ ๊ฐ์‹œ

โœ… 6. ๋ฉด์ ‘ ์งˆ๋ฌธ ์˜ˆ์‹œ + ํ•ด์„ค


โ“ Q. SPA ๊ธฐ๋ฐ˜ ๋Œ€ํ˜• ์„œ๋น„์Šค์—์„œ Ajax ์š”์ฒญ์„ ์–ด๋–ป๊ฒŒ ๊ตฌ์กฐํ™”ํ•˜์‹ญ๋‹ˆ๊นŒ?

โœ… A.


โœ… ์ „์ฒด ์š”์•ฝ ์นด๋“œ

๊ฐœ๋… ์„ค๋ช…
SPA + Ajax ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋งŒ ๊ฐ€์ ธ์™€์„œ ํ™”๋ฉด ๊ตฌ์„ฑ
์ƒํƒœ๊ด€๋ฆฌ Redux, Vuex, Recoil ๋“ฑ๊ณผ ์—ฐ๊ณ„
CSR ๋นˆ ํ™”๋ฉด ๋จผ์ €, Ajax๋กœ ๋‚ด์šฉ ์ฑ„์›€
SSR ์„œ๋ฒ„์—์„œ Ajax ํ˜ธ์ถœ โ†’ ์™„์„ฑ๋œ HTML ์ „์†ก
Hybrid ์ฒซ ํ™”๋ฉด์€ SSR, ์ดํ›„๋Š” CSR Ajax
๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ React Query / SWR: Ajax ์บ์‹ฑ + ์‹คํŒจ์ฒ˜๋ฆฌ ์ž๋™ํ™”

โœ… 8-2๋‹จ๊ณ„: Micro Frontend ํ™˜๊ฒฝ์—์„œ์˜ Ajax ํ†ต์‹  ๊ตฌ์กฐ ์™„์ „์ •๋ณต

ํ•˜๋‚˜์˜ ์›น์•ฑ์ด ์—ฌ๋Ÿฌ ํŒ€/๋ชจ๋“ˆ๋กœ ๋‚˜๋‰œ โ€˜Micro Frontendโ€™ ๊ตฌ์กฐ์—์„œ๋Š”

Ajax ํ†ต์‹ ๋„ ๋ชจ๋“ˆ๋ณ„๋กœ ๋ถ„๋ฆฌ, ๋ณด์•ˆ, ์„ฑ๋Šฅ ๋ถ„์‚ฐ๊นŒ์ง€ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.


โœ… 1. Micro Frontend๋ž€?


๐Ÿ“ฆ ์ •์˜

ํ•˜๋‚˜์˜ ์›น ํ”„๋ก ํŠธ์—”๋“œ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ž‘์€ ๋…๋ฆฝ ๋ชจ๋“ˆ(์•ฑ)๋กœ ๋‚˜๋ˆ ์„œ

์„œ๋กœ ๋‹ค๋ฅธ ํŒ€์ด ๋…๋ฆฝ์ ์œผ๋กœ ๊ฐœ๋ฐœ/๋ฐฐํฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“  ๊ตฌ์กฐ


๐Ÿ‘ฆ๐Ÿป ์‰ฌ์šด ๋น„์œ 

ํฌํ„ธ ๋ฉ”์ธ ํ™”๋ฉด์„ ์ƒ์ƒํ•ด๋ณด์„ธ์š”:

  • ์™ผ์ชฝ ๋‚ ์”จ: โ˜๏ธ ๋‚ ์”จํŒ€
  • ๊ฐ€์šด๋ฐ ๋‰ด์Šค: ๐Ÿ“ฐ ๋‰ด์ŠคํŒ€
  • ์˜ค๋ฅธ์ชฝ ์‡ผํ•‘: ๐Ÿ›’ ์‡ผํ•‘ํŒ€

โ†’ ํ•˜๋‚˜์˜ ํŽ˜์ด์ง€์ง€๋งŒ ๊ฐ ๊ธฐ๋Šฅ์€ ์„œ๋กœ ๋…๋ฆฝ์ ์œผ๋กœ ๋™์ž‘ํ•จ


โœ… 2. Micro Frontend์—์„œ์˜ Ajax ํ†ต์‹ ์ด ์™œ ์–ด๋ ค์šธ๊นŒ?

๋ฌธ์ œ ์„ค๋ช…
์š”์ฒญ ์ถฉ๋Œ ์—ฌ๋Ÿฌ ๋ชจ๋“ˆ์ด ๊ฐ™์€ API์— ์ ‘๊ทผํ•˜๋ฉด ์ถฉ๋Œ ๊ฐ€๋Šฅ
์ธ์ฆ ํ˜ผ์„  ์ผ๋ถ€ ๋ชจ๋“ˆ์€ ๊ด€๋ฆฌ์ž ๊ถŒํ•œ, ์ผ๋ถ€๋Š” ์‚ฌ์šฉ์ž๋งŒ ์ ‘๊ทผํ•ด์•ผ ํ•จ
์‘๋‹ต ์ค‘๋ณต ๋™์ผ ๋ฐ์ดํ„ฐ๋ฅผ ์—ฌ๋Ÿฌ ๋ชจ๋“ˆ์—์„œ ๋ฐ˜๋ณต ์š”์ฒญ ๊ฐ€๋Šฅ
์บ์‹œ ๊ณต์œ  ๋ฌธ์ œ ๋‹ค๋ฅธ ๋ชจ๋“ˆ์˜ ์‘๋‹ต์ด ๋ฎ์–ด์“ฐ๊ธฐ ๋  ์ˆ˜ ์žˆ์Œ

โœ… ๊ทธ๋ž˜์„œ ๋ชจ๋“ˆ ๊ฐ„ ๋ถ„๋ฆฌ + ๊ถŒํ•œ ์ œ์–ด + ์บ์‹œ ๋…๋ฆฝ์ด ์ค‘์š”ํ•ด์ง‘๋‹ˆ๋‹ค.


โœ… 3. ๋ชจ๋“ˆ๋ณ„ Ajax ๊ตฌ์กฐ ์„ค๊ณ„ ์ „๋žต


โœ… ํ•ต์‹ฌ ์›์น™ โ‘ : ๊ฐ ๋ชจ๋“ˆ์€ ์ž๊ธฐ๋งŒ์˜ API Wrapper๋ฅผ ๊ฐ€์ ธ์•ผ ํ•จ

๐Ÿ“ฆ weather-app
 โ”ฃ ๐Ÿ“„ api.js   โ† fetchWeather()

๐Ÿ“ฆ news-app
 โ”ฃ ๐Ÿ“„ api.js   โ† fetchNews()

๐Ÿ“ฆ shop-app
 โ”ฃ ๐Ÿ“„ api.js   โ† fetchProducts()

โœ… ์„œ๋กœ์˜ ์š”์ฒญ/๋ฐ์ดํ„ฐ๋ฅผ ์นจ๋ฒ”ํ•˜์ง€ ์•Š์Œ

โœ… ์œ ์ง€๋ณด์ˆ˜ + ๋…๋ฆฝ ๋ฐฐํฌ๋„ ์‰ฌ์›€


โœ… ํ•ต์‹ฌ ์›์น™ โ‘ก: API ์ ‘๊ทผ ๊ถŒํ•œ์€ ์ค‘์•™ ๊ฒŒ์ดํŠธ์›จ์ด or ์ธ์ฆ ์„œ๋น„์Šค๋กœ ๊ด€๋ฆฌ


๐Ÿ”’ ์˜ˆ์‹œ: ๋ชจ๋“ˆ A์—์„œ ๊ด€๋ฆฌ์ž ์ „์šฉ API ์š”์ฒญ

fetch("/api/admin/user", {
  headers: { Authorization: "Bearer userToken" }
})
โ†’ 403 Forbidden (๊ถŒํ•œ ์—†์Œ)

โœ… ์ด๋ ‡๊ฒŒ ์ค‘์•™ ์ธ์ฆ ์‹œ์Šคํ…œ์—์„œ ๊ถŒํ•œ์„ ๋ถ„๋ฆฌํ•ด์ค๋‹ˆ๋‹ค.


โœ… 4. Service Worker๋กœ Ajax ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๊ด€๋ฆฌ


๐Ÿ“ฆ Service Worker๋ž€?

๋ธŒ๋ผ์šฐ์ €์— ๋“ฑ๋ก๋˜๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ JS ํ”„๋กœ๊ทธ๋žจ

Ajax ์š”์ฒญ์„ ๊ฐ€๋กœ์ฑ„๊ฑฐ๋‚˜, ์บ์‹œํ•˜๊ฑฐ๋‚˜, ์˜คํ”„๋ผ์ธ ์ฒ˜๋ฆฌ๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•จ


๐Ÿ‘ฆ๐Ÿป ์‰ฌ์šด ์„ค๋ช…

โ€œ์›น์•ฑ์˜ ํƒ๋ฐฐ๊ธฐ์‚ฌโ€์ฒ˜๋Ÿผ, ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ํ™”๋ฉด์„ ๋ณด์ง€ ์•Š์•„๋„

๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์š”์ฒญ์„ ๋Œ€์‹  ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•˜๊ณ , ์บ์‹œ๋„ ํ•ด์ค๋‹ˆ๋‹ค.


โœ… Micro Frontend์—์„œ ํ™œ์šฉ ์˜ˆ์‹œ

๊ธฐ๋Šฅ ์„ค๋ช…
๊ณตํ†ต ์š”์ฒญ ์บ์‹ฑ /api/config, /api/user/me ๊ฐ™์€ ์š”์ฒญ์€ ๊ณตํ†ต Service Worker๊ฐ€ ์บ์‹œ
๋ชจ๋“ˆ ๊ฐ„ ์˜คํ”„๋ผ์ธ Ajax ๋Œ€์‘ ๋ชจ๋“ˆ์ด ์˜คํ”„๋ผ์ธ ์ƒํƒœ์ผ ๋•Œ ๋ฐฑ์—… ์‘๋‹ต ์ „๋‹ฌ
์š”์ฒญ ์ค‘๋ณต ๋ฐฉ์ง€ ๋™์ผํ•œ ์š”์ฒญ์€ Service Worker๊ฐ€ ํ•œ ๋ฒˆ๋งŒ ์ฒ˜๋ฆฌ

๐Ÿ“ฆ Ajax ์บ์‹œ ์˜ˆ์‹œ ์ฝ”๋“œ

self.addEventListener("fetch", event => {
  if (event.request.url.includes("/api/")) {
    event.respondWith(
      caches.match(event.request).then(cached => {
        return cached || fetch(event.request).then(res => {
          return caches.open("ajax-cache").then(cache => {
            cache.put(event.request, res.clone());
            return res;
          });
        });
      })
    );
  }
});

โœ… ๋ชจ๋“ˆ๋ณ„ API๋„ ๊ณตํ†ต์ ์œผ๋กœ ์บ์‹œ/๊ด€๋ฆฌ ๊ฐ€๋Šฅ


โœ… 5. ๊ถŒํ•œ ์ œ์–ด ์ „๋žต ์ •๋ฆฌ


์ „๋žต ์„ค๋ช…
๋ชจ๋“ˆ ์ž์ฒด์—์„œ๋Š” ์ธ์ฆ ์ •๋ณด๋งŒ ์†Œ์œ  ํ† ํฐ ์ €์žฅ์€ ๋กœ์ปฌ but ๊ฒ€์ฆ์€ ์ค‘์•™ ์„œ๋ฒ„
๋ฏผ๊ฐ API๋Š” ๋ฐฑ์—”๋“œ์—์„œ ๊ถŒํ•œ ์žฌ๊ฒ€์‚ฌ ํ”„๋ก ํŠธ์—์„œ๋งŒ ๋ฏฟ์ง€ ๋ง๊ธฐ
๊ฐ ๋ชจ๋“ˆ์€ ์ธ์ฆ ์ƒํƒœ๋ฅผ ์ค‘์•™ ์ƒํƒœ๋กœ ๊ณต์œ  ์˜ˆ: window.Auth ๋˜๋Š” ์ „์—ญ ์ƒํƒœ ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ

โœ… 6. ๋ฉด์ ‘ ์งˆ๋ฌธ ์˜ˆ์‹œ + ํ•ด์„ค


โ“ Q. Micro Frontend ๊ตฌ์กฐ์—์„œ Ajax ์š”์ฒญ์€ ์–ด๋–ป๊ฒŒ ๋ถ„๋ฆฌํ•˜๊ณ  ์ œ์–ดํ•˜์‹œ๋‚˜์š”?

โœ… A.


โœ… ์ „์ฒด ์š”์•ฝ ์นด๋“œ

๊ฐœ๋… ์„ค๋ช…
Micro Frontend ์›น์•ฑ์„ ์—ฌ๋Ÿฌ ๋…๋ฆฝ ์•ฑ์œผ๋กœ ๋ถ„๋ฆฌ
API ๊ฒฉ๋ฆฌ ๊ฐ ์•ฑ๋งˆ๋‹ค ๊ณ ์œ  API Wrapper ์šด์˜
๊ถŒํ•œ ๋ถ„๋ฆฌ ์ธ์ฆ์€ ์ค‘์•™ ์„œ๋ฒ„์—์„œ ์ผ๊ด„ ์ฒ˜๋ฆฌ
Service Worker Ajax ์š”์ฒญ ์บ์‹ฑ, ์ค‘๋ณต ์ œ๊ฑฐ, ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ฒ˜๋ฆฌ
์š”์ฒญ ์ œ์–ด ์บ์‹œ / ๊ถŒํ•œ / ์‹คํŒจ ์‹œ fallback ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ