๋ฐ˜์‘ํ˜•

prettier-plugin-tailwindcss ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜๋ฉด TailwindCSS์˜ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค ์ •๋ ฌ ๊ทœ์น™์— ๋”ฐ๋ผ ํด๋ž˜์Šค๋ฅผ ์ž๋™ ์ •๋ ฌํ•ด์ค€๋‹ค. ์ด์ „๊นŒ์ง„ Tailwind Formatter ๊ฐ™์€ IDE ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•ด์„œ ์ •๋ ฌ์ด ํ•„์š”ํ•  ๋•Œ๋งˆ๋‹ค ๋ถ€๊ฐ€๊ธฐ๋Šฅ์„ ์‹คํ–‰(โŒƒ โ‡ง H)ํ–ˆ๋Š”๋ฐ ๊ทธ๋Ÿด ํ•„์š”๊ฐ€ ์—†์–ด์กŒ๋‹ค.

 

prettier-plugin-tailwindcss ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์„ค์น˜ํ•˜๊ณ  ํŒŒ์ผ ์ €์žฅ์‹œ ์ž๋™ ํฌ๋งคํŒ… ๋˜๋„๋ก IDE๋ฅผ ์„ค์ •ํ•˜๋ฉด, ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค๋„ ํ•จ๊ป˜ ์ •๋ ฌ๋ผ์„œ ํŽธํ•˜๋‹ค.

 

์ฐธ๊ณ ๋กœ ํด๋ž˜์Šค ์ž๋™ ์ •๋ ฌ ์™ธ์—๋„ ์ž˜๋ชป ์ž…๋ ฅํ•œ ํด๋ž˜์Šค ์˜ค๋ฅ˜ ํ‘œ์‹œ, ์ถ•์•ฝ(shorthand) ์‚ฌ์šฉ ๊ฐ•์ œ, ์ž„์˜(arbitrary) ๊ฐ’ ์‚ฌ์šฉ ๊ธˆ์ง€ ๊ฐ™์€ ๊ทœ์น™์ด ์ ์šฉ๋œ eslint-plugin-tailwindcss ESLint ํ”Œ๋Ÿฌ๊ทธ์ธ๋„ ์žˆ๋‹ค.

 

์„ค์ • ๋ฐฉ๋ฒ•


โถ prettier-plugin-tailwindcss ํ”Œ๋Ÿฌ๊ทธ์ธ ์„ค์น˜

yarn add -D prettier prettier-plugin-tailwindcss

 

โท .prettierrc ์„ค์ • ํŒŒ์ผ์— plugins ์†์„ฑ ์ถ”๊ฐ€

{
  // ...
  plugins: ['prettier-plugin-tailwindcss'],
};

 

์‚ฌ์šฉ ๋ฐฉ๋ฒ•


๐Ÿ’ก  ํŒŒ์ผ ์ €์žฅ์‹œ Prettier ํฌ๋งคํŒ… ๋˜๋„๋ก IDE ์„ค์ •์„ ํ–ˆ๋‹ค๋ฉด ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค๋„ ํ•จ๊ป˜ ์ •๋ ฌ๋œ๋‹ค.

 

์„ค์ •์„ ์™„๋ฃŒํ•˜๊ณ  ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ณด๋ฉด ํด๋ž˜์Šค ์ด๋ฆ„์„ ์žฌ๋ฐฐ์น˜ ํ•˜๋ผ๋Š” ๊ฒฝ๊ณ ๊ฐ€ ๋‚˜์˜จ๋‹ค.

 

์ˆ˜์ •ํ•˜๋ฉด recommended class order ์ˆœ์„œ๋Œ€๋กœ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค๊ฐ€ ์ •๋ ฌ๋œ๋‹ค.

<!-- ์ •๋ ฌ ์ „ -->
<Header className="flex gap-8 items-center fixed top-0 z-10 w-full">

<!-- ์ •๋ ฌ ํ›„ -->
<Header className="fixed top-0 z-10 flex w-full items-center gap-8">

 

ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์— ์žˆ๋Š” ๋ชจ๋“  ํŒŒ์ผ์„ ํฌ๋งทํŒ…์„ ํ•˜๋ ค๋ฉด ํ„ฐ๋ฏธ๋„์— ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•œ๋‹ค

# ํ˜„์žฌ ํด๋” ์œ„์น˜๋ถ€ํ„ฐ ๋ชจ๋“  ํŒŒ์ผ์— ๋Œ€ํ•ด ํฌ๋งคํŒ… ๋๋Š”์ง€ "๊ฒ€์‚ฌ"(์ˆ˜์ •ํ•˜์ง„ ์•Š์Œ)
npx prettier --check .

# ํ˜„์žฌ ํด๋” ์œ„์น˜๋ถ€ํ„ฐ ๋ชจ๋“  ํŒŒ์ผ์— ๋Œ€ํ•ด "ํฌ๋งคํŒ…"
npx prettier --write .

# ๋ชจ๋“  ์œ„์น˜์— ์žˆ๋Š” js, ts, jsx, tsx ํ™•์žฅ์ž์— ๋Œ€ํ•ด ๋Œ€ํ•ด "ํฌ๋งคํŒ…"
npx prettier --write "**/*.{js,ts,jsx,tsx}"

 

package.json์— ์Šคํฌ๋ฆฝํŠธ ๋ช…๋ น์–ด๋ฅผ ๋งŒ๋“ค์–ด๋‘๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

"scripts": {
  // ํ”„๋กœ์ ํŠธ์— Prettier ํŒจํ‚ค์ง€๊ฐ€ ์„ค์น˜๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ npx๋ฅผ ๋ถ™์ด์ง€ ์•Š์•˜๋‹ค
  "format": "prettier --write '**/*.{js,jsx,ts,tsx}'"
},

 

Husky ์„ค์ •


Goot Hook์„ ์‚ฌ์šฉํ•˜๋ฉด ์ปค๋ฐ‹, ํ‘ธ์‹œ ๋“ฑ์˜ git ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ๋ฏธ๋ฆฌ ์ง€์ •ํ•œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ปค๋ฐ‹ํ–ˆ์„ ๋•Œ ํŠน์ • ๋™์ž‘์„ ์ˆ˜ํ–‰(์ปค๋ฐ‹ ์ „์— ์ˆ˜ํ–‰)ํ•˜๋Š” pre-commit hook์„ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค. Git Hook ์ œ์–ด๋Š” ๋ณดํ†ต Husky ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์ˆ˜์ •ํ•œ ํŒŒ์ผ์— ๋Œ€ํ•ด์„œ๋งŒ Hook์„ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด Lint Staged๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

์•„๋ž˜๋Š” pre-commit hook์„ ์ด์šฉํ•ด ์ˆ˜์ • ํŒŒ์ผ์„ ์ปค๋ฐ‹ํ–ˆ์„ ๋•Œ Prettier ํฌ๋งคํŒ…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. ํ”„๋กœ์ ํŠธ์—์„œ "eslint-config|plugin-prettier" ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ํ†ตํ•ด Prettier ์ฝ”๋“œ ์Šคํƒ€์ผ ๊ทœ์น™ ์˜ค๋ฅ˜๋ฅผ ESLint์—์„œ ํ‘œ์‹œํ•˜๊ณ  ์ˆ˜์ •ํ•˜๋„๋ก ์„ค์ •ํ–ˆ๋‹ค๋ฉด prettier --write ๋Œ€์‹  eslint --fix ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

โถ ํŒจํ‚ค์ง€ ์„ค์น˜

yarn add -D husky lint-staged # husky, lint-staged ํŒจํ‚ค์ง€ ์„ค์น˜

 

โท husky ์ดˆ๊ธฐ ์„ธํŒ…

npx husky install # ๋ช…๋ น์–ด ์‹คํ–‰ ํ›„ ๋ฃจํŠธ ํด๋”์— .husky ํด๋” ์ƒ์„ฑ๋จ

 

โธ package.json ํŒŒ์ผ์— prepare ์Šคํฌ๋ฆฝํŠธ ์ถ”๊ฐ€

npm pkg set scripts.prepare="husky install"

 

์œ„ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋ฉด package.json ํŒŒ์ผ์— prepare ์Šคํฌ๋ฆฝํŠธ ๋ช…๋ น์–ด๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค. prepare ์Šคํฌ๋ฆฝํŠธ๋Š” ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•˜๊ฑฐ๋‚˜ ์—…๋ฐ์ดํŠธํ•  ๋•Œ ์ž๋™์œผ๋กœ ์‹คํ–‰๋œ๋‹ค. ์ฆ‰, ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋ฅผ ํด๋ก ํ•˜๊ณ  ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•  ๋•Œ prepare ์Šคํฌ๋ฆฝํŠธ๋„ ์‹คํ–‰๋ผ์„œ husky๊ฐ€ ์„ค์น˜๋œ๋‹ค.

// package.json
"scripts": {
  "prepare": "husky install"
},

 

โน .husky/pre-commit ํŒŒ์ผ์— npx lint-staged ๋ช…๋ น์–ด ์ถ”๊ฐ€ (yarn lint-staged๋„ ๊ฐ€๋Šฅ)

npx add .husky/pre-commit "npx lint-staged"

 

์œ„ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋ฉด .husky/pre-commit ํŒŒ์ผ ์ œ์ผ ๋งˆ์ง€๋ง‰์— npx lint-staged ๋ช…๋ น์–ด๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค. ํ•ด๋‹น ํŒŒ์ผ์— ์›ํ•˜๋Š” ๋ช…๋ น์–ด๋ฅผ ์ง์ ‘ ์ถ”๊ฐ€ํ•ด๋„ ๋œ๋‹ค.

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx lint-staged

 

โบ package.json ํŒŒ์ผ์— lint-staged ์†์„ฑ ๋ฐ ๋ช…๋ น์–ด ์ถ”๊ฐ€. eslint์˜ --cache ์˜ต์…˜์€ ์ด๋ฏธ ๋ฆฐํŠธ๋ฅผ ์™„๋ฃŒํ•œ ํŒŒ์ผ์˜ ๊ฒฐ๊ณผ๋ฅผ .eslintcache ์บ์‹œ ํŒŒ์ผ์— ์ €์žฅํ•˜๊ณ , ์ดํ›„ ๋ฆฐํŠธ ์ž‘์—… ๋•Œ ์ด ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์€ ํŒŒ์ผ์€ ๋น ๋ฅด๊ฒŒ ๊ฑด๋„ˆ๋›ธ ์ˆ˜ ์žˆ๋‹ค. ๋งŽ์€ ํŒŒ์ผ์ด ์žˆ๋Š” ํฐ ํ”„๋กœ์ ํŠธ์—์„œ ์œ ์šฉํ•œ ์˜ต์…˜.

"lint-staged": {
  "*.{js,jsx,ts,tsx}": [
    "eslint --cache --fix"
    // "eslint-config|plugin-prettier" ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์•ˆ์“ด๋‹ค๋ฉด ์•„๋ž˜ ๋ช…๋ น์–ด ์ถ”๊ฐ€
    // prettier --write
  ]
},

 

์œ„์ฒ˜๋Ÿผ ์„ค์ •ํ–ˆ๋‹ค๋ฉด ์ปค๋ฐ‹ํ•  ๋•Œ๋งˆ๋‹ค ์ˆ˜์ •ํ•œ ํŒŒ์ผ์— ๋Œ€ํ•ด lint-staged ๋ฐฐ์—ด์— ๋“ฑ๋กํ•œ ๋ช…๋ น์–ด๊ฐ€ ์‹คํ–‰๋œ๋‹ค. ๋งŒ์•ฝ ์ปค๋ฐ‹ํ•  ๋•Œ๋งˆ๋‹ค ๋ชจ๋“  ํŒŒ์ผ์— ๋Œ€ํ•ด ํŠน์ • ์•ก์…˜์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด pre-commit ํŒŒ์ผ์— ์›ํ•˜๋Š” ๋ช…๋ น์–ด๋ฅผ ์ง์ ‘ ์ถ”๊ฐ€ํ•œ๋‹ค.

# format๋Š” package.json.scripts์— ๋“ฑ๋กํ•œ ์Šคํฌ๋ฆฝํŠธ
# ์ปค๋ฐ‹ํ•˜๋ฉด ๋ชจ๋“  ํŒŒ์ผ์„ ๋Œ€์ƒ์œผ๋กœ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹คํ–‰๋œ๋‹ค
npx add .husky/pre-commit "yarn format"

 

์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค ์ •๋ ฌ ๊ทœ์น™


โถ base layer → components layer → utilities layer ์ˆœ์„œ๋Œ€๋กœ ์ •๋ ฌ

<!-- `container` is a component so it comes first -->
<div class="container mx-auto px-6">
  <!-- ... -->
</div>

 

โท ๋‹ค๋ฅธ ํด๋ž˜์Šค๋ฅผ ๋ฎ์–ด์“ฐ๋Š” ํด๋ž˜์Šค๋Š” ๋’ค์— ์œ„์น˜ (CSS ์šฐ์„ ์ˆœ์œ„์™€ ๋™์ผ)

<!-- pt-2๊ฐ€ p-4๋ฅผ ๋ฎ์–ด์“ฐ๋ฏ€๋กœ pt-2๊ฐ€ ๋’ค๋กœ ์˜ค๋„๋ก ์ •๋ ฌ๋จ --> 
- <div class="pt-2 p-4">
+ <div class="p-4 pt-2">
    <!-- ... -->
  </div>

 

โธ layout์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š” ํด๋ž˜์Šค๋Š” ์•ž์— ์œ„์น˜, decorative ํด๋ž˜์Šค๋Š” ๋’ค์— ์œ„์น˜

- <div class="text-gray-700 shadow-md p-3 border-gray-300 ml-4 h-24 flex border-2">
+ <div class="ml-4 flex h-24 border-2 border-gray-300 p-3 text-gray-700 shadow-md">
    <!-- ... -->
  </div>

 

โน hover:, focus: ๊ฐ™์€ ์˜์‚ฌ ํด๋ž˜์Šค๋Š” ๊ทธ๋ฃนํ™”๋œ ํ›„ plain ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค ๋’ค์— ์œ„์น˜

- <div class="hover:opacity-75 opacity-50 hover:scale-150 scale-125">
+ <div class="scale-125 opacity-50 hover:scale-150 hover:opacity-75">
    <!-- ... -->
  </div>

 

โบ md:, lg: ๊ฐ™์€ ๋ฐ˜์‘ํ˜• modifiers๋Š” ๊ทธ๋ฃนํ™”๋œ ํ›„ ๋’ค์— ์œ„์น˜(smallest → largest ์ˆœ์„œ)

- <div class="lg:grid-cols-4 grid sm:grid-cols-3 grid-cols-2">
+ <div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4">
    <!-- ... -->
  </div>

 

โป Tailwind์—์„œ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š” ์ปค์Šคํ…€ ํด๋ž˜์Šค๋Š” ํ•ญ์ƒ ์•ž์ชฝ์— ์œ„์น˜

- <div class="p-3 shadow-xl select2-dropdown">
+ <div class="select2-dropdown p-3 shadow-xl">
  <!-- ... -->
</div>

 

๋ ˆํผ๋Ÿฐ์Šค


 


๊ธ€ ์ˆ˜์ •์‚ฌํ•ญ์€ ๋…ธ์…˜ ํŽ˜์ด์ง€์— ๊ฐ€์žฅ ๋น ๋ฅด๊ฒŒ ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค. ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•ด ์ฃผ์„ธ์š”
๋ฐ˜์‘ํ˜•