Tailwind์ ํ์ํ ๊ฒ๋ค ์ค์น
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -ppostcss์ autoprefixer๋ ์ ํ์ํ ๊น?
tailwind๋ง ์ค์นํ๋ฉด ๋ ์ค ์์์ผ๋ tailwind๊ฐ ์๋ํ๊ธฐ ์ํด์๋ postcss์ autoprefixer๊ฐ ํ์ํ๋ค. ์ด ๋์ ์ญํ ์ ๋ํด ์์๋ณด์.
postcss

postcss์ ๊ณต์๋ฌธ์์๋ PostCSS is a tool for transforming styles with JS plugins. ๋ผ๊ณ ์ ํ์๋ค. js๋ฅผ ์ด์ฉํ์ฌ css๋ฅผ ๋ณํ์ํจ๋ค๋ ์ด์ผ๊ธฐ์ด๋ค.
postcss๋ ๋ค๋ฅธ scss, Stylus๋ค๊ณผ๋ ๋ค๋ฅด๊ฒ ํ์ฒ๋ฆฌ๊ธฐ์ ์ฑ๊ฒฉ์ ์ง๋๋ค.
CSS ์ ์ฒ๋ฆฌ๊ธฐ ํ๋ฉด์ ๋ณด์ด๊ธฐ ์ ์ CSS๋ฅผ ๋ณ๊ฒฝํ๊ณ , ์คํ์ผ์ ์ ์ฉ CSS ์์ฑ โ ์คํ ์ ์ ๊ธฐ๋ณธ CSS๋ก ์ปดํ์ผ โ ๋ ๋๋ง Stylus, Sass, Less ๋ฑ
CSS ํ์ฒ๋ฆฌ๊ธฐ ํ๋ฉด์ ๋ณด์ฌ์ง ๋ค์ CSS ์คํ์ผ์ ์ ์ฉ CSS ์์ฑ โ ๋ ๋๋ง โ ์ธ๋ถ ๋ชจ๋์ ์ฌ์ฉํ์ฌ ์คํ์ผ ๋ณ๊ฒฝ PostCSS ๋ฑ
postCSS๋ ์์ ๊ฐ์ด Parser -> plugins -> Stringifier ์ ๊ณผ์ ์ ๊ฑฐ์น๋ค.
๊ฐ์ฅ ๋จผ์ Parser์์๋ ๋ฌธ์์ด์ tokenizingํ ๋ค์ AST๋ก ๋ณํํ์ฌ ๋จ์ผ ํ์ผ์ ์์ฑํ๋ ๊ณผ์ ์ ๊ฑฐ์น๋ค. ๊ธฐ์กด์ CSS์ ๋ํด์ ํ ํฐํ ํ๋ ๊ณผ์ ์ ์ดํด๋ณด์.
.className { color: #FFF; }์์ ๊ฐ์ CSS๋ฅผ ๋ง๋ค๊ธฐ ์ํด์๋ ์ฐ์ ์ด๋ฌํ CSS์ ๋ํด tokenizingํ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด
[
["word", ".className", 1, 1, 1, 10]
["space", " "]
["{", "{", 1, 12]
["space", " "]
["word", "color", 1, 14, 1, 18]
[":", ":", 1, 19]
["space", " "]
["word", "#FFF" , 1, 21, 1, 23]
[";", ";", 1, 24]
["space", " "]
["}", "}", 1, 26]
]์ด๋ฐ ์์ผ๋ก ๊ฐ๊ฐ ๋จ์ผ ํ ํฐ์ ๋ํด์ ๋ฐฐ์ด๋ก ๊ด๋ฆฌํ๋ฉฐ, ํ ํฐ ํ์ , ๋จ์ด, ์์น ์ ๋ณด ๋ฑ์ ๊ด๋ฆฌํ๋ค.
const token = [
// ํ ํฐ ํ์
'word',
// ๋งค์นญ๋ ๋จ์ด
'.className',
// ์ ๋ ์ซ์ -> ํ ํฐ์ ์์ ์์น(optional)
// `space`์ ๊ฐ์ ํ ํฐ์ ์์น ์ ๋ณด ์์
// ์ฌ๊ธฐ์ ์ฒซ ๋ฒ์งธ ์ซ์๋ ์ค ๋ฒํธ์ด๊ณ , ๋ ๋ฒ์งธ ์ซ์๋ ํด๋น ์ค์ ์ด ๋ฒํธ
1, 1,
// ์ด ํ ํฐ์ฒ๋ผ ์ฌ๋ฌ ๋ฌธ์์ ํ ํฐ์ ๋ํด ๋ ์์น(optional)
// ์ซ์๋ ์์์ ์ค๋ช
ํ ๊ท์น๊ณผ ๊ฐ์
1, 10
]
์ด๋ ๊ฒ ํ ํฐํ๋ ๊ฐ๊ฐ์ CSS์ ๋ํด์ postcss์ lib/parse.js์ lib/parser.js์ ๋ชจ๋์ ํตํด ํ์ฑํ๋ค. ์ด ํ์๋ฅผ ํตํด์ CSS์ ๋ํ AST๋ฅผ ์์ฑํ๋ค.
'use strict'
let Container = require('./container')
let Input = require('./input')
let Parser = require('./parser')
function parse(css, opts) {
let input = new Input(css, opts)
let parser = new Parser(input)
try {
parser.parse()
} catch (e) {
if (process.env.NODE_ENV !== 'production') {
if (e.name === 'CssSyntaxError' && opts && opts.from) {
if (/\.scss$/i.test(opts.from)) {
e.message +=
'\nYou tried to parse SCSS with ' +
'the standard CSS parser; ' +
'try again with the postcss-scss parser'
} else if (/\.sass/i.test(opts.from)) {
e.message +=
'\nYou tried to parse Sass with ' +
'the standard CSS parser; ' +
'try again with the postcss-sass parser'
} else if (/\.less$/i.test(opts.from)) {
e.message +=
'\nYou tried to parse Less with ' +
'the standard CSS parser; ' +
'try again with the postcss-less parser'
}
}
}
throw e
}
return parser.root
}
module.exports = parse
parse.default = parse
Container.registerParse(parse)ํด๋น parse์์๋ parser ์์ฑ์๋ฅผ ํตํด ๋ค์๊ธ ํ ํฐํ๋ ๊ฒ๋ค์ AST๋ก ๋ง๋๋ ๊ณผ์ ์ ๊ฑฐ์น๊ณ , ์ด์ ๋ํ root๋ฅผ ๋ฐํํ๋ค.
๊ทธ๋ ๊ฒ ๋ง๋ค์ด์ง ast์ ๋ํด์๋ processor(lib/processor.js)๋ฅผ ํตํด์ ํ๋ฌ๊ทธ์ธ๋ค์ ์ด๊ธฐํํ๊ณ ๋ฌธ๋ฒ์ ์ผ๋ก ๋ณํํ๋ ๊ณผ์ ์ ๊ฑฐ์น๋ค.
'use strict'
let Document = require('./document')
let LazyResult = require('./lazy-result')
let NoWorkResult = require('./no-work-result')
let Root = require('./root')
class Processor {
constructor(plugins = []) {
this.version = '8.4.47'
this.plugins = this.normalize(plugins)
}
normalize(plugins) {
let normalized = []
for (let i of plugins) {
if (i.postcss === true) {
i = i()
} else if (i.postcss) {
i = i.postcss
}
if (typeof i === 'object' && Array.isArray(i.plugins)) {
normalized = normalized.concat(i.plugins)
} else if (typeof i === 'object' && i.postcssPlugin) {
normalized.push(i)
} else if (typeof i === 'function') {
normalized.push(i)
} else if (typeof i === 'object' && (i.parse || i.stringify)) {
if (process.env.NODE_ENV !== 'production') {
throw new Error(
'PostCSS syntaxes cannot be used as plugins. Instead, please use ' +
'one of the syntax/parser/stringifier options as outlined ' +
'in your PostCSS runner documentation.'
)
}
} else {
throw new Error(i + ' is not a PostCSS plugin')
}
}
return normalized
}
process(css, opts = {}) {
if (
!this.plugins.length &&
!opts.parser &&
!opts.stringifier &&
!opts.syntax
) {
return new NoWorkResult(this, css, opts)
} else {
return new LazyResult(this, css, opts)
}
}
use(plugin) {
this.plugins = this.plugins.concat(this.normalize([plugin]))
return this
}
}
module.exports = Processor
Processor.default = Processor
Root.registerProcessor(Processor)
Document.registerProcessor(Processor)์ด๋ ๊ฒ ๋ฌธ๋ฒ์ ์ผ๋ก ๋ณํํ๋ ๊ณผ์ ์ ๋ง์น๋ฉด ์ด๋ฅผ ๋ค์ ์์ CSS ๊ตฌ๋ฌธ์ผ๋ก ๋ฐ๊ฟ์ค์ผ ํ๋๋ฐ, Stringifier๊ฐ AST๋ฅผ ์ํํ๋ฉด์ ๊ฐ ๋
ธ๋์ ๋ํด CSS ๋ฌธ์์ด์ ์์ฑํด๋ธ๋ค.
autoprefixer
ํ ํ๋ฆฟ ๊ฒฝ๋ก ์ง์
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
index.css์ tailwind ์ค์ ์ถ๊ฐ
@tailwind base;
@tailwind components;
@tailwind utilities;