TOAST UI - ํ„ฐ์น˜์™€ ํด๋ฆญ ์ด๋ฒคํŠธ ๊ธ€์—์„œ ์ƒ๊ธด ์˜๋ฌธ์„ ์ •๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.

 

ํ„ฐ์น˜ & ํด๋ฆญ ?!

 

ํ„ฐ์น˜ ์ด๋ฒคํŠธ๋ฅผ ๋‹ฌ์•˜๋Š”๋ฐ ์™œ ํด๋ฆญ ์ด๋ฒคํŠธ๊นŒ์ง€ ๋ฐœ์ƒํ•˜๋‚˜์š”?

  • ํ„ฐ์น˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋‚ด๊ฐ€ ๋ณ„๋„๋กœ ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ๋‹ฌ์ง€ ์•Š์•˜์–ด๋„ click ์ด๋ฒคํŠธ๊ฐ€ ์ค‘๋ณต์œผ๋กœ ๋ฐœ์ƒํ•ด ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค.
    ์™œ ์ด๋Ÿฐ ๋™์ž‘์ด ์ผ์–ด๋‚˜๋Š” ๊ฑธ๊นŒ์š”?
  • ์›น์€ ์˜ค๋žซ๋™์•ˆ ๋งˆ์šฐ์Šค ํด๋ฆญ ์ค‘์‹ฌ์œผ๋กœ ์„ค๊ณ„๋˜๊ณ  ๋ฐœ์ „ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ์ง€๊ธˆ๊นŒ์ง€ ๋งŽ์€ ์‚ฌ์ดํŠธ๊ฐ€ ์˜ค์ง click ์ด๋ฒคํŠธ๋งŒ ๋“ฃ๊ณ  ๋™์ž‘ํ•˜๋„๋ก ๋งŒ๋“ค์–ด์ ธ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋ชจ๋ฐ”์ผ ๋ธŒ๋ผ์šฐ์ €๋Š” ํ˜ธํ™˜์„ฑ ์œ ์ง€๋ฅผ ์œ„ํ•ด ํ„ฐ์น˜ ์‹œ ์ž๋™์œผ๋กœ click ์ด๋ฒคํŠธ๋„ ํ•จ๊ป˜ ๋ฐœ์ƒ์‹œํ‚ค๋„๋ก ์„ค๊ณ„๋ผ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ์— ํ„ฐ์น˜์Šคํฌ๋ฆฐ ํ™˜๊ฒฝ์—์„œ๋„ ๊ธฐ์กด ๋งˆ์šฐ์Šค ์ค‘์‹ฌ ์‚ฌ์ดํŠธ๋“ค์ด ๋ณ„๋„ ์ˆ˜์ • ์—†์ด ๋™์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

ํ„ฐ์น˜ ์ด๋ฒคํŠธ ํ›„ click ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒŒ ์™œ ํŽธ์˜์ผ๊นŒ์š”?

  • ์—ฌ๋Ÿฌ ์ž๋ฃŒ์—์„œ ์ด๊ฑธ ํŽธ์˜๋ผ๊ณ  ํ•˜๋˜๋ฐ ํ‘œํ˜„์ด ๋„ˆ๋ฌด ํฌ๊ด„์ ์œผ๋กœ ๋А๊ปด์ ธ์„œ ๊ทธ๋Ÿฐ์ง€ ์ฒ˜์Œ์—๋Š” ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ์ œ๊ฐ€ ์ฐพ์•„๋ณธ ํ›„ ์ดํ•ดํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค!
    • ๋ธŒ๋ผ์šฐ์ €๋Š” ์ด ์‚ฌ์ดํŠธ๊ฐ€ ํ„ฐ์น˜/ํด๋ฆญ ๋‘˜ ๋‹ค ์ง€์›ํ•˜๋Š”์ง€, ์–ด๋–ค ์‹์œผ๋กœ ์˜๋„ํ–ˆ๋Š”์ง€ ์•Œ ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค.
    • ๊ทธ๋ž˜์„œ ์ผ๊ด„์ ์œผ๋กœ, ํ„ฐ์น˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋ฐ˜๋“œ์‹œ click ์ด๋ฒคํŠธ๋„ ๊ฐ™์ด ๋ฐœ์ƒํ•˜๋„๋ก ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.
    • ๋ธŒ๋ผ์šฐ์ €๋Š” ์ €ํฌ๊ฐ€ ๋งŒ๋“  ์‚ฌ์ดํŠธ๋งŒ ๋„์šฐ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์•„์ฃผ ๋งŽ์€ ์‚ฌ์ดํŠธ๋ฅผ ๋™์‹œ์— ์ง€์›ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋ฐ”์ผ ๋„์ž… ์ดˆ๊ธฐ์—” ๋Œ€๋ถ€๋ถ„ ์˜ค์ง ํด๋ฆญ ์ด๋ฒคํŠธ๋งŒ ์‚ฌ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—, ํ„ฐ์น˜ ์ด๋ฒคํŠธ๋งŒ ๋ฐœ์ƒ์‹œ ํด๋ฆญ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋ฉด ์˜›๋‚  ์‚ฌ์ดํŠธ๋“ค์ด ๋ชจ๋ฐ”์ผ์—์„œ ๋จนํ†ต์ด ๋  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํ„ฐ์น˜ ์‹œ ์ž๋™์œผ๋กœ ํด๋ฆญ ์ด๋ฒคํŠธ๋„ ๋ฐœ์ƒ์‹œํ‚ค๋„๋ก ์„ค๊ณ„๋˜์—ˆ๊ณ  ๊ธฐ์กด ํด๋ฆญ ๊ธฐ๋ฐ˜ ์‚ฌ์ดํŠธ์™€์˜ ํ˜ธํ™˜์„ฑ๋„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

 

React ๋“ฑ์—์„œ๋„ ํด๋ฆญ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ• ๊นŒ์š”?

  • ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” React ๊ธฐ์ค€์œผ๋กœ ์—ฌ๊ธฐ์„œ๋„ ๋ธŒ๋ผ์šฐ์ €์˜ ์ด๋ฒคํŠธ ์œ„์ž„ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ๊ทธ๋Œ€๋กœ ๋”ฐ๋ž์Šต๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €์˜ ๋„ค์ดํ‹ฐ๋ธŒ ์ด๋ฒคํŠธ ์‹œ์Šคํ…œ์„ ๊ทธ๋Œ€๋กœ ํ™œ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋™์ผํ•œ ๋™์ž‘์ด ๋ฐœ์ƒํ•ด์š”.
  • ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ„ฐ์น˜ ์ด๋ฒคํŠธ ํ›„ ์ž๋™์œผ๋กœ ๋งˆ์šฐ์Šค์™€ ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋Š”๊ฑด React ์ด์ „ ๋‹จ๊ณ„์—์„œ ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค.
  • React๋Š” ๋ธŒ๋ผ์šฐ์ €์˜ ๋„ค์ดํ‹ฐ๋ธŒ ์ด๋ฒคํŠธ๋ฅผ ๊ฐ์‹ธ๋Š” SyntheticEvent๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด์š”. ํ•˜์ง€๋งŒ ๋ธŒ๋ผ์šฐ์ €์˜ ๊ธฐ๋ณธ ์ด๋ฒคํŠธ ๋™์ž‘์€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  ์ด๋ฒคํŠธ ์œ„์ž„์„ ์‚ฌ์šฉํ•˜์ง€๋งŒ ์ด๊ฑด ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์„ ์ตœ์ ํ™”ํ•˜๋Š” ๊ฒƒ์ด์ง€ ๋ธŒ๋ผ์šฐ์ €์˜ ๊ธฐ๋ณธ ์ด๋ฒคํŠธ ๋™์ž‘์„ ๋ฐ”๊พธ๋Š”๊ฒŒ ์•„๋‹™๋‹ˆ๋‹ค.
  • ๊ด€๋ จ ํ† ๋ก ์ธ GitHub ์ด์Šˆ #9809๋ฅผ ์ •๋ฆฌํ•ด๋ณด๋ฉด,
    • preventDefault() ๋ฌดํšจํ™”: React์˜ ํ•ฉ์„ฑ ์ด๋ฒคํŠธ์—์„œ e.prevnetDefault()๊ฐ€ ํด๋ฆญ ์ด๋ฒคํŠธ ๋ฐฉ์ง€์— ์‹คํŒจ
    • ๋„ค์ดํ‹ฐ๋ธŒ DOM API๋Š” ์ž‘๋™: addEventListener๋กœ ์ง์ ‘ ๋“ฑ๋กํ•˜๋ฉด preventDefault()๊ฐ€ ์ •์ƒ ๋™์ž‘
    • ๋ธŒ๋ผ์šฐ์ €๋ณ„ ์ฐจ์ด: Chrome, Firefox, Safari์—์„œ ๊ฐ๊ฐ ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ (์ถ”๊ฐ€ ํ™•์ธ์ด ํ•„์š”)
  • ์œ„์˜ ๋‚ด์šฉ์€ ๊ด€๋ จ ์ด์Šˆ๋ฅผ ์ง์ ‘ ๋ณด๊ณ  ์ƒ์„ธ ๋‚ด์šฉ๊ณผ ์ด์œ ๋ฅผ ํ™•์ธํ•ด ๋ณด๋Š”๊ฑธ ์ถ”์ฒœ๋“œ๋ฆฝ๋‹ˆ๋‹ค!
  • ์ด์Šˆ์—์„œ ์ œ์‹œ๋œ ํ•ด๊ฒฐ์ฑ…๋“ค๋„ ์งง๊ฒŒ๋ผ๋„ ์ •๋ฆฌํ•ด ๋ณด๊ฒŸ์Šต๋‹ˆ๋‹ค.
// ๋ฐฉ๋ฒ• 1: ๋„ค์ดํ‹ฐ๋ธŒ DOM API ์‚ฌ์šฉ
componentDidMount() {
  this.elem.addEventListener('touchstart', e => {
    e.preventDefault(); // ์ด๊ฑด ์ž‘๋™ํ•จ
  });
}

// ๋ฐฉ๋ฒ• 2: ํ”Œ๋ž˜๊ทธ ์‚ฌ์šฉ
handleTouchStart(event) {
  this.hasBeenTouchedRecently = true;
  setTimeout(() => { 
    this.hasBeenTouchedRecently = false; 
  }, 500);
}

handleMouseDown(event) {
  if(this.hasBeenTouchedRecently) {
    return; // ํ„ฐ์น˜ ํ›„ ๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ ๋ฌด์‹œ
  }
}

 

 

 

๋ทฐํฌํŠธ ๋ฉ”ํƒ€ ํƒœ๊ทธ์™€ ๋ฐ์Šคํฌํƒ‘/๋ชจ๋ฐ”์ผ ๋™์‹œ ์ง€์›์˜ ๋ฌธ์ œ๋Š” ์—†์„๊นŒ์š”?

 <meta name="viewport" content="width=device-width">
  •  ์œ„ ์ฝ”๋“œ๋ฅผ ๋„ฃ์œผ๋ฉด ๋ชจ๋ฐ”์ผ์—์„œ ํ„ฐ์น˜ ๋”œ๋ ˆ์ด๊ฐ€ ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค.
  • ์ด ํƒœ๊ทธ๋Š” ๋ชจ๋ฐ”์ผ๋งŒ์ด ์•„๋‹ˆ๋ผ ๋ฐ์Šคํฌํƒ‘์— ํฌํ•จํ•ด๋„ ๋ฌด๋ฐฉํ•ด์š”.

 

ํ„ฐ์น˜/ํด๋ฆญ ๋”œ๋ ˆ์ด๋Š” 2025๋…„์—๋„ ๋˜‘๊ฐ™์ด ๋ฐœ์ƒํ• ๊นŒ์š”?

  • ๊ณผ๊ฑฐ์—” 300ms์˜ ํ„ฐ์น˜→ํด๋ฆญ ๋”œ๋ ˆ์ด๊ฐ€ ์žˆ์—ˆ์ง€๋งŒ ํ˜„์žฌ ์ตœ์‹  ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” ๋ทฐํฌํŠธ ๋ฉ”ํƒ€ ํƒœ๊ทธ๋‚˜ CSS ์„ธํŒ…๋งŒ ์ž˜ ํ•˜๋ฉด ๋”œ๋ ˆ์ด ๋ฌธ์ œ๋Š” ๊ฑฐ์˜ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

๐Ÿ“ƒ ์ฐธ๊ณ  ๋ฌธํ—Œ  
Chrome ๊ฐœ๋ฐœ์ž ๋ธ”๋กœ๊ทธ - A More Compatible, Smoother Touch
quirksmode

 

ํ”„๋ฆฌํ”ฝ์Šค!!

 

ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค ๋ณด๋ฉด ํฌ๋กœ์Šค๋ธŒ๋ผ์šฐ์ง• ์ด์Šˆ๋Š” ํ”ผํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

::-webkit-input-placeholder์™€ ๊ฐ™์€ ๋ธŒ๋ผ์šฐ์ €๋ณ„ ํ”„๋ฆฌํ”ฝ์Šค(-webkit-, -moz-, -ms- ๋“ฑ)๋ฅผ ์ผ์ผ์ด ์ถ”๊ฐ€ํ•˜๋Š” ๊ฑด ๊ต‰์žฅํžˆ ๋ฒˆ๊ฑฐ๋กœ์šด ์ž‘์—…์ด์˜ˆ์š”.

 

์‚ฌ์‹ค ํ˜„์—…์—์„œ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ด๋Ÿฌํ•œ ํ”„๋ฆฌํ”ฝ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ๋งค์šฐ ๊ณค๋ž€ํ•œ ์ผ์ž…๋‹ˆ๋‹ค.

(์ €๋„ ๊ด€๋ จ๋œ ๋Œ€ํ™”๋ฅผ ๋‚˜๋ˆ„๋‹ค ์•Œ๊ฒŒ๋์–ด์š”!)

 

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ฒˆ๋“ค๋Ÿฌ๋ฅผ ํ†ตํ•ด ์ž๋™์œผ๋กœ ํ”„๋ฆฌํ”ฝ์Šค๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๋Š” ๋ฐฉ๋ฒ•์ธ Autoprefixer๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

PostCSS๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ผ๋ฉด, ํ˜น์€ CSS๋กœ ๋ณ€ํ™˜ํ•œ ํ›„ postcss-loader๊ฐ€ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ํ•œ๋‹ค๋ฉด ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฐ ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ์— ๋งž๊ฒŒ ์Šคํƒ€์ผ์„ ๋”ฐ๋กœ ์ž‘์„ฑํ•˜์ง€ ์•Š์•„๋„ Autoprefixer๊ฐ€ ์›นํ‚ท ํ”„๋ฆฌํ”ฝ์Šค์™€ ๊ฐ™์€ ๊ฒƒ์„ ์ž๋™์œผ๋กœ ๋ถ™์—ฌ์ค๋‹ˆ๋‹ค.

 

์ด๋ฒˆ ํฌ์ŠคํŠธ์—์„œ๋Š” PostCSS์™€ Autoprefixer๋ฅผ ํ™œ์šฉํ•ด ํ•ด๋‹น ISSUE๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‹ค์ œ ํ”„๋กœ์ ํŠธ ๊ฒฝํ—˜์„ ๋ฐ”ํƒ•์œผ๋กœ ์ƒ์„ธํžˆ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!

 

PostCSS์™€ Autoprefixer๋ž€?

PostCSS

  • JavaScript ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•ด CSS๋ฅผ ๋ณ€ํ™˜ํ•˜๋Š” ๋„๊ตฌ
  • "Post-processor"๋ผ๊ณ ๋„ ๋ถˆ๋ฆฌ๋Š” ์ด์œ ๋Š” CSS๋ฅผ ์ž‘์„ฑํ•œ ํ›„์— ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ
  • CSS ๊ตฌ๋ฌธ ๋ถ„์„์— ์ตœ์ ํ™”๋œ ํŒŒ์„œ๋ฅผ ์‚ฌ์šฉํ•ด ๋†’์€ ์„ฑ๋Šฅ์„ ๋ณด์ž„
  • CSS ์ „์ฒ˜๋ฆฌ๊ธฐ(Sass)๋‚˜ ํ›„์ฒ˜๋ฆฌ๊ธฐ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ (์ด ๋ถ€๋ถ„์€ ์ œ๊ฐ€ ํ—ท๊ฐˆ๋ ธ๋˜ ๋ถ€๋ถ„์ด๋ผ ์•„๋ž˜ ์ถ”๊ฐ€์„ค๋ช…์„ ๋„ฃ์—ˆ์–ด์š”!)
    1. CSS ์ „์ฒ˜๋ฆฌ๊ธฐ(SASS):
      CSS ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•œ ์–ธ์–ด ์ž…๋‹ˆ๋‹ค. ๋ณ€์ˆ˜, ์ค‘์ฒฉ ๊ทœ์น™, ๋ฏน์Šค์ธ ๋“ฑ์„ ์ง€์›ํ•˜๊ณ , PostCSS๋Š” Sass๋กœ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, PostCSS ์ž์ฒด๋Š” Sass ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜์ง„ ์•Š์•„์š”.
    2. CSS ํ›„์ฒ˜๋ฆฌ๊ธฐ:
      PostCSS๋Š” CSS์ฝ”๋“œ๊ฐ€ ์ž‘์„ฑ๋œ ํ›„์— ์ถ”๊ฐ€์ ์ธ ๋ณ€ํ™˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋„๊ตฌ๋กœ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
      ์˜ˆ๋ฅผ ๋“ค์–ด, ์ œ๊ฐ€ ์ง€๊ธˆ ์ž‘์„ฑํ•˜๋Š” Autoprefixer ๊ฐ™์€ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•ด์„œ ์ž๋™์œผ๋กœ ๋ธŒ๋ผ์šฐ์ € ํ”„๋ฆฌํ”ฝ์Šค๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ์š”!
  • 200๊ฐœ ์ด์ƒ์˜ ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ ์ œ๊ณต (์ƒํƒœ๊ณ„๊ฐ€ ํฝ๋‹ˆ๋‹ค!)
  • ๋ชจ๋“ˆํ™”๋œ ๊ตฌ์กฐ๋กœ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋งŒ ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ์„ ํƒ์  ์ถ”๊ฐ€ ๊ฐ€๋Šฅ

Autoprefixer

  • PostCSS์˜ ๋Œ€ํ‘œ์ ์ธ ํ”Œ๋Ÿฌ๊ทธ์ธ
  • ๋ธŒ๋ผ์šฐ์ € ํ”„๋ฆฌํ”ฝ์Šค๋ฅผ ์ž๋™์œผ๋กœ ์ถ”๊ฐ€ํ•ด์ฃผ๋Š” ๋„๊ตฌ
  • Browserslist ์„ค์ •์„ ํ†ตํ•ด ์ง€์› ๋ธŒ๋ผ์šฐ์ € ๋ฒ”์œ„ ์ง€์ • ๊ฐ€๋Šฅ

 

Create React App๊ณผ Vite์˜ ๊ธฐ๋ณธ ์ง€์›

ํ•ด๋‹น ๋ถ€๋ถ„์€ Webpack์„ ์ง์ ‘ ์„ค์ •ํ•˜์ง€ ์•Š์„ ๋• ์–ด๋–ป๊ฒŒ ๋˜๋Š” ๊ฑด์ง€, ๊ธฐ๋ณธ ์„ค์ •์ด ๋˜์–ด ์žˆ๋Š”์ง€ ๋“ฑ์ด ๊ถ๊ธˆํ•ด ์ฐพ์•„๋ณด๊ฒŒ ๋์Šต๋‹ˆ๋‹ค.

Create React App (CRA)

  • PostCSS์™€ Autoprefixer๊ฐ€ ๊ธฐ๋ณธ์œผ๋กœ ์„ค์ •๋˜์–ด ์žˆ์Œ
  • ๋ณ„๋„ ์„ค์ • ์—†์ด ๋ฐ”๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  • browserslist ์„ค์ •๋„ ๊ธฐ๋ณธ ์ œ๊ณต

CRA์˜ package.json์„ ๋ณด์‹œ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

"browserslist": {
  "production": [
    ">0.2%",
    "not dead",
    "not op_mini all"
  ],
  "development": [
    "last 1 chrome version",
    "last 1 firefox version",
    "last 1 safari version"
  ]
}


Vite

  • PostCSS๋Š” ๊ธฐ๋ณธ ์ง€์›
  • Autoprefixer๋Š” ๋ณ„๋„ ์„ค์น˜ ํ•„์š”
yarn add -D autoprefixer
// vite.config.js
import autoprefixer from 'autoprefixer'

export default {
  css: {
    postcss: {
      plugins: [
        autoprefixer()
      ]
    }
  }
}

 

ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์— Custom Webpack ์„ค์ •ํ•˜๊ธฐ

์ปค์Šคํ…€ Webpack ์„ค์ •์—์„œ๋Š” ์ˆ˜๋™์œผ๋กœ PostCSS์™€ Autoprefixer๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํ•„์š”ํ•œ ํŒจํ‚ค์ง€ ์„ค์น˜

yarn add -D postcss postcss-loader autoprefixer


์›นํŒฉ ์„ค์ • ์˜ˆ์‹œ

module.exports = {
  module: {
    rules: [
      {
        test: /\.module\.scss$/,
        use: [
          "style-loader",
          {
            loader: "css-loader",
            options: {
              modules: {
                localIdentName: "[name]__[local]--[hash:base64:5]",
              },
              importLoaders: 2,
            },
          },
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [
                  ["autoprefixer"]
                ],
              },
            },
          },
          "sass-loader",
        ],
      },
      {
        test: /\.(scss|css)$/,
        exclude: /\.module\.scss$/,
        use: [
          "style-loader",
          {
            loader: "css-loader",
            options: {
              importLoaders: 2,
            },
          },
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [
                  ["autoprefixer"]
                ],
              },
            },
          },
          "sass-loader",
        ],
      },
    ],
  },
  // ... ๊ธฐํƒ€ ์›นํŒฉ ์„ค์ •
};

 

์ถ”๊ฐ€์ ์œผ๋กœ ์ €๋Š” ์„ค์ •ํ•˜์ง€ ์•Š์•˜์ง€๋งŒ ๋‹ค๋ฅธ ๋ธ”๋กœ๊ทธ ๊ธ€์„ ๋ณด์‹œ๋ฉด ๊ฐ„ํ˜น postcss-scss์— ๋Œ€ํ•œ ์ถ”๊ฐ€๊ฐ€ ๋ณด์ด์…จ์„ ํ…๋ฐ, ์ด๊ฑด ๋ฌด์Šจ ์—ญํ• ์ผ๊นŒ์š”?!

postcss-scss๋ž€?

  • ์ผ๋ฐ˜์ ์œผ๋กœ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค
  • sass-loader๊ฐ€ SCSS๋ฅผ CSS๋กœ ๋ณ€ํ™˜ํ•œ ํ›„ postcss-loader๊ฐ€ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ
  • postcss-scss๋Š” SCSS ๊ตฌ๋ฌธ์„ ์ง์ ‘ PostCSS ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์„ ๋•Œ๋งŒ ํ•„์š”

 

์‹ค์ˆ˜ํ–ˆ๋˜ ๋ถ€๋ถ„๊ณผ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

package.json์— ์ž‘์„ฑ๋ผ์•ผ ํ•˜๋Š” json ๋ฌธ๋ฒ•์„. browserslistrc ํŒŒ์ผ์— ์ ์šฉํ•ด ๋ฒ„๋ ธ์–ด์š”. ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์ฝ๋‹ค ์ˆœ๊ฐ„์ ์œผ๋กœ ์ฐฉ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. ๋„ˆ๋ฌด ๊ฐ„๋‹จํ•˜์ง€๋งŒ ์ œ ๊ธฐ์ค€์—์„œ ์น˜๋ช…์ ์ธ ์‹ค์ˆ˜๋ž€ ์ƒ๊ฐ์ด ๋“ค์–ด ๊ธฐ๋กํ•ด๋‘๋ ค ํ•ฉ๋‹ˆ๋‹ค!

Browserslist ์„ค์ • ์˜ค๋ฅ˜

Error [BrowserslistError]: Unknown browser query `{`. Maybe you are using old Browserslist or made typo in query.

 

 

.browserslistrc ํŒŒ์ผ ์‚ฌ์šฉ (๊ถŒ์žฅ)

์ €๋Š” ์ตœ์ข…์ ์œผ๋กœ ์•„๋ž˜์˜ ์ฝ”๋“œ๋กœ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค!

# ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ
[production]
>0.2% # ์ „ ์„ธ๊ณ„ ์‚ฌ์šฉ๋ฅ  0.2% ์ด์ƒ์ธ ๋ธŒ๋ผ์šฐ์ €
not dead # ๊ณต์‹ ์ง€์›์ด ์ค‘๋‹จ๋˜์ง€ ์•Š์€ ๋ธŒ๋ผ์šฐ์ €
not op_mini all # Opera Mini ๋ธŒ๋ผ์šฐ์ € ์ œ์™ธ

# ๊ฐœ๋ฐœ ํ™˜๊ฒฝ
[development]
last 1 chrome version # ์ตœ์‹  ํฌ๋กฌ ๋ฒ„์ „
last 1 firefox version # ์ตœ์‹  ํŒŒ์ด์–ดํญ์Šค ๋ฒ„์ „
last 1 safari version # ์ตœ์‹  ์‚ฌํŒŒ๋ฆฌ ๋ฒ„์ „


ํ•ด๊ฒฐ๋ฐฉ๋ฒ• 2: package.json์— ์„ค์ •

{
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}


Browserslist ์„ค์ • ๊ฐ€์ด๋“œ

์ฃผ์š” ์ฟผ๋ฆฌ ์„ค๋ช…

  • >0.2%: ์ „ ์„ธ๊ณ„ ์‚ฌ์šฉ๋ฅ  0.2% ์ด์ƒ์ธ ๋ธŒ๋ผ์šฐ์ €
  • not dead: ๊ณต์‹ ์ง€์›์ด ์ค‘๋‹จ๋˜์ง€ ์•Š์€ ๋ธŒ๋ผ์šฐ์ €
  • not op_mini all: Opera Mini ๋ธŒ๋ผ์šฐ์ € ์ œ์™ธ
  • last 1 chrome version: ์ตœ์‹  ํฌ๋กฌ ๋ฒ„์ „
  • last 2 versions: ๊ฐ ๋ธŒ๋ผ์šฐ์ €์˜ ์ตœ์‹  2๊ฐœ ๋ฒ„์ „
  • > 1%: ์ „ ์„ธ๊ณ„ ์ ์œ ์œจ 1% ์ด์ƒ
  • IE 11: IE 11 ์ง€์›

์„ค์ • ํ…Œ์ŠคํŠธ

  • browserslist.dev์—์„œ ์„ค์ •์„ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์Œ
  • ์–ด๋–ค ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํฌํ•จ๋˜๋Š”์ง€ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ™•์ธ ๊ฐ€๋Šฅ

 

์‹ค์ œ ๋™์ž‘ ์˜ˆ์‹œ

๋ณ€ํ™˜ ์ „ CSS

.example {
  display: flex;
  user-select: none;
}

๋ณ€ํ™˜ ํ›„ CSS

.example {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
}

 

์ฃผ์˜์‚ฌํ•ญ๊ณผ ํŒ!

  • ๋กœ๋” ์ˆœ์„œ: PostCSS ๋กœ๋”๋Š” Sass ๋กœ๋” ์ดํ›„, CSS ๋กœ๋” ์ด์ „์— ์œ„์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.  
    1. sass-loader (SCSS -> CSS ๋ณ€ํ™˜)
    2. postcss-loader (์ž๋™ ํ”„๋ฆฌํ”ฝ์Šค ์ถ”๊ฐ€)
    3. css-loader (CSS -> JS ๋ณ€ํ™˜)
    4. style-loader (JS -> style ํƒœ๊ทธ ์‚ฝ์ž…)
  • ์„ฑ๋Šฅ ์ตœ์ ํ™”: development ํ™˜๊ฒฝ์—์„œ๋Š” source map์„ ํ™œ์„ฑํ™”ํ•˜๊ณ , production์—์„œ๋Š” ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
  • ๋ธŒ๋ผ์šฐ์ € ์ง€์› ๋ฒ”์œ„: browserslist ์„ค์ •์„ ํ†ตํ•ด ์ง€์›ํ•  ๋ธŒ๋ผ์šฐ์ € ๋ฒ”์œ„๋ฅผ ์ ์ ˆํžˆ ์กฐ์ ˆํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

์ฃผ์˜์‚ฌํ•ญ๊ณผ ํŒ์—์„œ์˜ Development ํ™˜๊ฒฝ์—์„œ source map ํ™œ์„ฑํ™”ํ•˜๋Š” ์ด์œ  & Production ํ™˜๊ฒฝ์—์„œ ๋น„ํ™œ์„ฑํ™” ํ•˜๋Š” ์ด์œ ์— ๋Œ€ํ•ด์„œ๋งŒ ์ข€ ๋” ์ž์„ธํžˆ ์•Œ์•„๋ณผ๊ฒŒ์š”!

 

Development ํ™˜๊ฒฝ์—์„œ source map ํ™œ์„ฑํ™”ํ•˜๋Š” ์ด์œ :

  1. ๋””๋ฒ„๊น… ์šฉ์ด์„ฑ
    • ๊ฐœ๋ฐœ ์ค‘์—๋Š” ์›๋ณธ ์†Œ์Šค ์ฝ”๋“œ์™€ ๋ณ€ํ™˜๋œ ์ฝ”๋“œ๋ฅผ ๋งคํ•‘ํ•˜์—ฌ ์‰ฝ๊ฒŒ ๋””๋ฒ„๊น…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
    • ๋ธŒ๋ผ์šฐ์ €์˜ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ์—์„œ ์‹ค์ œ ์ž‘์„ฑํ•œ CSS ํŒŒ์ผ์˜ ์œ„์น˜์™€ ๋ผ์ธ์„ ์ •ํ™•ํžˆ ํ™•์ธ ๊ฐ€๋Šฅ
    • PostCSS๋กœ ๋ณ€ํ™˜๋œ ์ฝ”๋“œ๊ฐ€ ์•„๋‹Œ ์›๋ณธ ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ํ™•์ธํ•˜๋ฉฐ ์ˆ˜์ • ๊ฐ€๋Šฅ
  2. ๊ฐœ๋ฐœ ํšจ์œจ์„ฑ
    • ์ฝ”๋“œ ์ˆ˜์ • ์‹œ ์ฆ‰๊ฐ์ ์ธ ํ”ผ๋“œ๋ฐฑ ํ™•์ธ ๊ฐ€๋Šฅ
    • CSS ๋ฌธ์ œ ๋ฐœ์ƒ ์‹œ ์ •ํ™•ํ•œ ์œ„์น˜ ์ถ”์ ์ด ๊ฐ€๋Šฅํ•˜์—ฌ ์ˆ˜์ • ์‹œ๊ฐ„ ๋‹จ์ถ•
    • ๋ณต์žกํ•œ ์Šคํƒ€์ผ ๊ตฌ์กฐ์—์„œ๋„ ์›๋ณธ ์ฝ”๋“œ ์œ„์น˜๋ฅผ ์‰ฝ๊ฒŒ ํŒŒ์•…!

Production ํ™˜๊ฒฝ์—์„œ source map ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ์ด์œ :

  1. ํŒŒ์ผ ํฌ๊ธฐ ์ตœ์ ํ™”
    • source map ํŒŒ์ผ์€ ์›๋ณธ ์ฝ”๋“œ์™€ ๋ณ€ํ™˜๋œ ์ฝ”๋“œ์˜ ๋งคํ•‘ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๋ฏ€๋กœ ์ƒ๋‹นํ•œ ํฌ๊ธฐ๋ฅผ ์ฐจ์ง€
    • ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ถˆํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ์ „์†ก์„ ์ค„์—ฌ ๋กœ๋”ฉ ์†๋„ ํ–ฅ์ƒ
    • ์ผ๋ฐ˜์ ์œผ๋กœ source map ํŒŒ์ผ์€ ์›๋ณธ ํŒŒ์ผ ํฌ๊ธฐ์˜ ์ ˆ๋ฐ˜ ์ด์ƒ์„ ์ฐจ์ง€ํ•  ์ˆ˜ ์žˆ์Œ
  2. ๋ณด์•ˆ ๊ฐ•ํ™”
    • source map์ด ๋…ธ์ถœ๋˜๋ฉด ์›๋ณธ ์ฝ”๋“œ ๊ตฌ์กฐ๊ฐ€ ๋“œ๋Ÿฌ๋‚  ์ˆ˜ ์žˆ์Œ
    • ์•…์˜์ ๋ฅผ ๊ฐ€์ง„ ์‚ฌ์šฉ์ž๊ฐ€ ์ฝ”๋“œ ๊ตฌ์กฐ๋ฅผ ๋ถ„์„ํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€
    • ๊ธฐ์—…์˜ proprietary ์ฝ”๋“œ ๋ณดํ˜ธ!!
  3. ์„ฑ๋Šฅ ์ตœ์ ํ™”
    • ๋ธŒ๋ผ์šฐ์ €๊ฐ€ source map์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ถ”๊ฐ€์ ์ธ ์ž‘์—… ์ œ๊ฑฐ
    • ์ดˆ๊ธฐ ํŽ˜์ด์ง€ ๋กœ๋”ฉ ์‹œ๊ฐ„ ๋‹จ์ถ•
    • ์„œ๋ฒ„ ๋Œ€์—ญํญ ์‚ฌ์šฉ๋Ÿ‰ ๊ฐ์†Œ

์‹ค์ œ ์„ค์ • ์˜ˆ์‹œ! (ํ”„๋กœ์ ํŠธ ์ฝ”๋“œ๋ณด๋‹ค ๊ฐ„๋žตํ™”)

// webpack.config.js
module.exports = {
  mode: process.env.NODE_ENV,
  module: {
    rules: [{
      test: /\.css$/,
      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            sourceMap: process.env.NODE_ENV === 'development'
          }
        },
        {
          loader: 'postcss-loader',
          options: {
            sourceMap: process.env.NODE_ENV === 'development'
          }
        }
      ]
    }]
  }
};

 

 

๊ฒฐ๋ก 

PostCSS์™€ Autoprefixer๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํฌ๋กœ์Šค๋ธŒ๋ผ์šฐ์ง•์„ ์œ„ํ•œ ์ˆ˜๋™ ์ž‘์—…์„ ์ž๋™ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

CRA๋‚˜ Create Vite๊ฐ™์€ ๊ฒฝ์šฐ ์ด๋ฏธ ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ ๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณตํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ์ปค์Šคํ…€ ์›นํŒฉ ์„ค์ •์—์„œ๋„ ๊ฐ„๋‹จํ•œ ์„ค์ •๋งŒ์œผ๋กœ ๋™์ผํ•œ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

ํŠนํžˆ Browserslist ์„ค์ •์„ ํ†ตํ•ด ํ”„๋กœ์ ํŠธ์˜ ๋ธŒ๋ผ์šฐ์ € ์ง€์› ๋ฒ”์œ„๋ฅผ ๋ช…ํ™•ํžˆ ํ•˜๊ณ , ํ•„์š”ํ•œ ํ”„๋ฆฌํ”ฝ์Šค๋งŒ ์ถ”๊ฐ€ํ•จ์œผ๋กœ์จ ์ตœ์ ํ™”๋œ CSS๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒ ์ฃ ?!

 

.browserslistrc ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋ฉด ์„ค์ • ๊ด€๋ฆฌ๊ฐ€ ๋”์šฑ ์šฉ์ดํ•ด์ง€๋ฉฐ, ๋‹ค๋ฅธ ๋„๊ตฌ๋“ค๊ณผ๋„ ์„ค์ •์„ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์—ฌ๊ธฐ์„œ "๋‹ค๋ฅธ ๋„๊ตฌ๋“ค"์€ ์ฃผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ CSS ๋˜๋Š” JavaScript ๋„๊ตฌ๋“ค์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค!

  1. Autoprefixer: CSS์— ํ•„์š”ํ•œ ๋ธŒ๋ผ์šฐ์ € ํ”„๋ฆฌํ”ฝ์Šค๋ฅผ ์ž๋™์œผ๋กœ ์ถ”๊ฐ€ํ•ด์ฃผ๋Š” ๋„๊ตฌ๋กœ, Browserslist ์„ค์ •์„ ํ†ตํ•ด ์–ด๋–ค ํ”„๋ฆฌํ”ฝ์Šค๋ฅผ ์ถ”๊ฐ€ํ• ์ง€ ๊ฒฐ์ • (์ง€๊ธˆ๊นŒ์ง€ ์„ค๋ช…๋“œ๋ฆฐ ๋‚ด์šฉ์ด์ฃ ?!)
  2. Babel: ์ตœ์‹  JavaScript ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜• ๋ธŒ๋ผ์šฐ์ €์—์„œ๋„ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ณ€ํ™˜ํ•ด์ฃผ๋Š” ๋„๊ตฌ๋กœ, Browserslist ์„ค์ •์„ ํ†ตํ•ด ์ง€์›ํ•  ๋ธŒ๋ผ์šฐ์ € ์ •์˜ ๊ฐ€๋Šฅ
  3. ESLint: JavaScript ์ฝ”๋“œ์˜ ํ’ˆ์งˆ์„ ๊ด€๋ฆฌํ•˜๋Š” ๋„๊ตฌ๋กœ, Browserslist์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•ด ํŠน์ • ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ์— ๋งž๋Š” ์ฝ”๋“œ ์Šคํƒ€์ผ ์ ์šฉ ๊ฐ€๋Šฅ
  4. Stylelint: CSS ์Šคํƒ€์ผ์„ ๊ฒ€์‚ฌํ•˜๋Š” ๋„๊ตฌ๋กœ, Browserslist ์„ค์ •์„ ์ฐธ๊ณ ํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ € ํ˜ธํ™˜์„ฑ ๊ด€๋ จ ๊ทœ์น™ ์ ์šฉ ๊ฐ€๋Šฅ

์ฆ‰, .browserslistrc ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋Ÿฌํ•œ ๋‹ค์–‘ํ•œ ๋„๊ตฌ๋“ค์ด ๋™์ผํ•œ ๋ธŒ๋ผ์šฐ์ € ์ง€์› ๋ฒ”์œ„๋ฅผ ๊ณต์œ ํ•˜๊ฒŒ ๋˜์–ด, ๊ฐœ๋ฐœ ๋ฐ ์œ ์ง€๋ณด์ˆ˜ ๊ณผ์ •์—์„œ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

 

 

๐Ÿ“ƒ ์ฐธ๊ณ  ๋ฌธํ—Œ  
PostCSS ๊ณต์‹ ๋ฌธ์„œ
Autoprefixer GitHub
Browserslist
Create React App PostCSS ์„ค์ •
Vite CSS ์„ค์ •
Webpack 5 postcss-loader 
Browserslist ๊ด€๋ จ ๊ฐœ์ธ ๋ธ”๋กœ๊ทธ

 

+ Recent posts