Coding Archive

[Next.js] Next.js์˜ Route Groups์™€ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ด์šฉํ•œ ์ธ์ฆ ๋ฐ ๊ฒฝ๋กœ ์ถฉ๋Œ ๋ฌธ์ œ ํ•ด๊ฒฐํ•˜๊ธฐ ๋ณธ๋ฌธ

๐Ÿ’ป Programming/Next.js & project

[Next.js] Next.js์˜ Route Groups์™€ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ด์šฉํ•œ ์ธ์ฆ ๋ฐ ๊ฒฝ๋กœ ์ถฉ๋Œ ๋ฌธ์ œ ํ•ด๊ฒฐํ•˜๊ธฐ

์ฝ”๋“ฑ์–ด 2024. 11. 13. 22:00

 

Next.js Route Groups์™€ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ด์šฉํ•œ ์ธ์ฆ ๋ฐ ๊ฒฝ๋กœ ์ถฉ๋Œ ๋ฌธ์ œ ํ•ด๊ฒฐ

 

Next.js์˜ app ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ์™€ Route Groups(๊ฒฝ๋กœ ๊ทธ๋ฃน) ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜๋‹ค ๋ณด๋ฉด, ๊ฒฝ๋กœ๋ฅผ ์ง๊ด€์ ์ด๊ณ  ์กฐ์ง์ ์œผ๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋™์ผํ•œ URL ๊ฒฝ๋กœ๋กœ ํ•ด์„๋˜๋Š” ํŽ˜์ด์ง€๋ฅผ ๋‘ ๊ฐœ ์ด์ƒ ๊ตฌ์„ฑํ•˜๊ฒŒ ๋˜๋ฉด ๊ฒฝ๋กœ ์ถฉ๋Œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ๋กœ๊ทธ์ธ ์ƒํƒœ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๊ณผ์ •์—์„œ ๋ฐœ์ƒํ•œ ๋ฌธ์ œ๋ฅผ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…ํ•œ ๊ณผ์ •๊ณผ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ํ™œ์šฉํ•œ ์ ‘๊ทผ ์ œ์–ด ๋ฐฉ๋ฒ•์„ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค.

 


๐Ÿ› ๋ฌธ์ œ ์ƒํ™ฉ

ํ”„๋กœ์ ํŠธ์˜ ๋ฉ”์ธ ํŽ˜์ด์ง€(/)์—์„œ ๋กœ๊ทธ์ธ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์ฝ˜ํ…์ธ ๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ ์ž ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ ์ƒํƒœ์— ๋”ฐ๋ผ ๋ณ„๋„์˜ ๊ฒฝ๋กœ ๊ทธ๋ฃน์„ ํ™œ์šฉํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

src/ 
โ”œโ”€โ”€app/ 
โ”‚  โ”œโ”€โ”€ (private)/
โ”‚  โ”‚   โ””โ”€โ”€ page.tsx             // ๋กœ๊ทธ์ธ ์‹œ ๋ Œ๋”๋ง๋  ํŽ˜์ด์ง€
โ”‚  โ”œโ”€โ”€ (public)/
โ”‚      โ””โ”€โ”€ page.tsx             // ๋น„๋กœ๊ทธ์ธ ์‹œ ๋ Œ๋”๋ง๋  ํŽ˜์ด์ง€
โ”œโ”€โ”€ middleware.ts // ๋กœ๊ทธ์ธ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ๋ฏธ๋“ค์›จ์–ด
  • (public)/page.tsx: ๋น„๋กœ๊ทธ์ธ ์ƒํƒœ์˜ ์‚ฌ์šฉ์ž์—๊ฒŒ ๊ธฐ๋ณธ์œผ๋กœ ๋ณด์—ฌ์ค„ ํŽ˜์ด์ง€(๋กœ๊ทธ์ธ ์œ ๋„ ์ฝ˜ํ…์ธ )
  • (private)/page.tsx: ๋กœ๊ทธ์ธ๋œ ์ƒํƒœ์˜ ์‚ฌ์šฉ์ž์—๊ฒŒ ๊ธฐ๋ณธ์œผ๋กœ ๋ณด์—ฌ์ค„ ํŽ˜์ด์ง€(ํ”ผ๋“œ ์ฝ˜ํ…์ธ )

 -> ์ด๋ ‡๊ฒŒ ๋‘ ๊ฐœ์˜ ๊ฒฝ๋กœ ๊ทธ๋ฃน์„ ์‚ฌ์šฉํ•ด ๋กœ๊ทธ์ธ ์ „๊ณผ ํ›„์— ์„œ๋กœ ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ ์ž ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋น„๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž๊ฐ€ / ๊ฒฝ๋กœ๋กœ ์ ‘์†ํ•˜๋ฉด (public)/page.tsx๊ฐ€ ๋ Œ๋”๋ง๋˜๊ณ , ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ์ ‘๊ทผํ•  ๋•Œ๋Š” (private)/page.tsx๊ฐ€ ๋ Œ๋”๋ง๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

 


โš ๏ธ ๋ฌธ์ œ ๋ฐœ์ƒ: ๊ฒฝ๋กœ ์ถฉ๋Œ ์˜ค๋ฅ˜

์œ„์™€ ๊ฐ™์€ ๊ฒฝ๋กœ ๊ทธ๋ฃน ์„ค์ •์€ ๋™์ผํ•œ URL์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋‘ ๊ฐœ์˜ ๋ณ‘๋ ฌ ๊ฒฝ๋กœ ๊ทธ๋ฃน์ด ์ƒ์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์—, Next.js์—์„œ ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒฝ๋กœ ์ถฉ๋Œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

Error: You cannot have two parallel pages that resolve to the same path. 
Please check /(private)/page and /(public)/page.

 


๐Ÿคท‍โ™‚๏ธ ์›์ธ ๋ถ„์„

๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์‚ดํŽด๋ณด๋‹ˆ Next.js์—์„œ๋Š” ๊ฒฝ๋กœ ๊ทธ๋ฃน ์ด๋ฆ„์ด URL์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ , ๋‹จ์ˆœํžˆ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ์œ„ํ•œ ์—ญํ• ๋งŒ ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, (public)/page.tsx์™€ (private)/page.tsx๋Š” ๊ฐ๊ฐ ๋‹ค๋ฅธ ๊ฒฝ๋กœ ๊ทธ๋ฃน์ด์ง€๋งŒ URL ์ƒ์—์„œ๋Š” ๋‘˜ ๋‹ค ๋™์ผํ•œ / ๊ฒฝ๋กœ๋กœ ํ•ด์„๋ฉ๋‹ˆ๋‹ค.

 [์ฐธ๊ณ : https://nextjs.org/docs/app/building-your-application/routing/route-groups]

 

Next.js ๊ฒฝ๋กœ ๊ทธ๋ฃน ๊ด€๋ จ ์‚ฌํ•ญ

  1. ๊ฒฝ๋กœ ๊ทธ๋ฃน์˜ ์ด๋ฆ„์€ URL์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Œ
    (public)์™€ (private)๋Š” URL ๊ตฌ์กฐ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ , Next.js ๋‚ด๋ถ€์—์„œ ๊ฒฝ๋กœ๋ฅผ ๊ตฌ๋ถ„(ํด๋”๋ฅผ ์กฐ์งํ™”ํ•˜๊ธฐ ์œ„ํ•œ ์—ญํ• )ํ•˜๊ธฐ ์œ„ํ•œ ์—ญํ• ๋งŒ ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ, (public)/page.tsx์™€ (private)/page.tsx๋Š” ๋ชจ๋‘ ๋™์ผํ•œ / ๊ฒฝ๋กœ๋กœ ์ธ์‹๋ฉ๋‹ˆ๋‹ค.

  2. ์ค‘๋ณต๋œ ๊ฒฝ๋กœ ์˜ค๋ฅ˜ ๋ฐœ์ƒ(๋ณ‘๋ ฌ ๊ฒฝ๋กœ๋Š” ๋™์ผํ•œ URL์„ ๊ฐ€์งˆ ์ˆ˜ ์—†์Œ)
    ๋™์ผํ•œ ๊ฒฝ๋กœ์— ๋Œ€ํ•ด ๋‘ ๊ฐœ์˜ ํŽ˜์ด์ง€๊ฐ€ ์กด์žฌํ•  ๊ฒฝ์šฐ Next.js๋Š” ๊ฒฝ๋กœ ์ถฉ๋Œ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ๊ฒฝ๋กœ ๊ทธ๋ฃน์„ ์ด์šฉํ•ด ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•ด๋„, ๋™์ผํ•œ URL(/)์— ๋‘ ๊ฐœ์˜ ํŽ˜์ด์ง€๊ฐ€ ์กด์žฌํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 


โœ… ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•: ๊ฒฝ๋กœ ๊ทธ๋ฃน์„ ๊ตฌ๋ถ„ํ•˜๊ณ  ๋ฏธ๋“ค์›จ์–ด๋กœ ์ ‘๊ทผ ์ œ์–ดํ•˜๊ธฐ

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ฏธ๋“ค์›จ์–ด๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํŠน์ • ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๋Š” ๋ฐฉ์‹์„ ์ฑ„ํƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ๋กœ๊ทธ์ธ ์ƒํƒœ์— ๋”ฐ๋ผ /feed์™€ ๊ฐ™์€ ๋ณดํ˜ธ ๊ฒฝ๋กœ ์ ‘๊ทผ์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์—ˆ์œผ๋ฉฐ, ํด๋ผ์ด์–ธํŠธ ์ธก ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์ด ์•„๋‹Œ ์„œ๋ฒ„ ์ธก์—์„œ ์ฒ˜๋ฆฌํ•จ์œผ๋กœ์จ ๋ณด์•ˆ์„ฑ๊ณผ ์„ฑ๋Šฅ ์ตœ์ ํ™” ํšจ๊ณผ๋ฅผ ๋™์‹œ์— ์–ป์„ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

 

์™œ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ–ˆ์„๊นŒ?

1. ๋ณด์•ˆ์„ฑ: ํด๋ผ์ด์–ธํŠธ ์ธก ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์˜ ํ•œ๊ณ„

๋งŒ์•ฝ layout.tsx ๋‚˜ page.tsx์—์„œ ํ† ํฐ ๊ฐ’์„ ๊ฐ€์ ธ์™€ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ†ตํ•ด ํŽ˜์ด์ง€ ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๋ ค ํ•œ๋‹ค๋ฉด, ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ์กฐ๊ฑด๋ถ€๋กœ ํŽ˜์ด์ง€๋ฅผ ์ˆจ๊ธฐ๋Š” ๋ฐฉ์‹์ด ๋ฉ๋‹ˆ๋‹ค. ์ด ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‹จ์ ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

  • ํด๋ผ์ด์–ธํŠธ์—์„œ ์ฝ˜ํ…์ธ ๊ฐ€ ์ž ์‹œ๋ผ๋„ ๋กœ๋“œ๋  ์ˆ˜ ์žˆ์Œ: ํด๋ผ์ด์–ธํŠธ ์ธก ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์€ ํŽ˜์ด์ง€๊ฐ€ ์ด๋ฏธ ๋กœ๋“œ๋œ ์ดํ›„์— ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋‚ด์šฉ์„ ๋ณด์—ฌ์ฃผ๊ฑฐ๋‚˜ ์ˆจ๊น๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์—์„œ ๋น„๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž๊ฐ€ ๋ณดํ˜ธ๋œ ์ฝ˜ํ…์ธ ์˜ ์ผ๋ถ€๋ฅผ ์ž ์‹œ๋ผ๋„ ๋ณผ ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ณดํ˜ธ๊ฐ€ ํ•„์š”ํ•œ ์ฝ˜ํ…์ธ ๋ฅผ ์™„์ „ํžˆ ์ฐจ๋‹จํ•˜๊ธฐ ์–ด๋ ค์›€: ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ์ฝ˜ํ…์ธ ๋ฅผ ์กฐ๊ฑด๋ถ€๋กœ ๋ Œ๋”๋งํ•  ๊ฒฝ์šฐ, ์‹ค์ œ๋กœ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋ณดํ˜ธ๋œ ํŽ˜์ด์ง€๋ฅผ ์š”์ฒญํ•˜๊ณ  ๋กœ๋“œํ•œ ํ›„์— ํ•ด๋‹น ์ฝ˜ํ…์ธ ๊ฐ€ ์ˆจ๊ฒจ์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ณด์•ˆ ์ธก๋ฉด์—์„œ ์™„์ „ํ•œ ์ ‘๊ทผ ์ œ์–ด๊ฐ€ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด, ๋ฏธ๋“ค์›จ์–ด๋Š” ์„œ๋ฒ„ ์ธก์—์„œ ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์ด ์ฒ˜๋ฆฌ๋˜๊ธฐ ์ „์— ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๋ฏ€๋กœ, ๋ณดํ˜ธ๋œ ํŽ˜์ด์ง€์— ๋Œ€ํ•œ ์š”์ฒญ ์ž์ฒด๋ฅผ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค. ํ† ํฐ์ด ์—†๋Š” ์‚ฌ์šฉ์ž๋Š” ์„œ๋ฒ„ ์ธก์—์„œ๋ถ€ํ„ฐ ๋ณดํ˜ธ๋œ ์ฝ˜ํ…์ธ ์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2. ์„ฑ๋Šฅ ์ตœ์ ํ™”: ๋ถˆํ•„์š”ํ•œ ํŽ˜์ด์ง€ ๋กœ๋“œ๋ฅผ ๋ฐฉ์ง€

ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ•œ๋‹ค๋ฉด, ๋น„๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž๊ฐ€ ๋ณดํ˜ธ๋œ ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•  ๋•Œ๋„ ํŽ˜์ด์ง€๊ฐ€ ๋กœ๋“œ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด /feed ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•  ๋•Œ, ๋น„๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž๋Š” ์ฝ˜ํ…์ธ  ๋กœ๋“œ ํ›„์—์•ผ ์ ‘๊ทผ์ด ์ œํ•œ๋˜์—ˆ๋‹ค๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๊ฒŒ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฐฉ์‹์€ ๋‘ ๊ฐ€์ง€ ์„ฑ๋Šฅ ๋ฌธ์ œ๋ฅผ ์•ผ๊ธฐํ•ฉ๋‹ˆ๋‹ค.

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

๋ฏธ๋“ค์›จ์–ด๋Š” ์š”์ฒญ ๋‹จ๊ณ„์—์„œ ๋ฐ”๋กœ ๋ฆฌ๋””๋ ‰์…˜์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋น„๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž๊ฐ€ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” ํŽ˜์ด์ง€์— ๋Œ€ํ•ด ๋ถˆํ•„์š”ํ•œ ๋กœ๋”ฉ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ ๊ฒฐ๊ณผ, ๋น„๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž๋Š” /login๊ณผ ๊ฐ™์€ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ฆ‰์‹œ ๋ฆฌ๋””๋ ‰์…˜๋˜์–ด ํŽ˜์ด์ง€ ๋กœ๋”ฉ๊ณผ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3. ์ผ๊ด€๋œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜: ๋น ๋ฅธ ๋ฆฌ๋””๋ ‰์…˜ ์ฒ˜๋ฆฌ

๋ฏธ๋“ค์›จ์–ด๋Š” ์š”์ฒญ์ด ์„œ๋ฒ„์—์„œ ์ฒ˜๋ฆฌ๋˜๋Š” ๋‹จ๊ณ„์—์„œ ํ† ํฐ ์œ ๋ฌด์— ๋”ฐ๋ผ ์ฆ‰์‹œ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๋ฏ€๋กœ, ๋น„๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž๊ฐ€ ๋ณดํ˜ธ๋œ ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•˜๋ ค ํ•  ๋•Œ ๋น ๋ฅด๊ฒŒ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋””๋ ‰์…˜๋ฉ๋‹ˆ๋‹ค.

  • ํŽ˜์ด์ง€ ์ „ํ™˜์˜ ์ผ๊ด€์„ฑ: ๋ฏธ๋“ค์›จ์–ด์—์„œ ์š”์ฒญ์„ ์ œ์–ดํ•˜๋ฉด, ๋น„๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž๋Š” ๋ณดํ˜ธ๋œ ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•˜๋ ค ํ•  ๋•Œ ์ง์ ‘ /login ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ค‘๊ฐ„์— ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋‚˜ ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€๋ฅผ ๋ณผ ํ•„์š” ์—†์ด ์ผ๊ด€๋œ UX ํ๋ฆ„์„ ์œ ์ง€ํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
  • ์ฆ‰๊ฐ์ ์ธ ํ”ผ๋“œ๋ฐฑ ์ œ๊ณต: ํด๋ผ์ด์–ธํŠธ ์ธก ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์—์„œ๋Š” ํŽ˜์ด์ง€๊ฐ€ ๋กœ๋“œ๋œ ์ดํ›„์—์•ผ ์ ‘๊ทผ ๋ถˆ๊ฐ€ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋Š” ๋ฐ˜๋ฉด, ๋ฏธ๋“ค์›จ์–ด๋ฅผ ํ†ตํ•ด ์ฆ‰์‹œ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๋ฉด ์‚ฌ์šฉ์ž๋Š” ๋น ๋ฅด๊ฒŒ ๋กœ๊ทธ์ธ ํ•„์š” ์ƒํƒœ๋ฅผ ์ธ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ•ด ์„œ๋ฒ„ ์ธก์—์„œ ํ† ํฐ ๊ฒ€์‚ฌ๋ฅผ ์ง„ํ–‰ํ•จ์œผ๋กœ์จ, ๋ณด์•ˆ์„ฑ, ์„ฑ๋Šฅ ์ตœ์ ํ™”, ๊ทธ๋ฆฌ๊ณ  ์ผ๊ด€๋œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๋ชจ๋‘ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ ์ธก ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์€ ํŽ˜์ด์ง€๋ฅผ ์ˆจ๊ธฐ๋Š” ๋ฐ ์ ํ•ฉํ•˜์ง€ ์•Š์œผ๋ฉฐ, ๋ณดํ˜ธ๋œ ์ฝ˜ํ…์ธ ์— ๋Œ€ํ•œ ์™„์ „ํ•œ ์ ‘๊ทผ ์ œ์–ด๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด ๋ฏธ๋“ค์›จ์–ด๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ฝ˜ํ…์ธ ์— ์ ‘๊ทผํ•˜๊ธฐ ์ „ ์š”์ฒญ์„ ์ฐจ๋‹จํ•˜๋ฏ€๋กœ, ๋” ๊ฐ•๋ ฅํ•˜๊ณ  ํšจ์œจ์ ์ธ ๋ฐฉ์‹์œผ๋กœ ๋ณดํ˜ธ๋œ ํŽ˜์ด์ง€ ์ ‘๊ทผ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 


๐Ÿ“ ์ตœ์ข… ๊ตฌํ˜„: ๋ฏธ๋“ค์›จ์–ด๋กœ ์ ‘๊ทผ ์ œ์–ด ์ฒ˜๋ฆฌ

๋ฏธ๋“ค์›จ์–ด์—์„œ ํŠน์ • ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ์ ‘๊ทผ ์ œ์–ด๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ณดํ˜ธ ๊ฒฝ๋กœ์— ๋น„๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž๊ฐ€ ์ ‘๊ทผํ•  ๊ฒฝ์šฐ /๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๋Š” ๊ตฌ์กฐ๋กœ ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ, ์•„๋ž˜์™€ ๊ฐ™์ด ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

src/ 
โ”œโ”€โ”€app/ 
โ”‚  โ”œโ”€โ”€ (private)/
โ”‚  โ”‚   โ””โ”€โ”€ page.tsx // ๋กœ๊ทธ์ธ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์—ฌ์ค„ ํŽ˜์ด์ง€
โ”‚  โ”œโ”€โ”€ (public)/
โ”‚      โ”œโ”€โ”€ feed/
โ”‚          โ””โ”€โ”€ page.tsx // ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ํ”ผ๋“œ ํŽ˜์ด์ง€
โ”œโ”€โ”€ middleware.ts // ๋กœ๊ทธ์ธ ์ƒํƒœ์— ๋”ฐ๋ผ ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๋Š” ๋ฏธ๋“ค์›จ์–ด
  • (public)/page.tsx: ์—ฌ์ „ํžˆ ๋กœ๊ทธ์ธํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž๋ฅผ ์œ„ํ•œ ๊ธฐ๋ณธ ํŽ˜์ด์ง€๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • (private)/feed/page.tsx: ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž๋ฅผ ์œ„ํ•œ ํ”ผ๋“œ ํŽ˜์ด์ง€๋กœ, /feed ๊ฒฝ๋กœ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํŽ˜์ด์ง€๋Š” ๋กœ๊ทธ์ธ๋œ ์ƒํƒœ์—์„œ๋งŒ ์ ‘๊ทผํ•˜๋„๋ก ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • middleware.ts: /feed ๊ฒฝ๋กœ์— ์ ‘๊ทผํ•  ๋•Œ ๋กœ๊ทธ์ธ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜์—ฌ, ๋กœ๊ทธ์ธ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž๋Š” / ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๋„๋ก ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

 

๋ฏธ๋“ค์›จ์–ด๋ฅผ ์„ค์ •ํ•˜์—ฌ ๋กœ๊ทธ์ธ ์—ฌ๋ถ€์— ๋”ฐ๋ผ /feed, /profile, /post, /search ๋“ฑ ํŠน์ • ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค.

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const token = request.cookies.get('userToken'); // ๋กœ๊ทธ์ธ ์ƒํƒœ ํ™•์ธ
  const { pathname } = request.nextUrl;

  // ๋ณดํ˜ธ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ๋กœ๋“ค์„ ์ •์˜
  const protectedPaths = ['/feed', '/profile', '/post', '/search'];

  // ๋กœ๊ทธ์ธ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž๊ฐ€ ๋ณดํ˜ธ ๊ฒฝ๋กœ์— ์ ‘๊ทผํ•˜๋ฉด /๋กœ ๋ฆฌ๋””๋ ‰์…˜
  if (!token && protectedPaths.some((path) => pathname.startsWith(path))) {
    return NextResponse.redirect(new URL('/', request.url));
  }

  return NextResponse.next();
}

export const config = {
  matcher: ['/:path*'], // ๋ชจ๋“  ๊ฒฝ๋กœ์— ๋Œ€ํ•ด ๋ฏธ๋“ค์›จ์–ด ์ ์šฉ ํ›„ ์กฐ๊ฑด๋ถ€๋กœ ์ œ์–ด
};

 

  • ๋กœ๊ทธ์ธ ์ƒํƒœ ํ™•์ธ: userToken ์ฟ ํ‚ค๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ ์ƒํƒœ์ธ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ๋ณดํ˜ธ ๊ฒฝ๋กœ ์กฐ๊ฑด: ๋กœ๊ทธ์ธ ์ƒํƒœ์— ๋”ฐ๋ผ ์ ‘๊ทผ์„ ์ œ์–ดํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ๋กœ(/feed, /profile, /post, /search ๋“ฑ)๋ฅผ ํ•˜๋‚˜์˜ protectedPaths ๋ฐฐ์—ด๋กœ ๊ด€๋ฆฌํ•˜๊ณ , ๋น„๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž์˜ ์ ‘๊ทผ์„ ๋ง‰์Šต๋‹ˆ๋‹ค.
  • ๋ฆฌ๋””๋ ‰์…˜ ์ฒ˜๋ฆฌ: ๋ณดํ˜ธ๋œ ๊ฒฝ๋กœ์— ๋น„๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž๊ฐ€ ์ ‘๊ทผํ•˜๋ฉด /๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๊ณ  ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž๋งŒ ํ”ผ๋“œ ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 


โญ๏ธ ๊ฒฐ๋ก 

Next.js์—์„œ ๊ฒฝ๋กœ ๊ทธ๋ฃน(Route Groups)์€ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ์ •๋ฆฌํ•˜๋Š” ๋ฐ ์œ ์šฉํ•˜์ง€๋งŒ, URL์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋™์ผํ•œ ๊ฒฝ๋กœ์—์„œ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์ด ํ•„์š”ํ•  ๋•Œ ์ถฉ๋Œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ฏธ๋“ค์›จ์–ด๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋กœ๊ทธ์ธ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ํŠน์ • ๊ฒฝ๋กœ ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๋Š” ๋ฐฉ์‹์„ ๋„์ž…ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ๊ฒฝ๋กœ ๊ทธ๋ฃน์˜ ํŠน์„ฑ ์ดํ•ด: ๊ฒฝ๋กœ ๊ทธ๋ฃน์€ ๋””๋ ‰ํ† ๋ฆฌ ์ •๋ฆฌ๋ฅผ ์œ„ํ•œ ๊ฒƒ์ด์ง€, URL ์ž์ฒด์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์„ ์œ ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฏธ๋“ค์›จ์–ด๋ฅผ ํ™œ์šฉํ•œ ์ ‘๊ทผ ์ œ์–ด: ๋ณดํ˜ธ๋œ ๊ฒฝ๋กœ๋ฅผ ์ •์˜ํ•˜๊ณ , ๋ฏธ๋“ค์›จ์–ด๋ฅผ ํ†ตํ•ด ์กฐ๊ฑด๋ถ€ ์ ‘๊ทผ ์ œ์–ด๋ฅผ ๊ตฌํ˜„ํ•จ์œผ๋กœ์จ ๋” ๋‚˜์€ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
  • ๋กœ๊ทธ์ธ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์ฝ˜ํ…์ธ  ์ œ๊ณต: ๋ฏธ๋“ค์›จ์–ด๋กœ ์ธ์ฆ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜์—ฌ, ์‚ฌ์šฉ์ž์˜ ๋กœ๊ทธ์ธ ์ƒํƒœ์— ๋”ฐ๋ผ ๋™์ ์œผ๋กœ ๋‹ค๋ฅธ ํŽ˜์ด์ง€ ์ฝ˜ํ…์ธ ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

 

Comments