ν”„λ‘œκ·Έλž˜λ°/React JS

[React] CRAμ—μ„œ Vite둜 λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ κ³Όμ • 및 μ½”λ“œ κ°œμ„ 

μš©λ‡½ 2024. 9. 1. 19:27
λ°˜μ‘ν˜•

[React] CRAμ—μ„œ Vite둜 λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ κ³Όμ • 및 μ½”λ“œ κ°œμ„ 

πŸ“–  λ“€μ–΄κ°€λ©°

졜근 νšŒμ‚¬μ—μ„œ λ‹΄λ‹Ήν•˜λŠ” μ„œλΉ„μŠ€μ— λŒ€ν•΄μ„œ CRAμ—μ„œ Vite둜 λ§ˆμ΄κ·Έλ ˆμ΄μ…˜μ„ ν•˜λ©΄μ„œ μ•½κ°„μ˜ μ½”λ“œ κ°œμ„ κΉŒμ§€ 진행을 ν•˜λŠ” κ²½ν—˜μ„ κ°–κ²Œ λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

 

ν”„λ‘œμ νŠΈ 규λͺ¨κ°€ μž‘μ€ 편이 μ•„λ‹ˆμ—ˆκΈ° λ•Œλ¬Έμ— λ§ˆμ΄κ·Έλ ˆμ΄μ…˜μ„ ν•˜λ©΄μ„œ webpack에 μ˜μ‘΄ν•˜κ³  μžˆλŠ” λ“±μ˜ μ‚¬μ΄λ“œμ΄νŽ™νŠΈκ°€ λ°œμƒν•˜λŠ” λΆ€λΆ„μ—μ„œ 제일 걱정을 많이 ν–ˆλŠ”λ°μš”.

 

이번 κΈ€μ—μ„œλŠ” 크게 μ™œ λ§ˆμ΄κ·Έλ ˆμ΄μ…˜μ„ μ§„ν–‰ν–ˆλŠ”μ§€, CRA와 ViteλŠ” μ–΄λ–€ 차이가 μžˆλŠ”μ§€ μ–΄λ–»κ²Œ μ§„ν–‰ν–ˆλŠ”μ§€, μ–΄λ–€ κ²°κ³Όκ°€ μžˆμ—ˆλŠ”μ§€ κΈ°λ‘ν•˜λ € ν•©λ‹ˆλ‹€.

⁉️ λ§ˆμ΄κ·Έλ ˆμ΄μ…˜μ˜ ν•„μš”μ„±

ν˜„μž¬ λ‹΄λ‹Ήν•œ μ„œλΉ„μŠ€λŠ” webpack 기반의 CRA둜 κ΅¬μ„±λœ ν”„λ‘œμ νŠΈμ˜€μŠ΅λ‹ˆλ‹€.

 

첫 번째, 였래 κ±Έλ¦¬λŠ” 개발 μ„œλ²„ κ΅¬λ™μ‹œκ°„μ΄μ—ˆμŠ΅λ‹ˆλ‹€.

κ΅¬λ™λ˜λŠ” μ‹œκ°„κΉŒμ§€ 평균 μ•½ 20μ΄ˆκ°€ μ†Œμš”λ˜κ³  μ΅œλŒ€ μ•½ 30μ΄ˆκΉŒμ§€ μ†Œμš”λ˜λŠ” μƒν™©μ΄μ—ˆμŠ΅λ‹ˆλ‹€.

 

두 번째, 였래 κ±Έλ¦¬λŠ” λΉŒλ“œ μ‹œκ°„μ΄μ—ˆμŠ΅λ‹ˆλ‹€.

배포λ₯Ό ν•˜κΈ° μœ„ν•΄ λΉŒλ“œλ˜λŠ” μ‹œκ°„μ€ 평균 μ•½ 26μ΄ˆκ°€ μ†Œμš”λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

 

μ„Έ 번째, μœ„μ™€ 같은 이유둜 μΈν•΄μ„œ React νŒ€μ—μ„œ 더 이상 ꢌμž₯ν•˜μ§€ μ•ŠλŠ” λΆ„μœ„κΈ°μž…λ‹ˆλ‹€.

λ¦¬μ•‘νŠΈ κ³΅μ‹λ¬Έμ„œ 쀑 일뢀 발췌
λ¦¬μ•‘νŠΈ 곡식 κΉƒν—ˆλΈŒ PR 발췌

CRA(webpack) vs Vite(rollup, esbuild)

λ¨Όμ € webpack, rollup, esbuild의 역할은 λ²ˆλ“€λŸ¬μž…λ‹ˆλ‹€.

 

λ²ˆλ“€λŸ¬μ˜ 역할에 λŒ€ν•΄μ„œ κ°„λ‹¨νžˆ μ„€λͺ…ν•˜λ©΄ μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

  • μ—¬λŸ¬ 개의 νŒŒμΌλ“€μ„ ν•˜λ‚˜μ˜ 파일둜 λ¬Άμ–΄μ£ΌλŠ” 도ꡬ
  • 더 μž‘μ€ μš©λŸ‰, 더 μ΅œμ ν™”λœ λ¦¬μ†ŒμŠ€λ₯Ό 제곡
  • μ‚¬μš©λ˜μ§€ μ•ŠλŠ” μ½”λ“œλ₯Ό λΆ„μ„ν•΄μ„œ 제거

κ·Έλž˜μ„œ, CRAλŠ” webpack을 기반으둜 ꡬ성이 λ˜μ—ˆκ³ , ViteλŠ” rollupκ³Ό esbuildλ₯Ό 기반으둜 ꡬ성이 λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

CRA vs Vite

CRA(webpack)

create-react-app

CRA의 νŠΉμ§•μ€ κ°„λ‹¨ν•˜κ²Œ μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

  • Facebookμ—μ„œ λ§Œλ“  React μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ 처음 쉽고 λΉ λ₯΄κ²Œ μ‚¬μš©ν•  수 μžˆλ„λ‘ λ§Œλ“  boilerplate
  • webpack 기반: μ•ˆμ •μ μ΄κ³  κ²€μ¦λœ λΉŒλ“œ 도ꡬ μ‚¬μš©
  • 제둜 μ„€μ •: λ³΅μž‘ν•œ μ„€μ • 없이 λ°”λ‘œ 개발 μ‹œμž‘ κ°€λŠ₯
  • 큰 μƒνƒœκ³„: λ§Žμ€ μ‚¬μš©μžμ™€ ν’λΆ€ν•œ λ¦¬μ†ŒμŠ€

μœ„μ™€ 같은 νŠΉμ§•μ΄ μžˆμŠ΅λ‹ˆλ‹€.

 

역사가 μƒλŒ€μ μœΌλ‘œ μ˜€λž˜λ˜μ—ˆκΈ° λ•Œλ¬Έμ— μ°Έκ³ ν•  λ§Œν•œ μžλ£Œκ°€ ν’λΆ€ν•˜κ³ , λŒ€λΆ€λΆ„μ˜ 섀정이 λ˜μ–΄μžˆμ–΄ νŽΈν•˜λ‹€λ©΄ νŽΈν•˜μ§€λ§Œ λ°˜λŒ€λ‘œ μ»€μŠ€ν„°λ§ˆμ΄μ§•μ„ ν•˜κΈ° μœ„ν•΄μ„œλŠ” ejectκ°€ ν•„μš”ν•˜λ©° λ³΅μž‘ν•©λ‹ˆλ‹€.

 

그리고 CRA(webpack)은 λ²ˆλ“€ 기반으둜 개발 μ„œλ²„κ°€ ꡬ동이 λ©λ‹ˆλ‹€.

λ²ˆλ“€ 기반 개발 μ„œλ²„

μ§„μž…μ μ—μ„œ 각 κ²½λ‘œλ“€μ„ νƒμƒ‰ν•˜κ³  κ²½λ‘œλ“€μ— λŒ€ν•œ λͺ¨λ“ˆμ„ 뢈러였고 λ²ˆλ“€λ§μ΄ 된 결과물을 톡해 개발 μ„œλ²„κ°€ μ‹œμž‘μ΄ λ©λ‹ˆλ‹€.

Vite(rollup, esbuild)

vite

Vite의 νŠΉμ§•μ€  κ°„λ‹¨ν•˜κ²Œ μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

  • Vue.js의 μ°½μ‹œμžμΈ Evan Youκ°€ λ§Œλ“  Frontend build tool
  • native ES moules 기반의 κ°•λ ₯ν•œ 개발 μ„œλ²„
  • esbuild둜 μ„±λŠ₯을 극적으둜 λŒμ–΄μ˜€κ³ , rollup을 ν†΅ν•œ λ²ˆλ“€λ§μ˜ μœ μ—°μ„±μ„ μ±™κΉ€

ViteλŠ” CRA와 λ‹€λ₯΄κ²Œ ES module을 ν†΅ν•œ κ°œλ°œμ„œλ²„λ₯Ό μ‹œμž‘ν•˜κ³ , 이둜 μΈν•΄μ„œ 개발 μ„œλ²„ μ‹œμž‘ 속도가 μƒλŒ€μ μœΌλ‘œ 맀우 λΉ λ¦…λ‹ˆλ‹€.

초기 μ„€μ • λ˜ν•œ CRA와 λ‹€λ₯΄κ²Œ μ΅œμ†Œν•œμ˜ 섀정이 λ˜μ–΄ 있고 μ»€μŠ€ν„°λ§ˆμ΄μ§•λ„ μœ μ—°ν•˜μ§€λ§Œ μΆ”κ°€ 섀정을 ν•˜κΈ° μœ„ν•œ 좔가적인 μ½”λ“œκ°€ ν•„μš”ν•©λ‹ˆλ‹€.

그리고 ν˜„μž¬ 메이저 5 λ²„μ „κΉŒμ§€ λ‚˜μ˜¬ μ •λ„λ‘œ 맀우 ν™œλ°œν•˜κ²Œ μœ μ§€λ³΄μˆ˜κ°€ 되고 μžˆμŠ΅λ‹ˆλ‹€.

 

ViteλŠ” μ•žμ„œ μ„€λͺ…ν•œ κ²ƒμ²˜λŸΌ ESM 기반으둜 개발 μ„œλ²„λ₯Ό κ΅¬λ™ν•©λ‹ˆλ‹€. 

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 λ¬Έλ²•μœΌλ‘œ λ³€κ²½ν•΄ μ£Όμ—ˆμŠ΅λ‹ˆλ‹€.

CJS
ESM
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

 

Import markdown files dynamically with Vite

I'm looking for a solution that lets me render markdown dynamically, based on the query string. At the moment I render markdown like this, in React + Vite: import some other stuff... import { usePa...

stackoverflow.com

pdfjs-dist 라이브러리 κ΄€λ ¨ 이슈 λ°œμƒ

상황

저희 μ„œλΉ„μŠ€μ—λŠ” μƒλŒ€λ°©μ—κ²Œ λ¬Έμ„œμ— λŒ€ν•œ ν™”λ©΄ κ³΅μœ ν•˜λŠ” κΈ°λŠ₯이 μžˆμŠ΅λ‹ˆλ‹€.

ν•˜μ§€λ§Œ Vite둜 μ „ν™˜ν•œ λ’€ PDF λ¬Έμ„œμ— λŒ€ν•΄μ„œ 화면을 곡유λ₯Ό μ‹œμž‘ν•  μ‹œ μœ„μ™€ 같은 μ—λŸ¬κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. 

원인

CRAλŠ” μ›ΉνŒ©μ„ 기반으둜 ν•˜λ©°, μ›ΉνŒ©μ€ PDF.js의 worker νŒŒμΌμ„ μžλ™μœΌλ‘œ μ²˜λ¦¬ν•˜κ³  λ²ˆλ“€λ§ ν•©λ‹ˆλ‹€.

ViteλŠ” ESM을 기반으둜 ν•˜λ©°, ν”„λ‘œμ„ΈμŠ€κ°€ CRA/webpackκ³ΌλŠ” λ‹€λ¦…λ‹ˆλ‹€.

ν•΄κ²°

GlobalWorkerOption에 λŒ€ν•΄ λͺ…μ‹œμ μœΌλ‘œ μ²˜λ¦¬ν–ˆμŠ΅λ‹ˆλ‹€.

https://github.com/mozilla/pdf.js/issues/10478

 

No "GlobalWorkerOptions.workerSrc" specified. · Issue #10478 · mozilla/pdf.js

if (!fallbackWorkerSrc && typeof document !== 'undefined') { var pdfjsFilePath = document.currentScript && document.currentScript.src; if (pdfjsFilePath) { fallbackWorkerSrc = pdfjsFilePath.replace...

github.com

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

 

Vite build is prepending undefined variables to @mediapipe deps in production /dist/index.js file · Issue #4120 · google-ai-ed

OS Platform and Distribution node:16.18-alpine official docker image Compiler version No response Programming Language and version JavaScript Installed using virtualenv? pip? Conda?(if python) No r...

github.com

✨ μΆ”κ°€ μ½”λ“œ κ°œμ„ 

λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ 외에 이 참에 μΆ”κ°€λ‘œ κ°œμ„ ν•  수 μžˆλŠ” 뢀뢄을 μ°Ύμ•„μ„œ μ½”λ“œλ₯Ό κ°œμ„ ν–ˆμŠ΅λ‹ˆλ‹€.

μƒλŒ€κ²½λ‘œ ➑️ μ ˆλŒ€ 경둜

기쑴 문제점

μœ„μ™€ 같이 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둜 λ³€ν™˜ν•˜λŠ” λ“± 개인적으둜 κ°œμ„ ν•˜λ©΄ μ’‹κ² λ‹€ ν•˜λŠ” 뢀뢄듀이 μƒλ‹Ήνžˆ λ§Žμ€λ° μ‹œκ°„μ΄ λ‚  λ•Œλ§ˆλ‹€ μ‘°κΈˆμ”© 진행을 ν•  수 μžˆλ„λ‘ ν•˜λ €κ³  μžˆμŠ΅λ‹ˆλ‹€.

 

κ°μ‚¬ν•©λ‹ˆλ‹€.

λ°˜μ‘ν˜•