CRA 없이 react app λ§Œλ“€κΈ°

μš°λ¦¬νŒ€(NDD)은 Nextκ°€ μ•„λ‹Œ SPA μ„œλΉ„μŠ€λ₯Ό λ§Œλ“€κ²ƒμ΄λ©°, 특히 CRA없이 react μ„œλΉ„μŠ€λ₯Ό ꡬ성해보렀고 ν•©λ‹ˆλ‹€.

Profile Picture
adultlee
2023-11-13

원본

0. μ„œλ¬Έ

μ§€λ‚œ μ‹œκ°„μ— μš°λ¦¬κ°€ μ‚¬μš©ν•  κΈ°μˆ λ“€μ— λŒ€ν•΄μ„œ 짧게 λ‚˜λ§ˆ λ…Όμ˜ν•œ ν›„ 결둠을 내릴 수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€. μš°λ¦¬νŒ€(NDD)은 Nextκ°€ μ•„λ‹Œ SPA μ„œλΉ„μŠ€λ₯Ό λ§Œλ“€κ²ƒμ΄λ©°, 특히 CRA없이 react μ„œλΉ„μŠ€λ₯Ό ꡬ성해보렀고 ν•©λ‹ˆλ‹€. λ³Έ κ²Œμ‹œκΈ€μ€ babel κ³Ό webpack에 μ§‘μ€‘ν•˜μ—¬ μž‘μ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

1. μ™œ cra없이 μ§„ν–‰ν•˜κ²Œ λ˜μ—ˆλŠ”κ°€?

ν”„λ ˆμž„μ›Œν¬λŠ” λ‹€μ–‘ν•˜κ³  νŽΈλ¦¬ν•œ κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€. λ‹Ήμ—°νžˆ μ—¬λŸ¬ 유λŠ₯ν•œ κ°œλ°œμžλ“€μ˜ 개발둜 μ΄λ£¨μ–΄μ‘ŒκΈ° λ•Œλ¬Έμ΄μ§€λ§Œ, μ—¬λŸ¬κ°€μ§€λ‘œ μœ„ν—˜ν•˜λ‹€λŠ” 생각이 λ“€μ—ˆμŠ΅λ‹ˆλ‹€.

  1. ν”„λ ˆμž„μ›Œν¬λ₯Ό μ‚¬μš©ν•˜λ©΄ νŽΈλ¦¬ν•œ κΈ°λŠ₯듀이 μ–΄λ–»κ²Œ μ œκ³΅λ˜λŠ”μ§€ λͺ¨λ¦…λ‹ˆλ‹€.
  2. ν”„λ ˆμž„μ›Œν¬λ₯Ό μ‚¬μš©ν•˜κΈ° μ „ "λΆˆνŽΈν•¨"을 μ•Œκ³  μžˆμ–΄μ•Ό ν•œλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€.

μœ„μ™€ 같은 생각듀을 톡해 μ €λŠ” 점점 ν”„λ ˆμž„μ›Œν¬λ₯Ό μ‚¬μš©ν•˜μ§€ 말아야 κ² λ‹€λŠ” 생각이 λ“€μ—ˆμŠ΅λ‹ˆλ‹€. 적어도 λΆˆνŽΈν•¨ 을 λͺ¨λ₯΄λŠ” μƒνƒœμ—μ„œ ν”„λ ˆμž„μ›Œν¬λ‘œ λ‹¨κΈ°κ°„μ˜ νŽΈλ¦¬ν•¨μ„ μ°ΎκΈ°λŠ” λͺ¨μˆœλœλ‹€λŠ” 생각이 λ“€μ—ˆμŠ΅λ‹ˆλ‹€.

무엇보닀 우린 ν”„λ‘œμ νŠΈλ₯Ό μ§„ν–‰ν•˜λ©΄μ„œ "μ„±μž₯" 에 μ΄ˆμ μ„ λ‘μ—ˆμŠ΅λ‹ˆλ‹€. 단기간 ν”„λ‘œμ νŠΈλ₯Ό μ™„μ„±ν•˜λŠ”κ²ƒμ΄ λͺ©ν‘œκ°€ μ•„λ‹Œ, μ‹œκ°„μ΄ 였래 걸리더라도 의미 μžˆλŠ” ν•™μŠ΅μ„ ν•¨κ»˜ μ§„ν–‰ν•˜κ³  μ‹Άμ—ˆμŠ΅λ‹ˆλ‹€.

λΆ€μΊ μ—μ„œλ„ μ§€μ–‘ν•œ webpack κΈ°λ°˜β€¦!

λΆ€μŠ€νŠΈμΊ ν”„μ—μ„œ μ œκ³΅ν•œ κ·Έλ£Ήν”„λ‘œμ νŠΈ κ°€μ΄λ“œλΌμΈ

ν•˜μ§€λ§Œ λΆ€μŠ€νŠΈμΊ ν”„ μΈ‘μ—μ„œλ„ Webpack에 λŒ€ν•œ μ…‹νŒ…μ€ μΆ”μ²œν•˜μ§€ μ•Šμ•˜λŠ”λ°μš”. κ·Έλž˜λ„ κΌ­ 진행해보고 μ‹Άμ—ˆμŠ΅λ‹ˆλ‹€. 늘 ν”„λ ˆμž„μ›Œν¬λ₯Ό μ‚¬μš©ν•˜λ©°, 뢀쑱함을 느끼던 뢀뢄을 이번 κΈ°νšŒμ— μ±„μš°κ³  μ‹Άμ—ˆμŠ΅λ‹ˆλ‹€.

2. 초기 ν”„λ‘œμ νŠΈ μ…‹νŒ…μ— ν•„μš”ν•œκ²ƒ

λ”°λΌμ„œ 초기 ν”„λ‘œμ νŠΈ μ…‹νŒ…μ— ν•„μš”ν•œ 것을 λ¦¬μŠ€νŠΈμ—…ν•˜κ²Œ λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

  1. React 기반 ν”„λ‘œμ νŠΈ μ…‹νŒ…μ΄ κ°€λŠ₯ν•΄μ•Όν•œλ‹€.
  2. TS 문법을 μ‚¬μš©κ°€λŠ₯ν•΄μ•Όν•œλ‹€.
  3. Emotion의 css-props 문법이 μ‚¬μš©κ°€λŠ₯ν•΄μ•Ό ν•œλ‹€.
  4. eslint λ‚˜ prettier λ“± μ½”λ“œ ν¬λ©§νŒ…μ΄ κ°€λŠ₯ν•΄μ•Όν•œλ‹€.

3. CRAλŠ” 어떻지?

npx create-react-app [ν”„λ‘œμ νŠΈ λͺ…]

λ‹€μŒκ³Ό 같은 λͺ…λ Ήμ–΄λ‘œ μ•„λž˜μ™€ 같은 결과물이 μƒμ„±λ©λ‹ˆλ‹€.

https://create-react-app.dev/docs/getting-started

my-app
β”œβ”€β”€ README.md
β”œβ”€β”€ node_modules
β”œβ”€β”€ package.json
β”œβ”€β”€ .gitignore
β”œβ”€β”€ public
β”‚   β”œβ”€β”€ favicon.ico
β”‚   β”œβ”€β”€ index.html
β”‚   β”œβ”€β”€ logo192.png
β”‚   β”œβ”€β”€ logo512.png
β”‚   β”œβ”€β”€ manifest.json
β”‚   └── robots.txt
└── src
    β”œβ”€β”€ App.css
    β”œβ”€β”€ App.js
    β”œβ”€β”€ App.test.js
    β”œβ”€β”€ index.css
    β”œβ”€β”€ index.js
    β”œβ”€β”€ logo.svg
    β”œβ”€β”€ serviceWorker.js
    └── setupTests.js

이 μ½”λ“œ 어디에도 μ•žμœΌλ‘œ μ„€λͺ…ν•  webpack, babel λ“±λ“± λ²ˆλ“€λ§κ³Ό μ»΄νŒŒμΌμ„ 진행할 μ…‹νŒ…μ΄ 보이질 μ•ŠμŠ΅λ‹ˆλ‹€.

κ·Έ μ΄μœ λŠ” Create React App (CRA)을 μ‚¬μš©ν•˜μ—¬ React ν”„λ‘œμ νŠΈλ₯Ό μƒμ„±ν•˜λ©΄, Webpack, Babel, ESLint λ“±μ˜ 섀정이 λ‚΄λΆ€μ μœΌλ‘œ 숨겨져 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€. 이런 방식을 "Zero-Configuration" λ˜λŠ” "No-Config" 방식이라고 ν•©λ‹ˆλ‹€. CRAλŠ” μ΄λŸ¬ν•œ 도ꡬ듀을 미리 κ΅¬μ„±ν•˜μ—¬ μ œκ³΅ν•˜κΈ° λ•Œλ¬Έμ—, μ‚¬μš©μžλŠ” λ³΅μž‘ν•œ μ„€μ • κ³Όμ • 없이도 λ°”λ‘œ React μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ κ°œλ°œν•˜κΈ° μ‹œμž‘ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ¬Όλ‘  접근을 μ™„μ „ λͺ»ν•˜λŠ”것은 μ•„λ‹™λ‹ˆλ‹€. npm run eject 와 같은 λͺ…λ Ήμ–΄λ₯Ό μ‚¬μš©ν•˜λ©΄, μˆ¨κ²¨μ§„ webpack, babel등에 μ ‘κ·Όν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ–΄λ–»κ²Œ reactλ₯Ό μ‚¬μš©ν•  수 μžˆμ„κΉŒ?

μœ„μ—μ„œ κ°„λ‹¨ν•˜κ²Œ μ„€λͺ…을 λ“œλ Έμ—ˆμŠ΅λ‹ˆλ‹€λ§Œ, reactλŠ” μ—¬λŸ¬κ°€μ§€ 도ꡬλ₯Ό ν†΅ν•΄μ„œ λΈŒλΌμš°μ €κ°€ 읽을 수 μžˆλ„λ‘ "λ³€ν™˜" ν•΄μ£ΌλŠ” 과정이 ν•„μš”ν•©λ‹ˆλ‹€. λ‹¨νŽΈμ μœΌλ‘œ React의 JSXλΌλŠ” XMLκ³Ό μœ μ‚¬ν•œ 문법을 μ‚¬μš©ν•©λ‹ˆλ‹€. λΈŒλΌμš°μ €λŠ” JSXλ₯Ό μ΄ν•΄ν•˜μ§€ λͺ»ν•˜κΈ° λ•Œλ¬Έμ—, Babel은 JSXλ₯Ό λΈŒλΌμš°μ €κ°€ 이해할 수 μžˆλŠ” 일반 JavaScript ν•¨μˆ˜ 호좜둜 λ³€ν™˜ν•©λ‹ˆλ‹€.

λ¬Όλ‘  μ΄λŠ” React μ—λ§Œ ν•œμ •λ˜λŠ” μ΄μ•ΌκΈ°λŠ” μ•„λ‹™λ‹ˆλ‹€. es6의 λͺ¨λ“ˆ μ‹œμŠ€ν…œκ³Ό 같은 μ΅œμ‹  λ¬Έλ²•λ“€μ—λŒ€ν•΄μ„œλ„ λΈŒλΌμš°μ €κ°€ 이해할 수 μžˆλŠ” μ½”λ“œλ‘œ λ³€ν™˜ν•˜λŠ” 과정이 ν•„μš”ν•©λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같이 μš”μ•½ν•  수 μžˆμ„κ²ƒ κ°™μŠ΅λ‹ˆλ‹€.

Node.js와 문법 문제

Node.jsλŠ” 기본적으둜 μ΅œμ‹  JavaScript λ¬Έλ²•μ˜ 일뢀λ₯Ό μ§€μ›ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, Reactμ—μ„œ 많이 μ‚¬μš©λ˜λŠ” JSX λ¬Έλ²•μ΄λ‚˜ ES6의 import/export 문법 등이 κ·Έλ ‡μŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ 문법을 Node.jsκ°€ 이해할 수 μžˆλ„λ‘ λ³€ν™˜ν•΄μ•Ό ν•˜λŠ”λ°, μ—¬κΈ°μ„œ Babel이 ν•„μš”ν•©λ‹ˆλ‹€.

Babel

Babel은 μ΅œμ‹  JavaScript 문법을 Node.jsκ°€ 이해할 수 μžˆλŠ” 이전 λ²„μ „μ˜ JavaScript둜 λ³€ν™˜ν•΄μ£ΌλŠ” λ„κ΅¬μž…λ‹ˆλ‹€. 이λ₯Ό 톡해 μš°λ¦¬λŠ” React μ•±μ—μ„œ μ΅œμ‹  문법을 자유둭게 μ‚¬μš©ν•  수 있게 λ©λ‹ˆλ‹€.

Webpackκ³Ό 파일 λΉŒλ“œ/μ„œλΉ„μŠ€

React 앱은 μ—¬λŸ¬ JavaScript 파일둜 κ΅¬μ„±λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. 이 νŒŒμΌλ“€μ„ μ›Ή λΈŒλΌμš°μ €κ°€ 이해할 수 μžˆλ„λ‘ ν•˜λ‚˜μ˜ 파일둜 ν•©μΉ˜λŠ” 과정이 ν•„μš”ν•©λ‹ˆλ‹€. 이 과정을 'λΉŒλ“œ(build)'라고 ν•©λ‹ˆλ‹€. Webpack은 μ΄λŸ¬ν•œ λΉŒλ“œ 과정을 κ΄€λ¦¬ν•˜λŠ” λ„κ΅¬λ‘œ, 개발 쀑에 μ‹€μ‹œκ°„μœΌλ‘œ νŒŒμΌμ„ ν•©μΉ˜κ³  ν•„μš”ν•œ λ³€ν™˜μ„ μˆ˜ν–‰ν•©λ‹ˆλ‹€. λ˜ν•œ, 개발 μ„œλ²„λ₯Ό μ œκ³΅ν•˜μ—¬ μ‹€μ‹œκ°„μœΌλ‘œ 앱을 ν…ŒμŠ€νŠΈν•˜κ³  확인할 수 있게 ν•΄μ€λ‹ˆλ‹€.

4. babel μ…‹νŒ…μ„ ν•΄λ³΄μž

Babel은 μžλ°”μŠ€ν¬λ¦½νŠΈ 컴파일러둜, 주둜 μ΅œμ‹  λ²„μ „μ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ(ES6 이상) μ½”λ“œλ₯Ό 였래된 μžλ°”μŠ€ν¬λ¦½νŠΈ λ²„μ „μœΌλ‘œ λ³€ν™˜ν•˜λŠ” 데 μ‚¬μš©λ©λ‹ˆλ‹€. 이런 λ³€ν™˜ 과정을 톡해, μ΅œμ‹  μžλ°”μŠ€ν¬λ¦½νŠΈ 문법을 μ‚¬μš©ν•˜μ—¬ μž‘μ„±λœ μ½”λ“œλ₯Ό 였래된 λΈŒλΌμš°μ €λ‚˜ ν™˜κ²½μ—μ„œλ„ μ‹€ν–‰ν•  수 있게 ν•©λ‹ˆλ‹€. Babel의 μ£Όμš” νŠΉμ§•κ³Ό κΈ°λŠ₯은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€:

μ½”λ“œ λ³€ν™˜(Transpilation): Babel은 μ΅œμ‹  μžλ°”μŠ€ν¬λ¦½νŠΈ 문법(예: ν™”μ‚΄ν‘œ ν•¨μˆ˜, 클래슀, ν…œν”Œλ¦Ώ λ¬Έμžμ—΄ λ“±)을 ꡬ λ²„μ „μ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œλ‘œ λ³€ν™˜ν•©λ‹ˆλ‹€. μ΄λŠ” κ΅¬ν˜• λΈŒλΌμš°μ €λ‚˜ ν™˜κ²½μ—μ„œλ„ μ΅œμ‹  μžλ°”μŠ€ν¬λ¦½νŠΈ κΈ°λŠ₯을 μ‚¬μš©ν•  수 있게 ν•΄μ€λ‹ˆλ‹€.

λΈŒλΌμš°μ € ν˜Έν™˜μ„±: λ‹€μ–‘ν•œ λΈŒλΌμš°μ €μ—μ„œ μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œκ°€ μΌκ΄€λ˜κ²Œ μž‘λ™ν•˜λ„λ‘ λ„μ™€μ€λ‹ˆλ‹€. 이λ₯Ό μœ„ν•΄ Babel은 νŠΉμ • λΈŒλΌμš°μ €μ—μ„œ ν•„μš”ν•œ νŠΉμ • λ³€ν™˜λ§Œμ„ μ μš©ν•  수 μžˆλŠ” '프리셋(presets)'κ³Ό 'ν”ŒλŸ¬κ·ΈμΈ(plugins)'을 μ œκ³΅ν•©λ‹ˆλ‹€.

JSX 및 React 지원: Babel은 React κ°œλ°œμ— ν•„μˆ˜μ μž…λ‹ˆλ‹€. Reactμ—μ„œ μ‚¬μš©λ˜λŠ” JSX 문법은 기본적으둜 μžλ°”μŠ€ν¬λ¦½νŠΈμ— λ‚΄μž₯λ˜μ–΄ μžˆμ§€ μ•ŠμœΌλ―€λ‘œ, Babel을 μ‚¬μš©ν•˜μ—¬ JSXλ₯Ό 일반 μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œλ‘œ λ³€ν™˜ν•΄μ•Ό ν•©λ‹ˆλ‹€.

ν”ŒλŸ¬κ·ΈμΈ 및 ν™•μž₯μ„±: Babel은 λ‹€μ–‘ν•œ ν”ŒλŸ¬κ·ΈμΈμ„ 톡해 ν™•μž₯ κ°€λŠ₯ν•©λ‹ˆλ‹€. κ°œλ°œμžλŠ” ν•„μš”μ— 따라 좔가적인 κΈ°λŠ₯을 Babel에 ν”ŒλŸ¬κ·ΈμΈμœΌλ‘œ μΆ”κ°€ν•˜μ—¬ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

ES6 μ΄μƒμ˜ κΈ°λŠ₯ 지원: Babel은 ES6, ES7 λ“±μ˜ μƒˆλ‘œμš΄ μžλ°”μŠ€ν¬λ¦½νŠΈ λ²„μ „μ—μ„œ λ„μž…λœ κΈ°λŠ₯듀을 였래된 μžλ°”μŠ€ν¬λ¦½νŠΈ λ²„μ „μœΌλ‘œ λ³€ν™˜ν•˜μ—¬, 이전 λ²„μ „μ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ μ—”μ§„μ—μ„œλ„ ν•΄λ‹Ή κΈ°λŠ₯듀을 μ‚¬μš©ν•  수 μžˆλ„λ‘ μ§€μ›ν•©λ‹ˆλ‹€.

// .babelrc
{
  "presets": [
    "@babel/preset-env",
    [
      "@babel/preset-react",
      { "runtime": "automatic", "importSource": "@emotion/react" }
    ],
    "@babel/preset-typescript"
  ],
  "plugins": ["@emotion/babel-plugin"],
  "targets": "> 0.5%, not dead"
}

ν•œμ€„μ”© μ„€λͺ…을 μΆ”κ°€ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€. Presets은 νŠΉμ •ν•œ λͺ©μ μ΄λ‚˜ ν™˜κ²½μ— λ§žμΆ°μ§„ 일련의 Babel ν”ŒλŸ¬κ·ΈμΈλ“€μ˜ λ¬ΆμŒμž…λ‹ˆλ‹€. 각 프리셋은 자주 μ‚¬μš©λ˜λŠ” νŠΉμ • μ„€μ •μ΄λ‚˜ ν™˜κ²½μ— μ΅œμ ν™”λœ Babel ν”ŒλŸ¬κ·ΈμΈμ˜ 쑰합을 ν¬ν•¨ν•©λ‹ˆλ‹€. μ—¬κΈ°μ„œ μ‚¬μš©λ˜λŠ” presetsλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

@babel/preset-env

@babel/preset-envλŠ” κ°œλ°œμžκ°€ μ§€μ •ν•œ λŒ€μƒ ν™˜κ²½(λΈŒλΌμš°μ €, Node.js λ“±)에 따라 ν•„μš”ν•œ JavaScript λ³€ν™˜μ„ μžλ™μœΌλ‘œ μ μš©ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, 였래된 λΈŒλΌμš°μ €μ—μ„œ μ‹€ν–‰λ˜λŠ” μ½”λ“œλ₯Ό κ°œλ°œν•œλ‹€λ©΄, 이 프리셋은 ES6 μ΄μƒμ˜ JavaScript 문법을 였래된 JavaScript λ¬Έλ²•μœΌλ‘œ λ³€ν™˜ν•˜μ—¬ ν˜Έν™˜μ„±μ„ 보μž₯ν•©λ‹ˆλ‹€.

"폴리필(polyfill)"을 μ μš©ν•œλ‹€λŠ” 것은 νŠΉμ • κΈ°λŠ₯μ΄λ‚˜ APIκ°€ μ§€μ›λ˜μ§€ μ•ŠλŠ” λΈŒλΌμš°μ €λ‚˜ ν™˜κ²½μ—μ„œλ„ κ·Έ κΈ°λŠ₯을 μ‚¬μš©ν•  수 μžˆλ„λ‘ ν•˜λŠ” μ½”λ“œ λ˜λŠ” 도ꡬλ₯Ό μ œκ³΅ν•œλ‹€λŠ” μ˜λ―Έμž…λ‹ˆλ‹€. Babelκ³Ό 같은 도ꡬλ₯Ό μ‚¬μš©ν•  λ•Œ, 폴리필은 μžλ™μœΌλ‘œ 적용될 수 μžˆμŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, @babel/preset-envλŠ” ν•„μš”ν•œ 폴리필을 ν”„λ‘œμ νŠΈμ˜ λŒ€μƒ ν™˜κ²½μ— 맞좰 μžλ™μœΌλ‘œ ν¬ν•¨μ‹œν‚΅λ‹ˆλ‹€. μ΄λŠ” κ°œλ°œμžκ°€ λ³„λ„λ‘œ 각 λΈŒλΌμš°μ €μ˜ ν˜Έν™˜μ„±μ„ μ²΄ν¬ν•˜κ³  ν•„μš”ν•œ 폴리필을 μˆ˜λ™μœΌλ‘œ μΆ”κ°€ν•˜λŠ” 수고λ₯Ό λœμ–΄μ€λ‹ˆλ‹€.

["@babel/preset-react",{ "runtime": "automatic", "importSource": "@emotion/react" }]

  1. @babel/preset-react 이 프리셋은 JSX와 같은 React의 문법을 일반 JavaScript둜 λ³€ν™˜ν•©λ‹ˆλ‹€. React μ»΄ν¬λ„ŒνŠΈμ—μ„œ μ‚¬μš©λ˜λŠ” JSX 문법은 λΈŒλΌμš°μ €κ°€ 직접 이해할 수 μ—†κΈ° λ•Œλ¬Έμ—, Babel을 톡해 ν˜Έν™˜ κ°€λŠ₯ν•œ JavaScript μ½”λ“œλ‘œ λ³€ν™˜μ‹œμΌœμ€λ‹ˆλ‹€.
  2. runtime: "automatic" runtime μ˜΅μ…˜μ€ JSXλ₯Ό μ–΄λ–»κ²Œ λ³€ν™˜ν• μ§€λ₯Ό κ²°μ •ν•©λ‹ˆλ‹€. "automatic"으둜 μ„€μ •ν•˜λ©΄, Babel은 JSXλ₯Ό λ³€ν™˜ν•  λ•Œ React의 import 문을 μžλ™μœΌλ‘œ μΆ”κ°€ν•©λ‹ˆλ‹€. μ΄λŠ” React 17 이후뢀터 λ„μž…λœ μƒˆλ‘œμš΄ JSX λ³€ν™˜ λ°©μ‹μž…λ‹ˆλ‹€. 이 방식을 μ‚¬μš©ν•˜λ©΄, κ°œλ°œμžλŠ” 각 νŒŒμΌμ—μ„œ import React from 'react'λ₯Ό λͺ…μ‹œμ μœΌλ‘œ 쓰지 μ•Šμ•„λ„λ©λ‹ˆλ‹€. Babel이 ν•„μš”ν•œ React ν•¨μˆ˜λ₯Ό μžλ™μœΌλ‘œ κ°€μ Έμ˜€κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.
  3. importSource: "@emotion/react" (μ•„μ£Όμ•„μ£Όμ•„μ£Ό μ€‘μš”!!!!!) importSource μ˜΅μ…˜μ€ JSX λ³€ν™˜ μ‹œ μ‚¬μš©ν•  라이브러리의 좜처λ₯Ό μ§€μ •ν•©λ‹ˆλ‹€. μ—¬κΈ°μ„œ "@emotion/react"둜 μ„€μ •λ˜μ–΄ 있으며, μ΄λŠ” Emotion 라이브러리λ₯Ό μ‚¬μš©ν•œλ‹€λŠ” 것을 μ˜λ―Έν•©λ‹ˆλ‹€. Emotion은 CSS-in-JS 라이브러리 쀑 ν•˜λ‚˜λ‘œ, 이 섀정을 톡해 Emotion의 JSX ν”„λΌκ·Έλ¨ΌνŠΈλ₯Ό μ‚¬μš©ν•˜μ—¬ μŠ€νƒ€μΌλ§λœ μ»΄ν¬λ„ŒνŠΈλ₯Ό μ‰½κ²Œ μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ‹€μŒμ˜ μ½”λ“œλ₯Ό ν†΅ν•΄μ„œ Emotion의 css-propsλ₯Ό μ‚¬μš©κ°€λŠ₯ν•˜κ²Œ 변경이 κ°€λŠ₯ν•©λ‹ˆλ‹€. (λ¬Όλ‘  tsconfigμ—μ„œ jsxImportλ₯Ό λ™μ‹œμ— λ³€κ²½μ‹œμΌœμ•Όλ§Œ ν•©λ‹ˆλ‹€.)

"@babel/preset-typescript"

Babel을 μ‚¬μš©ν•˜μ—¬ TypeScript μ½”λ“œλ₯Ό 일반 JavaScript둜 λ³€ν™˜ν•˜κΈ° μœ„ν•œ Babel ν”„λ¦¬μ…‹μž…λ‹ˆλ‹€. TypeScriptλŠ” JavaScript에 νƒ€μž…μ„ μΆ”κ°€ν•œ ν™•μž₯ μ–Έμ–΄λ‘œ, 더 μ•ˆμ •μ μ΄κ³  μœ μ§€λ³΄μˆ˜ν•˜κΈ° μ‰¬μš΄ μ½”λ“œ μž‘μ„±μ„ κ°€λŠ₯ν•˜κ²Œ ν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ λΈŒλΌμš°μ €λ‚˜ 일반적인 JavaScript ν™˜κ²½μ—μ„œ 직접 싀행될 수 μ—†κΈ° λ•Œλ¬Έμ—, TypeScript μ½”λ“œλ₯Ό 일반 JavaScript μ½”λ“œλ‘œ λ³€ν™˜ν•˜λŠ” 과정이 ν•„μš”ν•©λ‹ˆλ‹€. μ΄λ•Œ @babel/preset-typescriptκ°€ μ‚¬μš©λ©λ‹ˆλ‹€.

"plugins": ["@emotion/babel-plugin"],

emotionμ—μ„œ μ œκ³΅ν•˜λŠ” babel-plugin μž…λ‹ˆλ‹€. μ—¬λŸ¬κ°€μ§€ 편의 κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€. ν•„μˆ˜μ μ΄μ§„ μ•ŠμŠ΅λ‹ˆλ‹€. 이 ν”ŒλŸ¬κ·ΈμΈμ€ Emotion μŠ€νƒ€μΌ μ½”λ“œμ˜ μ„±λŠ₯을 μ΅œμ ν™” ν•˜λŠ” κΈ°λŠ₯을 μˆ˜ν–‰ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, μŠ€νƒ€μΌμ΄ 컴파일 νƒ€μž„μ— μ •μ μœΌλ‘œ 결정될 수 μžˆλ‹€λ©΄, λŸ°νƒ€μž„ μ˜€λ²„ν—€λ“œλ₯Ό 쀄이기 μœ„ν•΄ 이λ₯Ό 미리 κ³„μ‚°ν•©λ‹ˆλ‹€.

"targets": "> 0.5%, not dead"

ν•΄λ‹Ή 섀정은 babel이 지원할 수 μžˆλŠ” λΈŒλΌμš°μ €μ˜ λ²”μœ„μ— λŒ€ν•œ 쑰건을 λͺ…μ‹œν•©λ‹ˆλ‹€. μœ„μ˜ λ¬Έλ§₯은 λ‹€μŒκ³Ό 같은 의미λ₯Ό κ°€μ§‘λ‹ˆλ‹€. "> 0.5%": μ „ 세계 μ‚¬μš©μžμ˜ 0.5% 이상이 μ‚¬μš©ν•˜λŠ” λΈŒλΌμš°μ € 버전을 λŒ€μƒμœΌλ‘œ ν•©λ‹ˆλ‹€. 즉, 전체 인터넷 μ‚¬μš©μžμ˜ 상당 뢀뢄이 μ‚¬μš©ν•˜λŠ” λΈŒλΌμš°μ € 버전에 λŒ€ν•΄ μ½”λ“œλ₯Ό μ΅œμ ν™”ν•˜κ³  λ³€ν™˜ν•©λ‹ˆλ‹€.

"not dead": '죽은' λΈŒλΌμš°μ €λŠ” μ œμ™Έν•©λ‹ˆλ‹€. μ—¬κΈ°μ„œ '죽은' λΈŒλΌμš°μ €λž€ 곡식적인 지원이 μ’…λ£Œλœ λΈŒλΌμš°μ €λ₯Ό μ˜λ―Έν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, λ³΄μ•ˆ μ—…λ°μ΄νŠΈλ‚˜ 기술 지원이 더 이상 μ œκ³΅λ˜μ§€ μ•ŠλŠ” λΈŒλΌμš°μ €λŠ” 이 범주에 μ†ν•©λ‹ˆλ‹€.

이 밖에도 Source Maps (sourceMaps),Ignore / Only (ignore, only),Environment (env),Comments (comments),Compact (compact) λ“±λ“±μ˜ 속성이 μžˆμ§€λ§Œ, μ’€ 더 ν”„λ‘œμ νŠΈκ°€ μ„±μˆ™ν•΄ 진 이후에 ν•„μš”μ„±μ΄ λŒ€λ‘λœλ‹€λ©΄ λ„μž…ν•  μ˜ˆμ •μž…λ‹ˆλ‹€.

5. webpack μ…‹νŒ…μ„ ν•΄λ³΄μž

webpack의 λͺ¨λ“  섀정을 닀루기 보단, babelκ³Ό μ—°κ²°λ˜λŠ” 뢀뢄을 μ€‘μ‹¬μœΌλ‘œ λ‚˜λ¨Έμ§€ 뢀뢄듀은 μƒλŒ€μ μœΌλ‘œ μ–•κ²Œ λ‹€λ€„λ³΄κ² μŠ΅λ‹ˆλ‹€.

μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ μˆ˜λ§Žμ€ JavaScript 파일, CSS, 이미지 λ“±μœΌλ‘œ κ΅¬μ„±λ©λ‹ˆλ‹€. Webpack은 μ΄λŸ¬ν•œ λ‹€μ–‘ν•œ μžμ›λ“€μ„ λͺ¨μ•„μ„œ λΈŒλΌμš°μ €κ°€ 이해할 수 μžˆλŠ” ν•˜λ‚˜ λ˜λŠ” μ—¬λŸ¬ 개의 파일(λ²ˆλ“€)둜 κ²°ν•©ν•©λ‹ˆλ‹€. 이 과정은 μ›Ήμ‚¬μ΄νŠΈμ˜ λ‘œλ”© μ‹œκ°„μ„ 쀄이고 μ„±λŠ₯을 ν–₯μƒμ‹œν‚€λŠ” 데 도움이 λ©λ‹ˆλ‹€. Webpack은 λ‹€μ–‘ν•œ νƒ€μž…μ˜ νŒŒμΌλ“€μ„ μ²˜λ¦¬ν•  수 μžˆλŠ” λ‘œλ” μ‹œμŠ€ν…œμ„ μ œκ³΅ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, CSS, 이미지 파일, HTML 등을 JavaScript λͺ¨λ“ˆλ‘œ λ³€ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ, ν”ŒλŸ¬κ·ΈμΈμ„ 톡해 λ²ˆλ“€λ§ ν”„λ‘œμ„ΈμŠ€μ— μ»€μŠ€ν…€ μž‘μ—…μ„ μΆ”κ°€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

천천히 webpack의 ꡬ쑰와 방식에 λŒ€ν•΄μ„œ κ°„λ‹¨νžˆ μ„€λͺ…을 ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

entry

ν”„λ‘œμ νŠΈ λ‚΄λΆ€μ˜ λͺ¨λ“  읽기 과정이 μ‹œμž‘λ˜λŠ” μœ„μΉ˜λ₯Ό μ˜λ―Έν•©λ‹ˆλ‹€. 일반적으둜 /src 의 index.ts ν˜Ήμ€ index.tsxλ₯Ό μ‹œμž‘λ˜λŠ” μœ„μΉ˜λ‘œ μ„ μ •ν•©λ‹ˆλ‹€.

output

ν”„λ‘œμ νŠΈ λ‚΄λΆ€μ˜ λͺ¨λ“  νŒŒμΌλ“€μ˜ λ²ˆλ“€λœ 결과물을 λ°˜ν™˜ν•˜λŠ” νŒŒμΌμž…λ‹ˆλ‹€.

//webpack.config.json
...
output: {
    publicPath: '/',
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js', // μž„μ‹œλ‘œ μ‚¬μš©λ˜λŠ” κ²°κ³Ό νŒŒμΌμž…λ‹ˆλ‹€. hashκ°’μœΌλ‘œ λ³€κ²½μ˜ˆμ •μž…λ‹ˆλ‹€.
    clean: true,
  },
  ...
  1. publicPath: 이 속성은 λ²ˆλ“€λ§λœ νŒŒμΌλ“€μ΄ 참쑰될 λ•Œ μ‚¬μš©λ  κΈ°λ³Έ 경둜λ₯Ό μ„€μ •ν•©λ‹ˆλ‹€. μ—¬κΈ°μ„œ '/'둜 μ„€μ •λœ 것은 μ„œλ²„μ˜ 루트 경둜λ₯Ό κΈ°μ€€μœΌλ‘œ λ¦¬μ†ŒμŠ€λ₯Ό μ œκ³΅ν•˜κ² λ‹€λŠ” μ˜λ―Έμž…λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, μ„œλ²„μ˜ 루트 URL이 http://example.com/이라면, λ²ˆλ“€λ§λœ νŒŒμΌλ“€μ€ http://example.com/bundle.js와 같은 λ°©μ‹μœΌλ‘œ 접근될 κ²ƒμž…λ‹ˆλ‹€.
  2. path: μ΄λŠ” Webpack이 μ΅œμ’…μ μœΌλ‘œ λ²ˆλ“€λ§λœ νŒŒμΌλ“€μ„ μ €μž₯ν•  λ””λ ‰ν† λ¦¬μ˜ μ ˆλŒ€ 경둜λ₯Ό μ„€μ •ν•©λ‹ˆλ‹€. path.resolve(**dirname, 'dist')λŠ” ν˜„μž¬ 파일이 μžˆλŠ” 디렉토리(**dirname)와 'dist' 디렉토리λ₯Ό ν•©μΉœ μ ˆλŒ€ 경둜λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. 즉, μ΅œμ’…μ μΈ λ²ˆλ“€ νŒŒμΌμ€ dist 폴더 내에 μ €μž₯λ©λ‹ˆλ‹€.
  3. filename: λ²ˆλ“€λ§λœ κ²°κ³Ό 파일의 이름을 μ„€μ •ν•©λ‹ˆλ‹€. 이 μ˜ˆμ œμ—μ„œλŠ” bundle.js둜 μ„€μ •λ˜μ–΄ 있으며, μ΄λŠ” λͺ¨λ“  μžλ°”μŠ€ν¬λ¦½νŠΈ νŒŒμΌλ“€μ΄ ν•˜λ‚˜μ˜ bundle.js 파일둜 합쳐져 좜λ ₯됨을 μ˜λ―Έν•©λ‹ˆλ‹€.
  4. clean: 이 속성이 true둜 μ„€μ •λ˜λ©΄, μƒˆλ‘œμš΄ λΉŒλ“œλ₯Ό 진행할 λ•Œλ§ˆλ‹€ output.path에 μ§€μ •λœ 디렉토리 λ‚΄μ˜ κΈ°μ‘΄ λͺ¨λ“  νŒŒμΌμ„ μ œκ±°ν•©λ‹ˆλ‹€. μ΄λŠ” λΉŒλ“œ κ³Όμ •μ—μ„œ μƒμ„±λ˜λŠ” νŒŒμΌλ“€μ΄ λˆ„μ λ˜λŠ” 것을 λ°©μ§€ν•˜κ³ , 항상 μ΅œμ‹ μ˜ λΉŒλ“œ κ²°κ³Όλ§Œμ„ μœ μ§€ν•˜κΈ° μœ„ν•œ μ„€μ •μž…λ‹ˆλ‹€.

λ˜ν•œ dist폴더 내뢀에 bundle.js 뿐 μ•„λ‹ˆλΌ index.html이 ν¬ν•¨λ˜μ–΄ μžˆλŠ”λ°, μ΄λŠ” output option이 μ•„λ‹Œ pluginμ—μ„œ μ²˜λ¦¬ν•΄μ€λ‹ˆλ‹€.

 new HtmlWebpackPlugin({
      template: './public/index.html',
      filename: 'index.html',
    }),

ν•΄λ‹Ή 방식을 ν†΅ν•΄μ„œ index.html이 dist파일 내뢀에 μ„ μ–Έλ©λ‹ˆλ‹€. μ΄λ•Œ index.html이 μƒμ„±λ˜λŠ” μœ„μΉ˜λŠ” output μ˜΅μ…˜μ˜ pathκ·œμΉ™μ„ λ”°λ¦…λ‹ˆλ‹€.

module의 rules

module: {
    rules: [
      {
        test: /\.(ts|tsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
	....
	]

λ‹€μŒκ³Ό 같이 μ„ μ–Έν•˜μ—¬ babelrc에 μž‘μ„±ν•œ λ‚΄μš©μ„ λ°”νƒ•μœΌλ‘œ μ»΄νŒŒμΌμ‹œν‚¨ ν›„ λ²ˆλ“€λ§ μ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€. babel의 κ΄€λ ¨λœ μ˜΅μ…˜μ€ μƒλ‹¨μ˜ babelrcμ—μ„œ μ²˜λ¦¬λ˜μ—ˆκΈ° λ•Œλ¬Έμ—, 재 μ„ μ–Έν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. (ν•˜μ§€λ§Œ ν•΄λ‹Ή pr을 올릴 λ‹Ήμ‹œμ—λŠ” 이 문제λ₯Ό 깨닫지 λͺ»ν•˜κ³  쀑볡선언 λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. 이 문제의 처리λ₯Ό μœ„ν•΄ λ°±λ‘œκ·Έμ— κΈ°μž…ν›„ pr에도 μΆ”κ°€μ μœΌλ‘œ 기둝을 λ‚¨κ²¨λ‘μ—ˆμŠ΅λ‹ˆλ‹€.)

μΆ”κ°€μ μœΌλ‘  tsconfig와 μ—°κ²°ν•˜μ—¬ alias μ„€μ •, devServer 관련섀정이 μžˆμŠ΅λ‹ˆλ‹€

6. eslint $ prettier μ„€μ •

사싀 λ‚˜λ¨Έμ§€λŠ” 크게 어렡지 μ•Šμ€ μ˜΅μ…˜μ΄μ—ˆμŠ΅λ‹ˆλ‹€.

// .prettierrc.json
{
  "tabWidth": 2,
  "printWidth": 80,
  "singleQuote": true,
  "endOfLine": "auto",
  "arrowParens": "always",
  "trailingComma": "es5"
}
// ts와 react, css-props κΈ°μ€€ ν•„μš”ν•œ μ˜΅μ…˜λ§Œμ„ μ°Ύμ•„ μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€.
{
  "root": false,
  "parser": "@typescript-eslint/parser",
  "env": {
    "browser": true,
    "node": true
  },
  "ignorePatterns": ["webpack.config.js"],
  "parserOptions": {
    "project": ["./FE/tsconfig.json"] // 진행쀑인 ν”„λ‘œμ νŠΈκ°€ λͺ¨λ…Έλ ˆν¬λ‘œ κ΅¬μ„±λ˜μ–΄ λ‹€μŒκ³Ό 같은 μ˜΅μ…˜μ„ μ£Όμ–΄μ•Ό ν–ˆμŠ΅λ‹ˆλ‹€.
  },
  "plugins": ["@typescript-eslint", "prettier", "unused-imports"],
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/recommended-requiring-type-checking",
    "plugin:react/recommended",
    "plugin:react/jsx-runtime",
    "plugin:react-hooks/recommended",
    "prettier"
  ],
  "rules": {
    "no-unused-vars": "off",
    "@typescript-eslint/no-unused-vars": "off",
    "unused-imports/no-unused-imports": "error",
    "unused-imports/no-unused-vars": [
      "warn",
      {
        "vars": "all",
        "varsIgnorePattern": "^_",
        "args": "after-used",
        "argsIgnorePattern": "^_"
      }
    ],
    "no-console": "warn",
    "react/no-unknown-property": ["error", { "ignore": ["css"] }],
    "react/prop-types": "off"
  },
  "settings": {
    "react": {
      "version": "detect" // μžλ™μœΌλ‘œ λ¦¬μ•‘νŠΈ 버전 감지
    }
  }
}

prettier와 eslintλŠ” λ˜λ„λ‘ μ—„κ²©ν•˜κ²Œ κ²€μ‚¬ν•˜λ„λ‘ μ„€μ •ν–ˆμŠ΅λ‹ˆλ‹€.

맺음말

μ§€κΈˆκΉŒμ§€ CRA 없이 ν”„λ‘œμ νŠΈ μ…‹νŒ…μ— λŒ€ν•΄μ„œ 진행해 λ³΄μ•˜μŠ΅λ‹ˆλ‹€. ν•΄λ‹Ή μ½”λ“œλ₯Ό μž‘μ„±ν•œ PR이며,

아직 μ‹œμž‘μ— λΆˆκ³Όν•˜μ§€λ§Œ, ν”„λ‘œμ νŠΈλ₯Ό μ§„ν–‰ν•˜λ©° webapck에 λŒ€ν•΄μ„œ 더 κΉŠμ€ ν•™μŠ΅μ΄ κ°€λŠ₯ν•˜λ©΄ μ’‹κ² μŠ΅λ‹ˆλ‹€.

Β© 2024 Adultlee. All rights reserved.Made with ❀ by 이성인