<h2>๋ธ๋ก๊ทธ ์ฃผ์ธ</h2> <p> <a href="https://atj.sh">์ ์ฑํ</a>์ด๋ค. </p> <h2>๋ธ๋ก๊ทธ๋ฅผ ์์ํ๋ ์ด์ </h2> <p> ๊ธ์ฐ๊ธฐ๋ฅผ ์ฐ์ตํ๊ณ , ๋ด ๊ฒฝํ๊ณผ ์๊ฐ์ ๋ค๋ฅธ ์ฌ๋์๊ฒ ๋๋๋ ค๊ณ ํ๋ค. </p> <h2>๋ธ๋ก๊ทธ๋ฅผ ๋ง๋ ์ด์ </h2> <p> ์ํํธ์จ์ด ๊ฐ๋ฐ์๋ก์จ ํ์์ ํ์ตํ๊ณ ์ถ์ ํ๋ ์์ํฌ์ ์ธ์ด, ํด๋ค์ด ์์๋ค. </p> <ul> <li><a href="https://www.rust-lang.org/">Rust lang</a> - ํ๋ก๊ทธ๋๋ฐ ์ธ์ด</li> <li><a href="https://github.com/tokio-rs/axum">axum</a> - Rust ๊ธฐ๋ฐ ์น ํ๋ ์์ํฌ</li> <li><a href="https://aws.amazon.com/ko/lambda/">AWS Lambda</a> - ์ปดํจํ ์ธํ๋ผ์คํธ๋ญ์ณ</li> <li><a href="https://postgresql.org/">PostgreSQL</a> - DB</li> <li><a href="https://kit.svelte.dev/">SvelteKit</a> - Svelte ๊ธฐ๋ฐ ์น ํ๋ ์์ํฌ</li> <li><a href="https://pages.cloudflare.com/">Cloudflare Pages</a> - ๋ฌด๋ฃ ์น ํธ์คํ ์๋น์ค</li> <li><a href="https://supabase.com/">Supabase</a> - BaaS & ๋ฌด๋ฃ PostgreSQL ํธ์คํ ์๋น์ค</li> </ul> <p> ์ด๊ฒ๋ค์ ์ต๋จ์๊ฐ์ ํ์ตํ ๋ฐฉ๋ฒ์ ์์๊น ๊ณ ๋ฏผํ๋ค๊ฐ, ์ด๊ฒ๋ค๋ก ๋ด ์ ์ฉ ๋ธ๋ก๊ทธ๋ฅผ ํ๋ ๋ง๋ค๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค๊ณ ์๊ฐํ๋ค. ๊ทธ๋ฌ๋ฉด ํ์ต๋ ๋๊ณ , ํ์์ ํ์ํ๋ ๋ด ์ ์ฉ ๋ธ๋ก๊ทธ ํ๋ซํผ๋ ๋ง๋ค ์ ์์ผ๋๊น ๋ํํ ๋ ์ด๋์ด์๋ค. ์ค์ ๋ก ๋ธ๋ก๊ทธ๋ฅผ ๋ง๋ค ๋ ์ ๊ธฐ์ ๋ค์ ์ ๋ถ ์ฌ์ฉํ๋ค. </p> <h2>๊ธฐ์ ์ ํน์ง</h2> <p> ๋ฐฑ์๋ ๋ถ๋ถ์ Rust ์ธ์ด๋ก ๊ตฌํํ๋ค. axum ์น ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ์ผ๋ฉฐ, ๋ฐฐํฌ๋ AWS Lambda ์ธํ๋ผ์ ๋์ด ์๋ค. </p> <p> ๋ฐ์ดํฐ๋ PostgreSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋๋ฉฐ, Supabase์์ ๋ฌด๋ฃ๋ก ์ ๊ณตํ๋ ์ธ์คํด์ค ์์ ์ ์ฅ๋๋ค. ๊ฐ์ธ ๋ธ๋ก๊ทธ์ฉ์ผ๋ก๋ ์ถฉ๋ถํ ๋๋ํ ์ ๊ฐ์ ๋ณด์๋ค. </p> <p> ํ๋ก ํธ์๋๋ SvelteKit ํ๋ ์์ํฌ๋ก ๊ตฌํํ์๋ค. SSR์ ์ ๊ทน์ ์ผ๋ก ํ์ฉํ๋ค. ์ ์ ๊ฐ ์ํธ์์ฉํ๋ ๋๋ถ๋ถ์ ์ฝ๋๋ SvelteKit์ ์๋ฒ ์ฝ๋๋ก ๊ตฌํ๋์ด ์์ผ๋ฉฐ, ์น ๋ธ๋ผ์ฐ์ ๊น์ง ๋ ธ์ถ๋์ง ์๋๋ค. form๋ ๋ง์ฐฌ๊ฐ์ง์ด๋ฉฐ, form ๊ฒ์ฆ ๋ํ ์๋ฒ ๋ถ๋ถ์์ ์ด๋ฃจ์ด์ง๋ค. ํ๋ก ํธ์๋ ์ฝ๋๋ Cloudflare Pages์ ๋ฐฐํฌ๋์ด ์๋ค. </p> <h2>๋ธ๋ก๊ทธ๋ฅผ ๋ง๋ค๋ฉฐ ๋ง๋ ๋๊ด๋ค</h2> <h3>Cloudflare Pages์ Vercel, SvelteKit</h3> <p> ํ๋ก ํธ์๋ ๋ฐฐํฌ์ ์ด์๊ฐ ํ๋ ์์๋ค. ์ฌ์ค์ ํ๋ก ํธ์๋๋ฅผ <a href="https://vercel.com/">Vercel</a>์ ๋ฐฐํฌํ๊ณ ๋๋ด๋ ค๊ณ ํ์๋๋ฐ, Vercel์ ๋ฐฐํฌํ๊ณ ๋ณด๋ ์๋ฒ๊ฐ ์๊ฐ๋ณด๋ค ๋๋ฆฐ ๊ฒ์ด์๋ค. ์ฒ์์๋ AWS Lambda์ ๋ฐฐํฌ๋ ๋ฐฑ์๋์ Supabase์ PostgreSQL์ ์์ฌํ์๋๋ฐ, ์ ์ ๋ก์ปฌ์์ Lambda ์๋ฒ๋ฅผ ํธ์ถํ ๋์๋ ์๋๊ฐ ํ๋๋ ๋๋ฆฌ์ง ์์ ์ ์ด ์ด์ํ๋ค. </p> <p> ๊ทธ๋์ ํ๋ก ํธ์๋ ๋ฐฐํฌ ์์น๋ฅผ ๋ฐ๊พธ๊ธฐ๋ก ๊ฒฐ์ ํ๋ค. ํ๋ณด๊ตฐ์ ๋ง์ง ์์๋ค. Netifly, Cloudflare Pages, Vercel ์ ์ค ํ๋๋ฅผ ๊ณ ๋ฅด๊ฑฐ๋, AWS ์ธํ๋ผ์ ๋ด๊ฐ ์ง์ ๋ฐฐํฌํ๋ ๋ฐฉ๋ฒ์ ํํด์ผ ํ๋ค. ํนํ SSR์ ์ ๊ทน ํ์ฉํ๋๋ก ๊ตฌํ๋ ์ฝ๋๋ก์จ๋ ์ ์ ๋น๋๋ ์ด๋ ค์ด ์ํฉ์ด์๊ธฐ ๋๋ฌธ์, ์ ์ค์์ ๊ณ ๋ฅด์ง ๋ชปํ๋ฉด ๋ด๊ฐ ์ง์ SvelteKit์ ๋ฐฐํฌํด์ผ ํ๋ ์์ ์ ์งํํด์ผ ํ์ ๊ฒ์ด๋ค. </p> <p> ๊ทธ๋ฐ๋ฐ ๊ทธ ์์ค์ <a href="https://www.cloudflarestatus.com/incidents/hm7491k53ppg">Cloudflare์ ๋์๋ณด๋ ์ธํ๋ผ์ ์ฅ์ ๊ฐ ๋ฐ์</a>ํ๋ค. ํํ Cloudflare Pages์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐฐํฌํด๋ณผ ๋ ๋ฐ์ํด์, ์ ๋๋ก ๋ ํ ์คํธ๋ฅผ ์ฒ์์๋ ํ ์ ์์๋ค. ์ดํ ์ ๋ ๊ธฐ๋ค๋ฆฌ๋๊น ์ฅ์ ๊ฐ ํด๊ฒฐ๋ ๋ชจ์์ธ์ง, ์ ์์ ์ผ๋ก ๋ฐฐํฌํด๋ณผ ์ ์์๋ค. </p> <p> ๋คํํ๋ Cloudflare Pages๋ ๋ฌด๋ํ ์ฑ๋ฅ์ ๋ฝ์์ฃผ๋ ๊ฒ์ ํ์ธํ ์ ์์๋ค. ํนํ, ์ด์ ์ Cloudflare Pages์ ๋ฆฌ์กํธ ์ฑ์ ๋ฐฐํฌํด๋ณธ ์ ์ด ์์๊ธฐ ๋๋ฌธ์, SvelteKit ์ฑ ๋ฐฐํฌ ๋ํ ์ด๋ ต์ง ์์๋ค. ๋ค๋ง, ์๋๋ ํ๋ก ํธ์๋ ํจํค์ง ๋งค๋์ ๋ก <a href="https://bun.sh/">bun</a>์ ์ฌ์ฉํ๊ณ ์์๋๋ฐ, SvelteKit์ bun์ ์ฌ์ฉํ ๋น๋ ์ต์ ์ด ์กด์ฌํ์ง ์์ bun ์ฌ์ฉ์ ํฌ๊ธฐํ๋ ์ผ์ด ์์๋ค. ๋์ค์ bun ์ง์์ด ์ถ๊ฐ๋๋ฉด ๋ค์ ์ฌ์ฉํด๋ณผ ์ํฅ์ด ์๋ค. </p> <p> ๋ฐฐํฌ ์์ฒด๋ ๋ฐ๋ก ์งํํ์ผ๋ Cloudflare Pages์ ๋ฐฐํฌ๋ ํ ์ฑ์ด '500 ์๋ฌ'๋ฅผ ๋ด๋ฉฐ ์๋ํ์ง ์๋ ํ์์ด ๋ฐ์ํ๋ค. SSR๊น์ง๋ ์๋ํ๋ ๋ด๋ถ ๋ก์ง ์ด๋๊ฐ์์ ์๋ํ์ง ์๋ ๋ชจ์์ด์๋ค. ๋ถ์ํด๋ณธ ๊ฒฐ๊ณผ, Cloudflare Pages์ js ์คํ ํ๊ฒฝ(Cloudflare Workers)์ ๋ฌธ์ ์ธ ๊ฒ์ผ๋ก ํ์ธ๋์๋ค. fetch ํจ์์ ์ผ๋ถ ๊ธฐ๋ฅ์ด ์ง์๋์ง ์์ ์๋ฒ(๋ฐฑ์๋, AWS Lambda)๋ก๋ถํฐ์ ๋ฐ์ดํฐ ๋ก๋ฉ์ ์คํจํ๋ ๊ฒ์ด์๋ค. ๊ทธ๋์ fetch ํจ์ ํธ์ถ ์ ๋ถํ์ํ ์ฝ๋๋ฅผ ์ญ์ ํ๋๋ฐ, ๊ทธ๋ฌ๋๋ ์ ์๋ํ๋ค. <a href="https://github.com/atjsh/rust-blog/commit/2c03c79d73dcb83dc741640203e147a94c061229">๋น์ ์์ ์ปค๋ฐ</a> </p> <h3>Rust & AWS Lambda</h3> <p> AWS Lambda๋ก ๋ฐฐํฌํ๊ณ ๋๋ฉ์ธ ์ฃผ์๋ฅผ ํ ๋นํ๋ ์์ ์ <a href="https://www.mini-dice.com">Mini Dice</a> ์๋น์ค๋ฅผ ๊ตฌํํด๋ณด๋ฉฐ ์ด๋ฏธ ํด๋ณธ ์์ ์ด๋ผ ๋ณ๋ก ์ด๋ ต์ง ์์๋ค. ์ด ๋น์์๋ AWS Lambda๋ก ๋ฐฐํฌํ๊ณ API Gateway(HTTP)๋ฅผ ํตํด ์ธ๋ถ์ ์ ๊ทผํ ์ ์๋๋ก ์ค์ ํ์๋๋ฐ, ๋์ผํ ๋ฐฉ์์ผ๋ก ์ค์ ํ๋ ์ด๋ ต์ง ์๊ฒ ๋๋ฉ์ธ ์ฐ๊ฒฐ๊น์ง ์งํํ ์ ์์๋ค. ์ฐธ๊ณ ๋ก ๋๋ฉ์ธ์ AWS Route 53์ ํตํด ๊ด๋ฆฌ๋๊ณ ์์๊ธฐ์ ์์ ์ด ๋ ์ฌ์ ๋ค. </p> <p> AWS Lambda์ฉ์ผ๋ก axum์ ๋น๋ํ๋ ๊ณผ์ ๋ํ ์ด๋ ต์ง ์์๋ค. AWS์์ ์ง์ ์ ๊ณตํ๋ <a href="https://docs.rs/lambda_http/latest/lambda_http/">`lambda_http` rust crate</a>๋ฅผ ์ฌ์ฉํ๋ฉด ์ผ๋ฐ axum ์ฑ์ฒ๋ผ ์ฝ๋๋ฅผ ์์ฑํ๊ณ AWS Lambda์ ๋ฐฐํฌํ ์ ์๋ค. ๋ก์ปฌ ํ ์คํธ ๋ํ ์ฝ๋ ๋ณ๊ฒฝ์์ด <a href="https://www.cargo-lambda.info/commands/watch.html">`cargo lambda watch` ๋ช ๋ น์ด</a>๋ก ์งํํ ์ ์์๋ค. ์๊ฐ๋ณด๋ค ํธํด์ ๋๋๋ค. </p> <h2>์ฒซ ๋ฒ์ ์ ๋ง๋ค๊ณ ์ ๋๋ ์ </h2> <p> ๊ธฐ๋ถ์ด ์ข์๋ค. ๊ทธ๋ฆฌ๊ณ Rust ์ธ์ด๋ก ๋ญ ๋ง๋ค์ด๋ณธ ์ ์ด ํ ๋ฒ๋ ์์๋๋ฐ, ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ํ๋ ๋ง๋ค์ด๋ณด๋ Rust์ ๋ํ ์์ ๊ฐ์ด ์๊ฒผ๋ค (์๋๋ ๋ฌด์์ ๋ค). ๋์ค์๋ ๋ ๋ณต์กํ ์ฑ์ ๋ง๋ค์ด๋ณผ ์๊ฐ์ด๋ค. ์์ ์ธ๊ธํ Mini Dice ์๋น์ค๋ฅผ Rust๋ก ํฌํ ํด๋ณด๋ ๊ฒ๋ ์ฌ๋ฐ์ ๊ฒ ๊ฐ๋ค. SvelteKit ๋ํ ์ ์ ํ๊ณ ๋ ๋ ํ ๋๋์ด ๋ค์ด ๋์์ง ์์๋ค. CSS ์ง์์ด ๋ด์ฅ๋์ด ์๊ณ ์ด๋ ต์ง ์์ ์ข์๋ค. ํ์ ์ง์ ๋ํ ๊ต์ฅํ ์ ๋์ด์๋ ๊ฒ์ ๋๋๋ค. ์์ฌ์ด ๋ถ๋ถ์ด ๋ง์ง ์์๋ค. ๋ฌผ๋ก ์๋ฐ ๊ฒ ํฅ๊ธฐ ์์ผ๋ก ์จ๋ณธ ์ํ์ด๊ธด ํ์ง๋ง, Svelte์ ๊ธฐ๋ณธ์ ์ธ ํ ํ๋ฆฟ ๋ฌธ๋ฒ๊ณผ ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ์ ์จ๋ณผ ์ ์์ด์ ์ข์๋ค. </p> <p> ์ดํ์๋ ์ฝ๋ ์ ๋ฆฌ์ ๋์์ธ ๊ฐ์ , ๊ทธ๋ฆฌ๊ณ ๊ด๋ฆฌ์ ํ์ด์ง ๊ฐ์ ์ ํ์จ๋ณผ ์๊ฐ์ด๋ค. ํ์ฌ ์์ค์ฝ๋ ์ ์ฒด์ ์ผ๋ก ์ฝ๋ ์ค๋ณต์ด ์ฌํ ํธ์ด๋ค. ๋น์ฆ๋์ค ๋ก์ง์ ํจ์ํํ์ง ์๊ณ ์ฌ๊ธฐ์ ๊ธฐ์ ๊ฐ์ ธ๋ค ์จ์ ๋ฐ์ํ ๋ฌธ์ ์ธ๋ฐ, ์๊ณ ์๋ ๋์์ธ ํจํด๋ค์ ์ ์ฉํด์ ์ด๋ฅผ ํด๊ฒฐํด๋ณด๋ ค๊ณ ํ๋ค. ํ์์๋ NestJS์ DI ์์คํ ์ ์น์ํด์ ธ ์์๋๋ฐ, DI ์์คํ ์์ด ๋ฐฑ์๋๋ฅผ ์ง๋ณธ ๊ฒ์ด ์ค๋๋ง์ด๋ผ ์ฝ๋ ์ค๋ณต์ด ๋ ์ฌํ ๊ฒฝํฅ์ด ์๋ ๊ฒ ๊ฐ๋ค. ์ฝ๋๋ฅผ ๋ฆฌํฉํ ๋งํ๋ฉฐ ๋์์ธ ํจํด์ ๋ค์ ๋์๋ณผ ๊ธฐํ๋ฅผ ๊ฐ์ง ์ ์์ ๊ฒ ๊ฐ๋ค. ๋์์ธ์ ์ต๋ํ ์ฌํํ๊ฒ ๊ฐ์ ธ๊ฐ๊ณ , ๊ด๋ฆฌ์ ํ์ด์ง๋ ๋ด๊ฐ ํธํ ๋ฐฉํฅ์ผ๋ก ๋์์ธํ๋ฉด ๋๋๊น ํฐ ๋ฌธ์ ๋ ์๋๋ค. </p> <p> ์ฐธ๊ณ ๋ก ๊ด๊ณ ๋ ์์ง ๋ฌ ์๊ฐ์ด ์์ผ๋ฉฐ, ํต๊ณ/์ ์ ์ถ์ ๊ธฐ๋ฅ ๋ํ ์์ง ์๊ฐ์ด ์๊ณ , ๋๊ธ ๊ธฐ๋ฅ๋ ์์ง์ ์๊ฐ์ด ์๋ค. ๊ทธ๋ฐ๋ฐ ๋๊ธ์ ๊ตฌํ์ด ์ฌ์ด ํธ์ผํ ๋ฐ, ํ์ํ๋ฉด ๊ตฌํํ ์๊ฐ์ ์๋ค. ์, ๋์ ์น์ฌ์ดํธ์ ๋คํฌ ๋ชจ๋๋ ๊ผญ ๋ฃ๊ณ ์ถ๋ค. ๋ด๊ฐ ๋คํฌ ๋ชจ๋ ์ค๋ ์๋ผ ๊ทธ๋ ๋ค. </p> <h2>์์ค์ฝ๋</h2> <a href="https://github.com/ATJSH/rust-blog"> <img src="https://blog.atj.sh/post-attachments/v/01953d72-712b-7f90-8a97-c89743cd6dfc" width="10%"/> <br /> <p> https://github.com/ATJSH/rust-blog</a>์์ ์๋ณธ ์์ค์ฝ๋๋ฅผ ํ์ธํ ์ ์๋ค. </p> <h2>๊ฐ์ ํ ์ ๋ค</h2> <a href="https://github.com/atjsh/rust-blog/issues">https://github.com/atjsh/rust-blog/issues</a>์์ ํ์ธํ ์ ์๋ค.