π λ€μ΄κ°λ©°
μ΅κ·Ό νμ¬μμ λ΄λΉνλ μλΉμ€μ λν΄μ CRAμμ Viteλ‘ λ§μ΄κ·Έλ μ΄μ μ νλ©΄μ μ½κ°μ μ½λ κ°μ κΉμ§ μ§νμ νλ κ²½νμ κ°κ² λμμ΅λλ€.
νλ‘μ νΈ κ·λͺ¨κ° μμ νΈμ΄ μλμκΈ° λλ¬Έμ λ§μ΄κ·Έλ μ΄μ μ νλ©΄μ webpackμ μμ‘΄νκ³ μλ λ±μ μ¬μ΄λμ΄ννΈκ° λ°μνλ λΆλΆμμ μ μΌ κ±±μ μ λ§μ΄ νλλ°μ.
μ΄λ² κΈμμλ ν¬κ² μ λ§μ΄κ·Έλ μ΄μ μ μ§ννλμ§, CRAμ Viteλ μ΄λ€ μ°¨μ΄κ° μλμ§ μ΄λ»κ² μ§ννλμ§, μ΄λ€ κ²°κ³Όκ° μμλμ§ κΈ°λ‘νλ € ν©λλ€.
βοΈ λ§μ΄κ·Έλ μ΄μ μ νμμ±
νμ¬ λ΄λΉν μλΉμ€λ webpack κΈ°λ°μ CRAλ‘ κ΅¬μ±λ νλ‘μ νΈμμ΅λλ€.
첫 λ²μ§Έ, μ€λ 걸리λ κ°λ° μλ² κ΅¬λμκ°μ΄μμ΅λλ€.
ꡬλλλ μκ°κΉμ§ νκ· μ½ 20μ΄κ° μμλκ³ μ΅λ μ½ 30μ΄κΉμ§ μμλλ μν©μ΄μμ΅λλ€.
λ λ²μ§Έ, μ€λ 걸리λ λΉλ μκ°μ΄μμ΅λλ€.
λ°°ν¬λ₯Ό νκΈ° μν΄ λΉλλλ μκ°μ νκ· μ½ 26μ΄κ° μμλμμ΅λλ€.
μΈ λ²μ§Έ, μμ κ°μ μ΄μ λ‘ μΈν΄μ React νμμ λ μ΄μ κΆμ₯νμ§ μλ λΆμκΈ°μ λλ€.
CRA(webpack) vs Vite(rollup, esbuild)
λ¨Όμ webpack, rollup, esbuildμ μν μ λ²λ€λ¬μ λλ€.
λ²λ€λ¬μ μν μ λν΄μ κ°λ¨ν μ€λͺ νλ©΄ μλμ κ°μ΅λλ€.
- μ¬λ¬ κ°μ νμΌλ€μ νλμ νμΌλ‘ λ¬Άμ΄μ£Όλ λꡬ
- λ μμ μ©λ, λ μ΅μ νλ 리μμ€λ₯Ό μ 곡
- μ¬μ©λμ§ μλ μ½λλ₯Ό λΆμν΄μ μ κ±°
κ·Έλμ, CRAλ webpackμ κΈ°λ°μΌλ‘ ꡬμ±μ΄ λμκ³ , Viteλ rollupκ³Ό esbuildλ₯Ό κΈ°λ°μΌλ‘ ꡬμ±μ΄ λμμ΅λλ€.
CRA(webpack)
CRAμ νΉμ§μ κ°λ¨νκ² μλμ κ°μ΅λλ€.
- Facebookμμ λ§λ React μ ν리μΌμ΄μ μ μ²μ μ½κ³ λΉ λ₯΄κ² μ¬μ©ν μ μλλ‘ λ§λ boilerplate
- webpack κΈ°λ°: μμ μ μ΄κ³ κ²μ¦λ λΉλ λꡬ μ¬μ©
- μ λ‘ μ€μ : 볡μ‘ν μ€μ μμ΄ λ°λ‘ κ°λ° μμ κ°λ₯
- ν° μνκ³: λ§μ μ¬μ©μμ νλΆν 리μμ€
μμ κ°μ νΉμ§μ΄ μμ΅λλ€.
μμ¬κ° μλμ μΌλ‘ μ€λλμκΈ° λλ¬Έμ μ°Έκ³ ν λ§ν μλ£κ° νλΆνκ³ , λλΆλΆμ μ€μ μ΄ λμ΄μμ΄ νΈνλ€λ©΄ νΈνμ§λ§ λ°λλ‘ μ»€μ€ν°λ§μ΄μ§μ νκΈ° μν΄μλ ejectκ° νμνλ©° 볡μ‘ν©λλ€.
κ·Έλ¦¬κ³ CRA(webpack)μ λ²λ€ κΈ°λ°μΌλ‘ κ°λ° μλ²κ° ꡬλμ΄ λ©λλ€.
μ§μ μ μμ κ° κ²½λ‘λ€μ νμνκ³ κ²½λ‘λ€μ λν λͺ¨λμ λΆλ¬μ€κ³ λ²λ€λ§μ΄ λ κ²°κ³Όλ¬Όμ ν΅ν΄ κ°λ° μλ²κ° μμμ΄ λ©λλ€.
Vite(rollup, esbuild)
Viteμ νΉμ§μ κ°λ¨νκ² μλμ κ°μ΅λλ€.
- Vue.jsμ μ°½μμμΈ Evan Youκ° λ§λ Frontend build tool
- native ES moules κΈ°λ°μ κ°λ ₯ν κ°λ° μλ²
- esbuildλ‘ μ±λ₯μ κ·Ήμ μΌλ‘ λμ΄μ€κ³ , rollupμ ν΅ν λ²λ€λ§μ μ μ°μ±μ μ±κΉ
Viteλ CRAμ λ€λ₯΄κ² ES moduleμ ν΅ν κ°λ°μλ²λ₯Ό μμνκ³ , μ΄λ‘ μΈν΄μ κ°λ° μλ² μμ μλκ° μλμ μΌλ‘ λ§€μ° λΉ λ¦ λλ€.
μ΄κΈ° μ€μ λν CRAμ λ€λ₯΄κ² μ΅μνμ μ€μ μ΄ λμ΄ μκ³ μ»€μ€ν°λ§μ΄μ§λ μ μ°νμ§λ§ μΆκ° μ€μ μ νκΈ° μν μΆκ°μ μΈ μ½λκ° νμν©λλ€.
κ·Έλ¦¬κ³ νμ¬ λ©μ΄μ 5 λ²μ κΉμ§ λμ¬ μ λλ‘ λ§€μ° νλ°νκ² μ μ§λ³΄μκ° λκ³ μμ΅λλ€.
Viteλ μμ μ€λͺ ν κ²μ²λΌ ESM κΈ°λ°μΌλ‘ κ°λ° μλ²λ₯Ό ꡬλν©λλ€.
λ¨Όμ μλ²κ° μμλ©λλ€.
μλ²κ° μμλλ©΄ HTTP μμ²μ λ³΄λ΄ μ§μ μ μΌλ‘ λ€μ΄κ°κ³ , νμν κ²½λ‘μ λν λͺ¨λλ€λ§ λΆλ¬μμ λΉ λ₯΄κ² κ°λ° μλ²λ₯Ό μμν μ μμ΅λλ€.
λ²λ€ κΈ°λ°μ λͺ¨λ κ²½λ‘μ λν΄μ λ²λ€μ νκ³ λ³΄μ¬μ£Όλ κ²,
ESM κΈ°λ°μ νμν κ²½λ‘λ€μ λν΄μλ§ HTTP μμ²μ νκ² λ©λλ€.
νλ‘ μ 리νλ©΄ μλμ κ°μ΅λλ€.
νΉμ§ | CRA | Vite |
λΉλ λꡬ | webpack | Rollup(νλ‘λμ ) |
κ°λ° μλ² | webpack Dev Server | Native ESM + esbuild |
μ΄κΈ° μ€μ | 미리 ꡬμ±λ¨ | μ΅μνμ μ€μ |
κ°λ° μλ² μμ μλ | λλ¦Ό | λ§€μ° λΉ λ¦ |
컀μ€ν°λ§μ΄μ§ | eject νμ λλ λ³΅μ‘ | κ°λ¨νκ³ μ μ°ν¨ |
SSR | μΆκ° μ€μ νμ | κΈ°λ³Έ μ§μ |
λ κ±°μ λΈλΌμ°μ μ§μ | μ’μ | μ νμ (μΆκ° μ€μ νμ) |
π€ λ§μ΄κ·Έλ μ΄μ κ³Όμ
Vite μ€μΉ
νλ‘μ νΈμ Viteλ₯Ό μ€μΉν©λλ€.
yarn add -D vite @vitejs/plugin-react
package.json μμ
μ΄μ λ viteλ‘ κ΅¬λλ μ μκ²λ λ§κ² μμ ν΄ μ£Όμμ΅λλ€.
vite.config.ts μΆκ°
μλμ κ°μ λ°©μμΌλ‘ νμν μ½λλ€μ μΆκ°νμ΅λλ€.
μ€μ λ‘λ λ λ§μ μ€μ μ΄ μΆκ°λμμ΅λλ€. (svg, md, λΉλ νμΌ ν΄μ, ν΄λ¦¬ν λ±)
import react from '@vitejs/plugin-react';
import fs from 'fs';
import path from 'path';
import { defineConfig } from 'vite';
// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
return {
plugins: [
react(),
],
...
});
tsconfig.json μΆκ°
νμ μ€ν¬λ¦½νΈκ° viteμ λν΄μ μΈμν μ μλλ‘ μΆκ°ν΄ μ£Όμμ΅λλ€.
index.html μμ λ° %PUBLIC_URL% μ κ±°
μΆκ°μ μΈ λ²λ€λ§ κ³Όμ μμ΄ index.html νμΌμ΄ μ±μ μ§μ μ μ΄ λκ²λ νκΈ° μν μμ μ λλ€.
EVN νκ²½ λ³μ μ€μ
vite-env.d.ts νμΌμ νμν νκ²½ λ³μνμ μ μΆκ°νμ΅λλ€.
/// <reference types="vite/client" />
/// <referencetypes="vite-plugin-svgr/client" />
interface ImportMetaEnv {
readonly VITE_SKIP_PREFLIGHT_CHECK: string;
readonly VITE_REACT_APP_VERSION: string;
readonly VITE_ALPHA_PUBLIC_KEY: string;
readonly VITE_PROD_PUBLIC_KEY: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
CommonJS -> ES Module
κΈ°μ‘΄ μ½λμμ CJS λ¬Έλ²μΌλ‘ λμ΄μλ λΆλΆλ€μ μ°Ύμμ ESM λ¬Έλ²μΌλ‘ λ³κ²½ν΄ μ£Όμμ΅λλ€.
π‘ νΈλ¬λΈμν
Viteμ νμν μ€μΉ λ° μ€μ μ ν΄μ€ λ€μ CRA νκ²½μμλ λ°μνμ§ μμμ§λ§ Vite νκ²½μμλ μλ¬κ° λ°μνλ μν©λ€μ΄μμ΅λλ€.
μ£Όμ μν©λ€μ λν΄μ μν©, μμΈ, ν΄κ²° 3κ°μ§ μΉμ μΌλ‘ μ λ¦¬ν΄ λ΄€μ΅λλ€.
λ§ν¬λ€μ΄(.md)νμΌ import μ΄μ λ°μ
μν©
.mdνμΌμ λν΄μ import νλλ° μ²λ¦¬νμ§ λͺ»νμ¬ μλ¬κ° λ°μνλ μν©μ΄μμ΅λλ€.
μμΈ
Viteλ κΈ°λ³Έμ μΌλ‘ μ΅μνμ νμΌλ§ μ²λ¦¬ν©λλ€.
CRAμμλ λ§μ κΈ°λ₯μ κΈ°λ³Έμ μΌλ‘ μ 곡νκ³ μκΈ° λλ¬Έμ μ΄μ μ λ³λ€λ₯Έ μ²λ¦¬κ° νμνμ§ μμμ΅λλ€.
ν΄κ²°
vite.config.ts νμΌμ μλμ μ½λλ₯Ό μΆκ°ν΄ μ£Όμμ΅λλ€.
.md νμ₯μλ₯Ό κ°μ§ λͺ¨λ νμΌμ μ μ μμ°(static asset)μΌλ‘ μ²λ¦¬ νλ €κ³ μ§μνλ λ¬Έλ²μ λλ€.
.md νμΌμ import ν λ Viteκ° μ΄λ₯Ό λ¬Έμμ΄λ‘ λ³ννμ¬ μ 곡ν©λλ€.
https://stackoverflow.com/questions/73459654/import-markdown-files-dynamically-with-vite
pdfjs-dist λΌμ΄λΈλ¬λ¦¬ κ΄λ ¨ μ΄μ λ°μ
μν©
μ ν¬ μλΉμ€μλ μλλ°©μκ² λ¬Έμμ λν νλ©΄ 곡μ νλ κΈ°λ₯μ΄ μμ΅λλ€.
νμ§λ§ Viteλ‘ μ νν λ€ PDF λ¬Έμμ λν΄μ νλ©΄μ 곡μ λ₯Ό μμν μ μμ κ°μ μλ¬κ° λ°μνμ΅λλ€.
μμΈ
CRAλ μΉν©μ κΈ°λ°μΌλ‘ νλ©°, μΉν©μ PDF.jsμ worker νμΌμ μλμΌλ‘ μ²λ¦¬νκ³ λ²λ€λ§ ν©λλ€.
Viteλ ESMμ κΈ°λ°μΌλ‘ νλ©°, νλ‘μΈμ€κ° CRA/webpackκ³Όλ λ€λ¦ λλ€.
ν΄κ²°
GlobalWorkerOptionμ λν΄ λͺ μμ μΌλ‘ μ²λ¦¬νμ΅λλ€.
https://github.com/mozilla/pdf.js/issues/10478
mediapipe νΈν μ΄μ
μν©
κΈ°λ₯ μ€μ μΉ΄λ©λΌ νλ©΄μ λν΄μ μ¬μ©μ μΌκ΅΄ μ€μ λ§μΆκΈ° κΈ°λ₯μ΄ μ‘΄μ¬νμ΅λλ€.
κΈ°λ₯μ μ¬μ©νλ €κ³ νλ©΄ μμ κ°μ μλ¬κ° λ°μνμ΅λλ€.
μ κΈ°νκ²λ κ°λ° νκ²½μμλ λμμ λμμΌλ, λ°°ν¬ νκ²½(preview)μμλ§ μλ¬κ° λ°μνλ μν©μ΄μμ΅λλ€.
μμΈ
μ ν¬ μ¬λ΄ λΌμ΄λΈλ¬λ¦¬ λ΄μμ mediapipe λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νκ³ μμμ΅λλ€.
mediapipe λΌμ΄λΈλ¬λ¦¬μ λͺ¨λμ΄ CJS λμ λ΄λ³΄λ΄κΈ°λ₯Ό μ¬μ©νλλ°, ESMμ μ μ λΆμκ³Ό νΈνμ΄ λμ§ μλ κ²μΌλ‘ νμ νμ΅λλ€.
mediapipe λΌμ΄λΈλ¬λ¦¬μ νΉμ λ΄λ³΄λ΄κΈ° λ°©μμ΄ esbuildμμλ λ¬Έμ μμ΄ μ²λ¦¬λμμ§λ§, rollupμ λ μ격ν μ²λ¦¬ κ³Όμ μμ μλ¬κ° λ°μν κ²μΌλ‘ λΆμνμ΅λλ€.
ν΄κ²°
vite-plugin-mediapipe.ts νμΌμ μμ±νκ³ μλμ κ°μ΄ μ½λλ₯Ό μΆκ°ν΄ 쀬μ΅λλ€.
// vite-plugin-mediapipe.ts
import { PluginOption } from 'vite';
import path from 'path';
import fs from 'fs';
/**
* MediaPipe λΌμ΄λΈλ¬λ¦¬μ ESM νΈνμ± λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν Vite νλ¬κ·ΈμΈ
*/
export const mediapipe = (config?: Record<string, string[]>): PluginOption => ({
name: 'mediapipe',
load(id) {
const MEDIAPIPE_EXPORT_NAMES: Record<string, string[]> = {
'camera_utils.js': ['Camera'],
'drawing_utils.js': ['clamp', 'drawLandmarks', 'drawConnectors', 'drawRectangle', 'lerp'],
'holistic.js': [
'Holistic',
'FACE_GEOMETRY',
'FACEMESH_LIPS',
'FACEMESH_LEFT_EYE',
'FACEMESH_LEFT_EYEBROW',
'FACEMESH_LEFT_IRIS',
'FACEMESH_RIGHT_EYE',
'FACEMESH_RIGHT_EYEBROW',
'FACEMESH_RIGHT_IRIS',
'FACEMESH_FACE_OVAL',
'FACEMESH_CONTOURS',
'FACEMESH_TESSELATION',
'HAND_CONNECTIONS',
'POSE_CONNECTIONS',
'POSE_LANDMARKS',
'POSE_LANDMARKS_LEFT',
'POSE_LANDMARKS_RIGHT',
'POSE_LANDMARKS_NEUTRAL',
'matrixDataToMatrix',
'VERSION',
],
'face_detection.js': ['VERSION', 'FaceDetection'],
...config,
};
const fileName = path.basename(id);
if (!(fileName in MEDIAPIPE_EXPORT_NAMES)) return null;
let code = fs.readFileSync(id, 'utf-8');
for (const name of MEDIAPIPE_EXPORT_NAMES[fileName]) {
code += `exports.${name} = ${name};`;
}
return { code };
},
});
MediaPipe λͺ¨λμ λ΄λ³΄λ΄κΈ°λ₯Ό λͺ μμ μΌλ‘ μ²λ¦¬νλ Vite νλ¬κ·ΈμΈμ μ¬μ©νμ¬ λ¬Έμ λ₯Ό ν΄κ²°νμ΅λλ€.
1. MediaPipe νμΌμ μ½μ΅λλ€.
2. νμν κ°μ²΄μ ν¨μλ₯Ό λͺ
μμ μΌλ‘ λ΄λ³΄λ΄λ μ½λλ₯Ό μΆκ°ν©λλ€.
3. μμ λ μ½λλ₯Ό Viteμ μ λ¬ν©λλ€.
μ΄λ₯Ό ν΅ν΄ νλ‘λμ
λΉλ μμλ MediaPipe λͺ¨λμ΄ μ¬λ°λ₯΄κ² λ‘λλκ³ μ¬μ©λ μ μκ² λμμ΅λλ€.
// vite.config.ts
import { mediapipe } from './config/vite-plugin-mediapipe';
export default defineConfig(({ mode }) => {
return {
plugins: [
react(),
...
mediapipe(),
...
https://github.com/google/mediapipe/issues/4120
β¨ μΆκ° μ½λ κ°μ
λ§μ΄κ·Έλ μ΄μ μΈμ μ΄ μ°Έμ μΆκ°λ‘ κ°μ ν μ μλ λΆλΆμ μ°Ύμμ μ½λλ₯Ό κ°μ νμ΅λλ€.
μλκ²½λ‘ β‘οΈ μ λ κ²½λ‘
κΈ°μ‘΄ λ¬Έμ μ
μμ κ°μ΄ depthκ° λ§μμ§μλ‘ κ°λ μ±μ΄ λ§€μ° λ¨μ΄μ§λ μν©μ΄μμ΅λλ€.
κ°μ
// vite.config.ts
resolve: {
alias: {
'@apis': path.resolve(__dirname, 'src/apis'),
'@assets': path.resolve(__dirname, 'src/assets'),
'@components': path.resolve(__dirname, 'src/components'),
'@constants': path.resolve(__dirname, 'src/constants'),
'@hooks': path.resolve(__dirname, 'src/hooks'),
'@libs': path.resolve(__dirname, 'src/libs'),
'@modules': path.resolve(__dirname, 'src/modules'),
'@pages': path.resolve(__dirname, 'src/pages'),
'@services': path.resolve(__dirname, 'src/services'),
'@styles': path.resolve(__dirname, 'src/styles'),
'@templates': path.resolve(__dirname, 'src/templates'),
'@utils': path.resolve(__dirname, 'src/utils'),
...
},
},
// tsconfig.json
...
"baseUrl": ".",
"paths": {
"react": ["./node_modules/@types/react"],
// "@/*": ["src/*"],
"@apis/*": ["src/apis/*"],
"@assets/*": ["src/assets/*"],
"@components/*": ["src/components/*"],
"@constants/*": ["src/constants/*"],
"@hooks/*": ["src/hooks/*"],
"@libs/*": ["src/libs/*"],
"@modules/*": ["src/modules/*"],
"@pages/*": ["src/pages/*"],
"@services/*": ["src/services/*"],
"@styles/*": ["src/styles/*"],
"@templates/*": ["src/templates/*"],
"@utils/*": ["src/utils/*"]
}
μμ κ°μ΄ μ λκ²½λ‘ κ΄λ ¨ μ½λλ₯Ό μ€μ ν΄ μ£Όμμ΅λλ€.
μ΄μ depthμ μκ΄μμ΄ src ν΄λ κΈ°μ€μΌλ‘ νκΈ° λλ¬Έμ λ§€μ° κΉλν΄μ§ κ²μ νμΈν μ μμμ΅λλ€.
λͺ¨λ μ½λλ€μ λν΄μ λ³κ²½ν΄ μ£Όμμ΅λλ€.
λΆνμν λΌμ΄λΈλ¬λ¦¬ μ κ±°
νμ¬ νλ‘μ νΈμμ μ¬μ©λμ§ μκ³ , λ체 κ°λ₯ν κ²λ€μ λν΄μ 리μ€νΈμ μ νκ³ μ κ±°λ₯Ό μ§ννμ΅λλ€.
μ΄μ κ΄λ ¨ν΄μλ νΉμλ μ μ¬μ μΌλ‘ μ¬μ©λκ³ μκ±°λ, νμν λΌμ΄λΈλ¬λ¦¬λ₯Ό μ κ±°νλ©΄ μ λκΈ° λλ¬Έμ μμ²λΌ 리μ€νΈμ μ νκ³ νμλΆλ€κ» ν λ² λ νμΈμ λ°κ³ μ κ±°λ₯Ό μ§ννμ΅λλ€.
μ΄ 27κ°μ λΆνμν λΌμ΄λΈλ¬λ¦¬λ₯Ό μ κ±°νμ΅λλ€.
β μ±λ₯ λΉκ΅ λ° κ°μ κ²°κ³Ό
μ΄λ ν μμ μ νλμ§ λμ΄ν΄λ³΄μλ©΄ μλμ κ°μ΅λλ€.
- Vite μ ν, config μ€μ
- λΆνμν λΌμ΄λΈλ¬λ¦¬ 27κ° μ κ±° λ° λ체
- CRA μμ‘΄μ± μ κ±°
- λ λλ§ λ¬Έμ μ½λ μμ
- μλ κ²½λ‘ β‘οΈ μ λκ²½λ‘ λ³κ²½
- κ°λ° νκ²½ μ€ν μ ν°λ―Έλμμ proxy μλ² μ ν κ°λ₯ν μ€ν¬λ¦½νΈ μΆκ°
- defaultProps β‘οΈ defaultParameter λ체
- react-query λ΄λΆμ λΆνμν useState μ κ±° λ° λ체
νμ¬ κΈμ μμ±λ κ² μΈμ λ μΆκ°μ μΈ μμ μ΄ μ‘΄μ¬νμ΅λλ€.
κ°μ κ²°κ³Όλ μλμ κ°μ΅λλ€.
μΈ‘μ νλͺ© | CRA(webpack) | Vite(rollup, esbuild) | κ°μ μ¨ |
κ°λ° νκ²½ ꡬλ μκ° | μ½ 20μ΄ | μ½ 200ms | μ½ 99.0% |
λΉλ μμ μκ° | μ½ 26μ΄ | μ½ 16μ΄ | μ½ 38.5% |
λΉλλ ν¬κΈ° | μ½ 317MB | μ½ 222MB | μ½ 30.0% |
μΈ‘μ νκ²½μ m1 pro 16Gμ΄λ©°, νκ· κ°μ λλ€.
π λ§μΉλ©°
CRAμμ Viteλ‘ λ§μ΄κ·Έλ μ΄μ μ μ§νν΄λ λλμ§μ λν΄μ νμλΆλ€μκ² λ¨Όμ μ μμ νλ μν©μ΄μμ΅λλ€.
λ€νν λͺ¨λ μ°¬μ±μ ν΄μ£Όμ ¨κ³ , μ΄μκ° ν°μ‘μ λ 곡μ λ₯Ό νλ©΄ μ κ·Ήμ μΌλ‘ λμμ£Όμ μ μ½κ² ν΄κ²°μ ν μ μμμ΅λλ€.
μ΄μ λ λ μΎμ ν κ°λ° νκ²½μμ κ°λ°μ ν μ μκ² λμμ΅λλ€!
μμΌλ‘ react-query λ²μ μ , FSD μν€ν μ², recoilμμ jotaiλ‘ λ³ννλ λ± κ°μΈμ μΌλ‘ κ°μ νλ©΄ μ’κ² λ€ νλ λΆλΆλ€μ΄ μλΉν λ§μλ° μκ°μ΄ λ λλ§λ€ μ‘°κΈμ© μ§νμ ν μ μλλ‘ νλ €κ³ μμ΅λλ€.
κ°μ¬ν©λλ€.