๋ถ๋ฅ ์ ์ฒด๋ณด๊ธฐ (18) ์ธ๋ค์ผํ ๋ฆฌ์คํธํ Express ์ปค์คํ ์๋ฒ๋ฅผ Next.js API Routes๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ๊ธฐ ๋ค์ด๊ฐ๋ฉฐ๋ ๊ฑฐ์ ์ฝ๋๋ฅผ ๋ฆฌํฉํ ๋งํ ๋ ๊ฐ์ฅ ์ด๋ ค์ด ์ ์ "์ ์ด๋ ๊ฒ ๋ง๋ค์ด์ก์๊น?"๋ฅผ ์ดํดํ๋ ๊ฒ์ ๋๋ค. ์ ๊ฐ ๊ฐ๋ฐํ๊ณ ์๋ WMS(Warehouse Management System) ํ๋ก์ ํธ๋ ๋ง์ฐฌ๊ฐ์ง์์ต๋๋ค. Next.js ๊ธฐ๋ฐ ํ๋ก์ ํธ์์๋ ๋ถ๊ตฌํ๊ณ ๋ณ๋์ Express ์ปค์คํ ์๋ฒ๋ฅผ ์ด์ํ๊ณ ์์๋๋ฐ, ์ด๊ธฐ์๋ API ํ๋ก์ ๊ธฐ๋ฅ์ ๋น ๋ฅด๊ฒ ๊ตฌํํ๊ธฐ ์ํ ์ ํ์ด์์ ๊ฒ์ ๋๋ค.ํ์ง๋ง ์๊ฐ์ด ์ง๋๋ฉฐ ์ด ์ ํ์ ๊ธฐ์ ๋ถ์ฑ๋ก ์์ฌ๊ฐ๊ณ , ๊ฒฐ๊ตญ 1,056์ค์ ๊ฑฐ๋ํ ๋จ์ผ ํ์ผ์ด ๋์ด ์ ์ง๋ณด์์ ๋ฐ๋ชฉ์ ์ก์์ต๋๋ค.๋ฌธ์ ์ํฉ1,056์ค์ง๋ฆฌ Express ์๋ฒ์ ํ๊ณWMS ํ๋ก ํธ์๋ ํ๋ก์ ํธ๋ Next.js ๊ธฐ๋ฐ์ด์ง๋ง, API ํ๋ก์๋ฅผ ์ํด ๋ณ๋์ Express ์ปค์คํ ์๋ฒ(server/index.js)๋ฅผ ์ฌ์ฉํ๊ณ .. Next.js ๋น๋ ์ต์ ํ : Babel → SWC ์ ํ ๋ฌธ์ ์ํฉํ๋ก์ ํธ ๋น๋ ์๊ฐ์ด 1๋ถ 30์ด๋ฅผ ์ด๊ณผCI/CD ํ์ดํ๋ผ์ธ์์ ๋ณ๋ชฉ ๋ฐ์์์ธ ๋ถ์๋น๋ ๋ก๊ทธ ํ์ธ ๊ฒฐ๊ณผinfo - Disabled SWC as replacement for Babel because of custom Babel configuration ".babelrc"์ฃผ์ ๋ฌธ์ ์ :.babelrc ํ์ผ๋ก ์ธํ SWC ๋นํ์ฑํ738MB ํฌ๊ธฐ์ node_modules1MB ์ด์์ ๋์ฉ๋ ๋ฒ๋ค200๊ฐ ์ด์ ํ์ด์ง์ SSR ์ค์ ํด๊ฒฐ ๊ณผ์ 1. SWC ์ปดํ์ผ๋ฌ ํ์ฑํrm -f .babelrc// next.config.jsconst nextConfig = { // SWC ๊ฐ์ ํ์ฑํ swcMinify: true, // ๋น๋ ์ต์ ํ experimental: { forceSwcTransforms: t.. Monorepo ๋์ ๊ธฐ: ํ๋ก ํธ์๋ ๋ง์ด๊ทธ๋ ์ด์ ์ค๊ณ ์ ๋ฆฌ 1. ๊ฐ์๋ณธ ๋ฌธ์์์๋ Legacy Web๊ณผ Mobile์ ๋ชจ๋ ธ๋ ํฌ ํ๋ก์ ํธ๋ก ํตํฉํ๋ ์ค๊ณ์ ์ ํ ์ ๋ต์ ์ ์ํฉ๋๋ค.2. ํ์ฌ ์ํฉ & ๋ฌธ์ ์ ๊ธฐ์ ์คํNext.js 12.3.6 + JavaScript(ES6)MobX 6.5.0, Material-UI v4React Query v3, Axios, npm์ฃผ์ ๋ฌธ์ ๊ฐ๋ฐ ํ๊ฒฝ ๋ณต์กExpress ๊ธฐ๋ฐ ์ปค์คํ ์๋ฒ(500+์ค), API ํ๋ก์ ์ค๋ณตํ๊ฒฝ ๋ณ์ ๊ด๋ฆฌ ๋์ด๋ ๋์ํด๋ ๊ตฌ์กฐ ๋นํ์คํv1/v2 ํผ์ฌ, Atomic Design ์ผ๋ถ ์ ์ฉ์ปดํฌ๋ํธ ์ฌ์ฌ์ฉ์ฑ ๋ฎ์์ฝ๋ ๋ฐ ์์กด์ฑ ์ค๋ณต๋์ผ ๋ก์ง·UI๋ฅผ ๋ ํ๋ก์ ํธ์ ์ค๋ณต ๊ตฌํ์์กด์ฑ 100% ์ค๋ณต ์ค์น๊ธฐ์ ๋ถ์ฑNext.js 12, React 17, MUI v4 ๋ฑ ๊ตฌ๋ฒ์ JavaScript → TypeScript ํ์๋.. Next.js ์ด๊ธฐ ๋ ๋๋ง ์ ๋ค๊ตญ์ด ๋ฌธ๊ตฌ๊ฐ ๋น์ด ๋ณด์ด๋ ๋ฌธ์ ํด๊ฒฐํ๊ธฐ Next.js ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ค๊ตญ์ด๋ฅผ localStorage ๊ธฐ๋ฐ์ผ๋ก ์ฒ๋ฆฌํ ๋ ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.์ด๊ธฐ ํ๋ฉด ๋ก๋ฉ ์ ๋ฒํผ ํ ์คํธ๊ฐ ๋น์ด ์์์๋ก๊ณ ์นจ ํ์๋ ์ ์์ ์ผ๋ก ๋ค๊ตญ์ด ๋ฌธ๊ตฌ๊ฐ ํ์๋จ์ ๋ฌธ์ ์ ์์ธ์ ๋ถ์ํ๊ณ ํด๋ผ์ด์ธํธ ํ๊ฒฝ์์ ๋ค๊ตญ์ด๋ฅผ ๋ถ๋ฌ์ค๋๋ก ์์ ํ๊ณ , ์ฑ๋ฅ ์ต์ ํ ์์ ์ ํด๋ณด์์ต๋๋ค.๋ฌธ์ ์์ธconst DUMMY_DATA = [ { id: 0, name: getLang("WD000266"), ... }, ...];getLang(code)๋ localStorage์์ ๋ค๊ตญ์ด ๋ฌธ์์ด์ ๋ถ๋ฌ์ค๋ ํจ์์ ๋๋ค.export const getLang = (code) => { if (typeof window !== "undefined") { const langL.. useState์ ๋น๋๊ธฐ์ฑ ์ด๋ฒ ๊ธ์์๋ useState๊ฐ ๋น๋๊ธฐ์ ์ผ๋ก ๋์ํ๋ ์๋ฆฌ์ ์ฌ๋ฐ๋ฅธ ์ฌ์ฉ ํจํด์ ๋ํด ๋ค๋ค๋ณด๊ฒ ์ต๋๋ค. ๋จผ์ ๋น๋๊ธฐ์ ์ด๋ผ๋ ๊ฒ์ setState๋ฅผ ํธ์ถํ ์งํ์ ์ํ๊ฐ ์ฆ์ ๋ฐ์๋์ง ์์์ ์๋ฏธํฉ๋๋ค.const [count, setCount] = useState(0);const handleClick = () => { setCount(count + 1); console.log(count); // ์ฌ์ ํ setCount ์ด์ ๊ฐ์ธ 0์ด ์ถ๋ ฅ๋จ}; ์ ์ฝ๋์์ handleClick์ ํธ์ถํ๋ฉด setCount(count + 1)์ด ์คํ๋์ง๋ง, console.log(count)๋ ์ฌ์ ํ ์ด์ ๊ฐ์ธ 0์ ์ถ๋ ฅํฉ๋๋ค. useState๊ฐ ๋น๋๊ธฐ์ ์ผ๋ก ๋์ํ๋ ์๋ฆฌ์ด๋ฌํ ๋น๋๊ธฐ์ฑ์ด ๋ฐ์ํ๋ ์ด์ ๋ ๋ ๋๋ง ์ฑ๋ฅ์ ์ต์ .. React key prop๊ณผ ์ํ ์ด๊ธฐํ React์์ key prop์ ๋ฆฌ์คํธ๋ iterable ๊ฐ์ฒด ๋ ๋๋ง ์ ์ค์ํ ์ญํ ์ ํ์ง๋ง, ์ํ(state) ๊ด๋ฆฌ์๋ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค.key์ ์ญํ React์์ key๋ ๊ฐ ์ปดํฌ๋ํธ์ ๊ณ ์ ์ฑ์ ๋ณด์ฅํ์ฌ ๋ณ๊ฒฝ ์ฌํญ์ ํจ์จ์ ์ผ๋ก ๊ฐ์งํ๊ณ ์ ๋ฐ์ดํธํ๋ ์ญํ ์ ํฉ๋๋ค.๋ฆฌ์คํธ๋ฅผ ๋ ๋๋งํ ๋ key๊ฐ ๋ณ๊ฒฝ๋์ง ์์ผ๋ฉด ๊ธฐ์กด์ ์ปดํฌ๋ํธ๊ฐ ์ ์ง๋๋ฉฐ, ๋ณ๊ฒฝ๋๋ฉด ํด๋น ์ปดํฌ๋ํธ๋ ์๋ก์ด ๊ฒ์ผ๋ก ์ธ์๋ฉ๋๋ค.key๊ฐ state์ ๋ฏธ์น๋ ์ํฅkey๊ฐ ๋ณ๊ฒฝ๋๋ฉด React๋ ๊ธฐ์กด ์ปดํฌ๋ํธ๋ฅผ ์ ๊ฑฐํ๊ณ ์๋ก์ด ์ปดํฌ๋ํธ๋ฅผ ์์ฑํฉ๋๋ค.์ฆ, key ๊ฐ์ด ๋ฐ๋๋ฉด ํด๋น ์ปดํฌ๋ํธ์ ์ํ๊ฐ ์ด๊ธฐํ๋ฉ๋๋ค.์ด๋ ๊ฐ์ ์ปดํฌ๋ํธ๋ฅผ ์ฌ๋ฌ ๊ฐ ์ฌ์ฉํ๋ฉด์ ๊ฐ๋ณ์ ์ผ๋ก ์ํ๋ฅผ ์ ์งํ๊ณ ์ถ์ ๋ ์ ์ฉํ๊ฒ ํ์ฉํ ์ ์์ต๋๋ค.import { useStat.. Timer Interval ์ง์ฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๋ฐฉ๋ฒ ์ฝ๋ ๋ฆฌ๋ทฐ๋ฅผ ์งํํ๋ ์ค, ๊ธฐ์กด ๊ตฌํ๋ ํ์ด๋จธ์์ ์ธํฐ๋ฒ ์์ ์ด ์ง์ฐ๋๋ ๋ฌธ์ ๊ฐ ์๋ค๋ ํผ๋๋ฐฑ์ ๋ฐ์์ต๋๋ค.๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์๊ฐํด๋ณด์์ต๋๋ค. ์๋ ์ฝ๋๋ ์์๋ฅผ ์ํด ์์ฑ๋ ์ฝ๋์ ๋๋ค.AS-IS. ์๊ฐ์ ์ง์ ๊ณ์ฐ, setInterval๋ก 1์ด๋ง๋ค ๊ฐฑ์ 'use client';import { useEffect, useState } from 'react';import { atomWithStorage } from 'jotai/utils';import { useAtom } from 'jotai';const startTimeAtom = atomWithStorage('inboundProcessStartTime', Date.now());export default function Timer() {.. CDN (Content Delivery Network) CDN์ด๋?CDN(์ฝํ ์ธ ์ ์ก ๋คํธ์ํฌ)์ ์ง๋ฆฌ์ ์ผ๋ก ๋ถ์ฐ๋ ์ฌ๋ฌ ๊ฐ์ ์๋ฒ→ ์น ์ฝํ ์ธ ๋ฅผ ์ฌ์ฉ์์ ๊ฐ๊น์ด ๊ณณ์์ ์ ์กํจ์ผ๋ก์จ ์ ์ก ์๋๋ฅผ ๋์์น ํ์ด์ง, ์ด๋ฏธ์ง, ๋์์ ๋ฑ์ ์ฝํ ์ธ ๋ฅผ ์ฌ์ฉ์์ ์ค์ ์์น์ ๊ฐ๊น์ด ์๋ฒ์ ์บ์ฑ์ฌ์ฉ์์ ๊ฐ์ฅ ๊ฐ๊น์ด ์๋ฒ์์ ์ฝํ ์ธ ๋ฅผ ์ ์ก → ํ์ด์ง ๋ก๋ ์๊ฐ ๋จ์ถ, ๋ ๋น ๋ฅธ ๊ณ ์ฑ๋ฅ ์น ํ๊ฒฝ ๊ฒฝํ CDN์ ๋์ ์๋ฆฌCDN์ ์ธ ๊ฐ์ง ์ข ๋ฅ์ ์๋ฒ์ ์์กด์ค๋ฆฌ์ง ์๋ฒ์ฝํ ์ธ ์ ์๋ณธ ๋ฒ์ ์ด ํฌํจ๋์ด ์์ผ๋ฉฐ ์๋ณธ ์์ค ์ญํ ์ ํจ์ฝํ ์ธ ๋ฅผ ์ ๋ฐ์ดํธํด์ผ ํ ๋๋ง๋ค ์ค๋ฆฌ์ง ์๋ฒ์์ ๋ณ๊ฒฝ์ค๋ฆฌ์ง ์๋ฒ๋ ์ฝํ ์ธ ๊ณต๊ธ์ ์ฒด๊ฐ ์์ ํ๊ณ ๊ด๋ฆฌ or ์จ๋ํํฐ ํด๋ผ์ฐ๋ ๊ณต๊ธ์ ์ฒด์ ์ธํ๋ผ(Amazon์ AWS S3 ๋๋ Google Cloud Storage)์์ ํธ์คํ ์ฃ์ง ์๋ฒ์ ์ธ๊ณ ์ฌ๋ฌ ์ง๋ฆฌ์ ์์น์ ์์น.. ์ด์ 1 2 3 ๋ค์