- Published on
๐ PROJECT | ๋ธ๋ก๊ทธ ์ ์ง๋ณด์ ์ผ๊ธฐ #3
Locomote the world ์ ์ง๋ณด์ ๊ธฐ๋ก
์ด๋ฒ ์ ๋ฐ์ดํธ์ ์์ฝ์ ์๋์ ๊ฐ๋ค.
- Nextjs 15๋ก ์ ๊ทธ๋ ์ด๋
- Tailwind CSS 4๋ก ์ ๊ทธ๋ ์ด๋
- TypeScript 5๋ก ์ ๊ทธ๋ ์ด๋
- ์์ ํ๋ ํธ์ ์ฝ๊ฐ ๋ณ๊ฒฝ์ด ์์๋ค. (๊ธฐ์กด์๋ gray๋ฅผ neutral๋ก ๋์ฒดํด์ ์ฌ์ฉ).
- Clean coding & Refactoring
- Home hero threejs ์ ๋๋ฉ์ด์ ์ถ๊ฐ
Tailwind Nextjs ๋ธ๋ก๊ทธ์ ์ ๋ฐ์ดํธ
์ด ๋ธ๋ก๊ทธ๋ v2 ๋์ค๊ธฐ ์ 2022๋ ์ ์์์ผ๋ก ์ ์ํด์, 2๋ ์ ๋ฐ๋ v2๋ก ๋ฐ์ํด์ ์ ๋ฐ์ดํธ ํ์ง ์์์๋ค. ์๋๋ ๊ณต์ ๋ฆฌํฌ์งํฐ๋ฆฌ ์ ๋ฐ์ดํธ ๋ก๊ทธ ๋งํฌ.
๊ธฐ์กด page router ๋ฐฉ์์์ app router ๋ฐฉ์์ผ๋ก ๋ณ๊ฒฝ๋์๊ณ , ๊ทธ์ ๋ฐ๋ผ ํ์ด์ง ๊ตฌ์กฐ๊ฐ ๋ฐ๋์๋ค. ๋ํ tailwindcss v4๋ก ์
๊ทธ๋ ์ด๋ ๋๋ฉด์, ์ค์ ์ด ๋ณ๊ฒฝ๋์๋ค๋ ์ , ๊ทธ๋ฆฌ๊ณ ๋ฆฌํฉํ ๋งํ๋ฉด์ analytics๋ผ๋๊ฐ function์ ์ธ ๋ถ๋ถ๋ค์ ์ ๋ถ pliny
๋ก ์์ฒด third party๋ก ๋ง๋ค์ด์ ๋๋์ ์ผ๋ก ์
๋ฐ์ดํธํ ๋ชจ์.
์๋๋ javascript๋ฅผ ์ฌ์ฉํ๋ฉด์ ๊ธฐ์กด ๊ฒ๊ณผ ๋น๊ตํ๋ฉด์ ์กฐ๊ธ์ฉ migration์ ์งํํ๊ณ ์์๋๋ฐ, ์์ ์๋ ์ค๋ฅ๋ก ๊ทธ๋ฅ v2 ์์์ ๋ค์ ์์ ํ๊ฒ ๋์๋ค. ๊ทธ๋์ ๊ฑฐ์ ์ผ์ฃผ์ผ์์ ๋ด์ง๋ 10์ผ๋์ ๊ฒ์ผ๋ฆ ํผ์ฐ๋ฉด์ ์์ ์ ์งํํ๋ค.
App router vs Page router
์ ์ค๋ช ๋์ด ์๋ ๋ธ๋ก๊ทธ ๊ธ์ ์ฐพ์์ ์๋ ๋งํฌ๋ฅผ ๋จ๊ธด๋ค.
๊ณต์ ๋ฌธ์์์๋ ์๋ฌด๋ฆฌ ์ฐพ์๋ด๋.. ์๋ก์ด ๊ธฐ๋ฅ๋ค์ ์ด์ฉํ ์ ์๋ค. ์ด๋ฐ์์ ์ค๋ช ๋ฐ์ ์์ด์ ์ผ๋จ์ ์๋ก์ด ๋ฐฉ๋ฒ์ ๋์ ํ๋ ๊ฒ์ ๋์์ง ์๋ค๋ ์๊ฐ์ app router๋ก ๋ณ๊ฒฝํ๋ค. ๊ฐ์ธ์ ์ผ๋ก๋ app router๊ฐ ๋ ์ง๊ด์ ์ด๊ฒ ๋๊ปด์ก๋ค.
custom api๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ๋ฐ๋ก api ํด๋๋ฅผ ๋ง๋ค๊ณ ๊ทธ ์์ ๊ด๋ จ ๊ธฐ๋ฅ๋ค์ ๋ฃ์ผ๋ฉด ๋๋ค.
๋ฐ๋ v2์์๋ ๋์ผํ๊ฒ ํ๋๋ฐ, ๊ตฌ์กฐ๋ ๋น์ทํ๊ฒ ๋ง๋ค๊ณ ์๋์ ๊ฐ์ด handler๊ฐ ์๋๋ผ ์๋ ํ
ํ๋ฆฟ๊ณผ ๊ฐ์ด ๋ง๋ค๋ฉด ๋๋ค.
export async function GET(
_request: NextRequest,
props: { params: Promise<{ query: string }> },
) {
try {
const params = await props.params;
if (!API_KEY) {
return NextResponse.json(
{ error: "Missing API configuration" },
{ status: 500 },
);
}
const url = `YOUR_API/?range=/${params.query}/?key=${API_KEY}`;
const response = await fetch(url);
if (!response.ok) {
return NextResponse.json(
{ error: "Failed to fetch data" },
{ status: response.status },
);
}
const data = await response.json();
return NextResponse.json({ data: [data.values] });
} catch (error) {
console.error("Error fetching", error);
return NextResponse.json(
{ error: "Internal Server Error" },
{ status: 500 },
);
}
}
api๋ฅผ ์ฌ์ฉํ๊ณ ์ถ์ ๋๋ ์๋์ ๊ฐ์ด ์ฌ์ฉํ๋ฉด ๋๋ค.
const response = await fetch(`/api/example/${encodeURIComponent(query)}`);
Tailwindcss v4
tailwindcss v4๋ก ์
๊ทธ๋ ์ด๋ ๋๋ฉด์, ๋ ์ด์ tailwind.config.js
ํ์ผ์ ์ฌ์ฉํ์ง ์๋๋ค. ๋จ์ tailwind.css
๋ก ํต์ผ๋์๋๋ฐ, ์ด๊ฒ ์๊ฐ๋ณด๋ค.. ์๋ฌ๊ฐ ๊ฝค๋ ๋ง์ด ๋ฌ์๋๋ฐ, ์์ง๋ ์์ธ์ ํ์
์ ๋ชปํ๋ค.
๊ด๋ จ ์ค๋ฅ๋ ์๋ ๊น ์ด์์ ๊ฐ์ ์ด์๋ค์ด ์ฌ๋ฌ ์ฐจ๋ก ์์๋ค.
์ํผ.. ๊ธฐ์กด tailwind.config.js
์์๋ ์ ๋๋ฉ์ด์
๋ง์ด๊ทธ๋ ์ด์
ํ ๋๋ง๋ค ํฐ์ ธ์ ์์ ๋ง์ถ๋ฉด์ ํด๊ฒฐํ๋ ๊ฒ์ผ๋ก ๊ธฐ์ตํ๋๋ฐ, ์ฐ์ฐํ๊ฒ ๋ง๋ฌด๋ฆฌํ ๊ฒ ๊ฐ์์ ํ ...
Clean coding & Refactoring
๊ฐ์ธ์ ์ผ๋ก pliny
๋ก ๊ธฐ๋ฅ๋ค์ ๋บ๊ฒ์ด ์กฐ๊ธ ์์ฌ์ ๋ค. third party๋ค ๋ณด๋๊น ์ด๊ฑธ forkingํด์ ๊ฐ์ธ์ด ์ปค์คํ
ํ๋ ๋ฐฉ๋ฒ ๋ฐ์ ์๊ณ , ๋์์ธ์ ๋๋ฌด.. ์์ฑํ ์ํ์์ ์ฌ๋ฆฌ๋ค๋ณด๋ ์ปค์คํ
์ด ์์ ์ด ์ด๋ ต๋ค๊ธฐ ๋ณด๋จ ๊ท์ฐฎ์์๋ค.
UI ๊ธฐ๋ฅ์ ๊ฑฐ์ ์ฌ์ฉํ์ง ์๋ ๊ธฐ๋ฅ๋ค ์์ฃผ(ex. comments)๋ง ์ฌ์ฉํ๊ณ , ๊ทธ์ธ๋ ๊ธฐ์กด์ ๋ด๊ฐ ๋ง๋ค๋ ๊ฒ๋ค๋ง typescript๋ก ์ฎ๊ฒผ๋ค.
๊ธฐ์กด ํ์ฌ์์ ๋ฐฐ์ฐ๋ refactoring ๋ฐฉ๋ฒ์ ๊ฐ์ ธ์ค๋, convention์ ๊ณต์ nextjs์ ๋ง๊ฒ๋ ํ๋ ค๊ณ ํ์๊ณ , typescript์ ๋ช
์์ ์ธ type ์ง์ ์ ๋ช๋ถ๋ถ ์ํํ ํ๊ฒ ์ข ๋ฐ์ฑ ํฌ์ธํธ..
Wrapup & Conclusion
10์ผ ์ฌ๊ฐ ๋์ ๋ค์ locomote the world๊ฐ v2๋ก ์๋กญ๊ฒ 2025๋
์ ๊ฐํธ์ด ๋์๋ค. ๋๋์ ์ธ ๋์์ธ ๋ณ๊ฒฝ์ด๋ผ๊ธฐ ๋ณด๋จ ๋ถ์ฐ์ค๋ฌ์ด ๋ถ๋ถ๋ค์ ๋๊ฑฐ ์ถ์ํ๋ค. ๋ฃ๊ณ ์ถ์๋ threejs ๊ธฐ๋ฅ๋ home hero์ ์ถ๊ฐ๋ ๊ฑฐ ์ธ์ ํฌ๊ฒ ์์ ๊ฒ ๊ฐ๋ค.
์ผ๋จ.. ๋ถํ์ํ๋ ์ฝ๋๋ค์ ๋์ฒด๋ก ๋ง์ด ์ ๋ฆฌํ๋ค๋ ๊ฒ์ ์ด๋ฒ ๋ฒ์ ์์ ๋ง์กฑํ๋ ๊ฒ์ผ๋ก.. ๋ค์์๋ ๋ ์ ๋ง๋ค์ด๋ด์ผ๊ฒ ๋ค.(ํ์ฌ์์ ๋ฐฐ์ด ๊ฒ๋ค ์ ์ธ๋จน์๋ค..ใ
ใ
)
๋ค์ ๋ฒ์ ์์๋ ์๋์ ๊ฐ์ ๊ฒ๋ค์ด ์์ ๋ ์์ ์ด๋ค.
- ํฌํธํด๋ฆฌ์ค ๋ฐ์ดํฐ ์ ๋ฐ์ดํธ
- ํฌํธํด๋ฆฌ์ค ์์ธํ ๋ณด๊ธฐ ๋ฐ ํฌ์คํธ๋ชจํ ์ฐ๊ฒฐ
- ๋ธ๋ก๊ทธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ด๋ฏธ์ง ์ถ๊ฐ
- Authors
- Name
- Amelia Young
- GitHub
- @ameliacode