์๋ฐ์คํฌ๋ฆฝํธ ๋ชจ๋ ๋ด ์์ (์ด๋ฏธ์ง, ํฐํธ, ์คํ์ผ์ํธ) ๊ด๋ฆฌ ์ข ํฉ ๊ฐ์ด๋. ๋ฒ๋ค๋ฌ, ๋ก๋, ์ฑ๋ฅ ๋ฐ ํ์ฅ์ฑ์ ์ํ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ค๋ฃน๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ๋ชจ๋ ๋ฆฌ์์ค ๊ด๋ฆฌ: ์์ ํธ๋ค๋ง
์๋ฐ์คํฌ๋ฆฝํธ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ณต์กํด์ง์ ๋ฐ๋ผ ์ด๋ฏธ์ง, ํฐํธ, ์คํ์ผ์ํธ ๋ฑ๊ณผ ๊ฐ์ ๋ฆฌ์์ค๋ฅผ ๊ด๋ฆฌํ๋ ๊ฒ์ด ์ ์ ๋ ์ค์ํด์ง๊ณ ์์ต๋๋ค. ๊ฐ๋ ฅํ ๋ฒ๋ค๋ฌ ๋ฐ ๋ก๋์ ๊ฒฐํฉ๋ ์ต์ ์๋ฐ์คํฌ๋ฆฝํธ ๋ชจ๋ ์์คํ ์ ์ด๋ฌํ ์์ ์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํ ์ ๊ตํ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค. ์ด ๊ฐ์ด๋์์๋ ์ ์ธ๊ณ ์ฌ์ฉ์๋ฅผ ๋์์ผ๋ก ์ฑ๋ฅ๊ณผ ์ ์ง๋ณด์์ฑ์ ํฅ์์ํค๊ธฐ ์ํ ์์ ํธ๋ค๋ง ์ ๋ต์ ์ด์ ์ ๋ง์ถฐ ์๋ฐ์คํฌ๋ฆฝํธ ๋ชจ๋ ๋ฆฌ์์ค ๊ด๋ฆฌ์ ๋ค์ํ ์ ๊ทผ ๋ฐฉ์์ ์ดํด๋ด ๋๋ค.
์์ ๊ด๋ฆฌ์ ํ์์ฑ ์ดํดํ๊ธฐ
์น ๊ฐ๋ฐ ์ด์ฐฝ๊ธฐ์๋ ์ผ๋ฐ์ ์ผ๋ก <script>
, <link>
, <img>
ํ๊ทธ๋ฅผ ํตํด HTML ํ์ผ์ ์์
์ ํฌํจํ์ต๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ํ๋ก์ ํธ ๊ท๋ชจ๊ฐ ์ปค์ง๋ฉด์ ๋ค๋ฃจ๊ธฐ ํ๋ค์ด์ง๋ฉฐ ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๋ก ์ด์ด์ก์ต๋๋ค:
- ์ ์ญ ๋ค์์คํ์ด์ค ์ค์ผ: ์คํฌ๋ฆฝํธ๊ฐ ์๋ก์ ๋ณ์๋ฅผ ์๋์น ์๊ฒ ๋ฎ์ด์ฐ๋ฉด์ ์์ธกํ ์ ์๋ ๋์์ ์ ๋ฐํ ์ ์์์ต๋๋ค.
- ์์กด์ฑ ๊ด๋ฆฌ ๋ฌธ์ : ์ฌ๋ฐ๋ฅธ ์คํฌ๋ฆฝํธ ์คํ ์์๋ฅผ ๊ฒฐ์ ํ๊ธฐ ์ด๋ ค์ ์ต๋๋ค.
- ์ต์ ํ ๋ถ์กฑ: ์์ ์ด ๋นํจ์จ์ ์ผ๋ก ๋ก๋๋์ด ํ์ด์ง ๋ก๋ ์๊ฐ์ ์ํฅ์ ๋ฏธ์ณค์ต๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ๋ชจ๋ ์์คํ (์: ES ๋ชจ๋, CommonJS, AMD)๊ณผ ๋ชจ๋ ๋ฒ๋ค๋ฌ(์: Webpack, Parcel, Vite)๋ ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค:
- ์บก์ํ: ๋ชจ๋์ ๊ฒฉ๋ฆฌ๋ ์ค์ฝํ๋ฅผ ์์ฑํ์ฌ ๋ค์์คํ์ด์ค ์ถฉ๋์ ๋ฐฉ์งํฉ๋๋ค.
- ์์กด์ฑ ํด๊ฒฐ: ๋ฒ๋ค๋ฌ๋ ๋ชจ๋ ์์กด์ฑ์ ์๋์ผ๋ก ํด๊ฒฐํ์ฌ ์ฌ๋ฐ๋ฅธ ์คํ ์์๋ฅผ ๋ณด์ฅํฉ๋๋ค.
- ์์ ๋ณํ ๋ฐ ์ต์ ํ: ๋ฒ๋ค๋ฌ๋ ์์ถ(minification), ์์ถ(compression) ๋ฐ ๊ธฐํ ๊ธฐ์ ์ ํตํด ์์ ์ ์ต์ ํํ ์ ์์ต๋๋ค.
๋ชจ๋ ๋ฒ๋ค๋ฌ: ์์ ๊ด๋ฆฌ์ ํต์ฌ
๋ชจ๋ ๋ฒ๋ค๋ฌ๋ ์ต์ ์๋ฐ์คํฌ๋ฆฝํธ ํ๋ก์ ํธ์์ ์์ ์ ๊ด๋ฆฌํ๊ธฐ ์ํ ํ์ ๋๊ตฌ์ ๋๋ค. ์ฝ๋๋ฅผ ๋ถ์ํ๊ณ ์์กด์ฑ์ ์๋ณํ์ฌ ํ์ํ ๋ชจ๋ ํ์ผ(์๋ฐ์คํฌ๋ฆฝํธ, CSS, ์ด๋ฏธ์ง, ํฐํธ ๋ฑ ํฌํจ)์ ์น ์๋ฒ์ ๋ฐฐํฌํ ์ ์๋ ์ต์ ํ๋ ๋ฒ๋ค๋ก ํจํค์งํฉ๋๋ค.
์ฃผ์ ๋ชจ๋ ๋ฒ๋ค๋ฌ
- Webpack: ๊ตฌ์ฑ ๊ฐ๋ฅ์ฑ์ด ๋๊ณ ๋ค์ฌ๋ค๋ฅํ ๋ฒ๋ค๋ฌ์ ๋๋ค. ๊ด๋ฒ์ํ ํ๋ฌ๊ทธ์ธ๊ณผ ๋ก๋ ์ํ๊ณ ๋๋ถ์ ๊ฐ์ฅ ์ธ๊ธฐ ์๋ ์ ํ ์ค ํ๋์ด๋ฉฐ, ์ด๋ฅผ ํตํด ๋ค์ํ ์์ ๋ณํ ๋ฐ ์ต์ ํ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
- Parcel: ๋น๋ ํ๋ก์ธ์ค๋ฅผ ๋จ์ํํ๋ ์ ๋ก-๊ตฌ์ฑ(zero-configuration) ๋ฒ๋ค๋ฌ์ ๋๋ค. ๊ด๋ฒ์ํ ๊ตฌ์ฑ ์์ด๋ ๋ค์ํ ์์ ์ ํ์ ์๋์ผ๋ก ๊ฐ์งํ๊ณ ์ฒ๋ฆฌํฉ๋๋ค.
- Vite: ๋ค์ดํฐ๋ธ ES ๋ชจ๋์ ํ์ฉํ์ฌ ๋ ๋น ๋ฅธ ๊ฐ๋ฐ ๋ฐ ๋น๋ ์๊ฐ์ ์ ๊ณตํ๋ ์ฐจ์ธ๋ ํ๋ก ํธ์๋ ๋๊ตฌ์ ๋๋ค. ์์กด์ฑ์ด ๋ง์ ๋๊ท๋ชจ ํ๋ก์ ํธ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐ ํ์ํฉ๋๋ค.
์์ ํธ๋ค๋ง ๊ธฐ๋ฒ
์์ ์ ํ์ ๋ฐ๋ผ ๋ค๋ฅธ ์ฒ๋ฆฌ ์ ๋ต์ด ํ์ํฉ๋๋ค. ์ด๋ฏธ์ง, ํฐํธ, ์คํ์ผ์ํธ๋ฅผ ๊ด๋ฆฌํ๋ ์ผ๋ฐ์ ์ธ ๊ธฐ๋ฒ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์ด๋ฏธ์ง ํธ๋ค๋ง
์ด๋ฏธ์ง๋ ๋๋ถ๋ถ์ ์น ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ค์ํ ๋ถ๋ถ์ด๋ฉฐ, ๋ก๋ฉ๊ณผ ์ ๋ฌ์ ์ต์ ํํ๋ ๊ฒ์ ์ฑ๋ฅ์ ๋งค์ฐ ์ค์ํฉ๋๋ค.
์ด๋ฏธ์ง๋ฅผ ๋ชจ๋๋ก ๊ฐ์ ธ์ค๊ธฐ
์ต์ ๋ฒ๋ค๋ฌ๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋ฏธ์ง๋ฅผ ์๋ฐ์คํฌ๋ฆฝํธ ๋ชจ๋๋ก ์ง์ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. ์ด๋ ์ฌ๋ฌ ๊ฐ์ง ์ด์ ์ ์ ๊ณตํฉ๋๋ค:
- ์์กด์ฑ ์ถ์ : ๋ฒ๋ค๋ฌ๋ ์ด๋ฏธ์ง๋ฅผ ๋ฒ๋ค์ ์๋์ผ๋ก ํฌํจํ๊ณ ์ฝ๋์ ์ด๋ฏธ์ง ๊ฒฝ๋ก๋ฅผ ์ ๋ฐ์ดํธํฉ๋๋ค.
- ์ต์ ํ: ๋ก๋๋ ๋น๋ ๊ณผ์ ์์ ์ด๋ฏธ์ง๋ฅผ ์ต์ ํํ ์ ์์ต๋๋ค (์: ์์ถ, ๋ฆฌ์ฌ์ด์ง, WebP๋ก ๋ณํ).
์์ (Webpack๊ณผ ES ๋ชจ๋):
// ์ด๋ฏธ์ง ๊ฐ์ ธ์ค๊ธฐ
import myImage from './images/my-image.jpg';
// ์ปดํฌ๋ํธ์์ ์ด๋ฏธ์ง ์ฌ์ฉํ๊ธฐ
function MyComponent() {
return <img src={myImage} alt="My Image" />;
}
์ด ์์์์ myImage
๋ Webpack์ด ์ฒ๋ฆฌํ ํ ์ต์ ํ๋ ์ด๋ฏธ์ง์ URL์ ํฌํจํ๊ฒ ๋ฉ๋๋ค.
์ด๋ฏธ์ง ์ต์ ํ ์ ๋ต
์ด๋ฏธ์ง ์ต์ ํ๋ ํ์ผ ํฌ๊ธฐ๋ฅผ ์ค์ด๊ณ ํ์ด์ง ๋ก๋ ์๊ฐ์ ๊ฐ์ ํ๋ ๋ฐ ํ์์ ์ ๋๋ค. ๋ค์ ์ ๋ต์ ๊ณ ๋ คํด ๋ณด์ธ์:
- ์์ถ: ImageOptim(macOS), TinyPNG ๋๋ ์จ๋ผ์ธ ์๋น์ค๋ฅผ ์ฌ์ฉํ์ฌ ์๋นํ ํ์ง ์ ํ ์์ด ์ด๋ฏธ์ง๋ฅผ ์์ถํ์ธ์.
- ๋ฆฌ์ฌ์ด์ง: ์ด๋ฏธ์ง๋ฅผ ์๋๋ ๋์คํ๋ ์ด ํฌ๊ธฐ์ ๋ง๋ ์ ์ ํ ์น์๋ก ์กฐ์ ํ์ธ์. ๋ธ๋ผ์ฐ์ ์์ ์ถ์๋๋ ํฐ ์ด๋ฏธ์ง๋ฅผ ์ ๊ณตํ์ง ๋ง์ธ์.
- ํฌ๋งท ๋ณํ: ์ด๋ฏธ์ง๋ฅผ WebP์ ๊ฐ์ด ๋ ํจ์จ์ ์ธ ํฌ๋งท์ผ๋ก ๋ณํํ์ธ์ (๋๋ถ๋ถ์ ์ต์ ๋ธ๋ผ์ฐ์ ์์ ์ง์). WebP๋ JPEG ๋ฐ PNG์ ๋นํด ์ฐ์ํ ์์ถ๋ฅ ์ ์ ๊ณตํฉ๋๋ค.
- ์ง์ฐ ๋ก๋ฉ(Lazy Loading): ์ด๋ฏธ์ง๊ฐ ๋ทฐํฌํธ์ ๋ณด์ผ ๋๋ง ๋ก๋ํ์ธ์. ์ด๋ ์ด๊ธฐ ํ์ด์ง ๋ก๋ ์๊ฐ์ ๊ฐ์ ํ๊ณ ๋ถํ์ํ ๋์ญํญ ์๋น๋ฅผ ์ค์
๋๋ค.
<img>
ํ๊ทธ์loading="lazy"
์์ฑ์ ์ฌ์ฉํ๊ฑฐ๋ lazysizes์ ๊ฐ์ ์๋ฐ์คํฌ๋ฆฝํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ธ์. - ๋ฐ์ํ ์ด๋ฏธ์ง: ์ฌ์ฉ์์ ๊ธฐ๊ธฐ ๋ฐ ํ๋ฉด ํฌ๊ธฐ์ ๋ฐ๋ผ ๋ค๋ฅธ ํฌ๊ธฐ์ ์ด๋ฏธ์ง๋ฅผ ์ ๊ณตํ์ธ์.
<picture>
์์๋<img>
ํ๊ทธ์srcset
์์ฑ์ ์ฌ์ฉํ์ธ์.
์์ (<picture>
๋ฅผ ์ฌ์ฉํ ๋ฐ์ํ ์ด๋ฏธ์ง):
<picture>
<source media="(max-width: 600px)" srcset="small.jpg">
<source media="(max-width: 1200px)" srcset="medium.jpg">
<img src="large.jpg" alt="My Responsive Image">
</picture>
์ด ์์๋ ๋ทฐํฌํธ ๋๋น์ ๋ฐ๋ผ ๋ค๋ฅธ ํฌ๊ธฐ์ ์ด๋ฏธ์ง๋ฅผ ์ ๊ณตํฉ๋๋ค.
์ด๋ฏธ์ง ๋ก๋ (Webpack ์์)
Webpack์ ๋ค์ํ ์ ํ์ ํ์ผ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ๋ก๋๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด๋ฏธ์ง๋ฅผ ์ํ ์ผ๋ฐ์ ์ธ ๋ก๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
file-loader
: ํ์ผ์ ์ถ๋ ฅ ๋๋ ํ ๋ฆฌ๋ก ๋ด๋ณด๋ด๊ณ ๊ณต๊ฐ URL์ ๋ฐํํฉ๋๋ค.url-loader
:file-loader
์ ์ ์ฌํ์ง๋ง, ํ์ผ ํฌ๊ธฐ๊ฐ ํน์ ์๊ณ๊ฐ๋ณด๋ค ์์ ๊ฒฝ์ฐ ์ด๋ฏธ์ง๋ฅผ base64 ๋ฐ์ดํฐ URI๋ก ์ธ๋ผ์ธ ์ฒ๋ฆฌํ ์๋ ์์ต๋๋ค. ์ด๋ HTTP ์์ฒญ ์๋ฅผ ์ค์ผ ์ ์์ง๋ง, ์๋ฐ์คํฌ๋ฆฝํธ ๋ฒ๋ค์ ํฌ๊ธฐ๋ฅผ ์ฆ๊ฐ์ํฌ ์๋ ์์ต๋๋ค.image-webpack-loader
: ๋ค์ํ ๋๊ตฌ(์: imagemin, pngquant)๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฏธ์ง๋ฅผ ์ต์ ํํฉ๋๋ค.
Webpack ์ค์ ์์:
module.exports = {
// ... ๋ค๋ฅธ ์ค์
module: {
rules: [
{
test: /\.(png|jpg|jpeg|gif|svg)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192, // 8kb ๋ฏธ๋ง ํ์ผ์ ์ธ๋ผ์ธ ์ฒ๋ฆฌ
name: '[name].[hash:8].[ext]',
outputPath: 'images',
},
},
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 65,
},
optipng: {
enabled: false, // ํ์ง์ ํฌ๊ฒ ์ ํ์ํค๋ฏ๋ก ๋นํ์ฑํ
},
pngquant: {
quality: [0.65, 0.90],
speed: 4,
},
gifsicle: {
interlaced: false,
},
webp: {
quality: 75,
},
},
},
],
},
],
},
};
ํฐํธ ํธ๋ค๋ง
ํฐํธ๋ ์ฌ์ฉ์ ๊ฒฝํ์ ํฐ ์ํฅ์ ๋ฏธ์น ์ ์๋ ๋ ๋ค๋ฅธ ํ์ ์์ ์ ํ์ ๋๋ค. ์ ์ ํ ํฐํธ ํธ๋ค๋ง์๋ ์ฌ๋ฐ๋ฅธ ํฐํธ ์ ํ, ๋ก๋ฉ ์ต์ ํ, ๊ทธ๋ฆฌ๊ณ ๋ค์ํ ๋ธ๋ผ์ฐ์ ์ ๊ธฐ๊ธฐ์์ ์ผ๊ด๋ ๋ ๋๋ง ๋ณด์ฅ์ด ํฌํจ๋ฉ๋๋ค.
ํฐํธ๋ฅผ ๋ชจ๋๋ก ๊ฐ์ ธ์ค๊ธฐ
์ด๋ฏธ์ง์ ๋ง์ฐฌ๊ฐ์ง๋ก, ํฐํธ๋ ์๋ฐ์คํฌ๋ฆฝํธ ๋ชจ๋๋ก ์ง์ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
์์ (Webpack๊ณผ ES ๋ชจ๋):
// ํฐํธ ์คํ์ผ์ํธ ๊ฐ์ ธ์ค๊ธฐ
import './fonts/my-font.css';
// CSS์์ ํฐํธ ์ฌ์ฉํ๊ธฐ
body {
font-family: 'My Font', sans-serif;
}
์ด ์์์์ my-font.css
ํ์ผ์ ํด๋น ํฐํธ์ ๋ํ @font-face
์ ์ธ์ ํฌํจํ๊ฒ ๋ฉ๋๋ค.
ํฐํธ ์ต์ ํ ์ ๋ต
ํฐํธ ์ต์ ํ๋ ํ์ผ ํฌ๊ธฐ๋ฅผ ์ค์ด๊ณ ํ์ด์ง ๋ก๋ ์๊ฐ์ ๊ฐ์ ํ๋ ๋ฐ ๋งค์ฐ ์ค์ํฉ๋๋ค. ๋ค์ ์ ๋ต์ ๊ณ ๋ คํด ๋ณด์ธ์:
- ์๋ธ์ธํ (Subsetting): ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ฌ์ฉ๋๋ ๋ฌธ์๋ง ํฌํจํ์ธ์. ์ด๋ ํนํ ๋ฌธ์ ์งํฉ์ด ํฐ ํฐํธ(์: ์ค๊ตญ์ด, ์ผ๋ณธ์ด, ํ๊ตญ์ด)์ ๊ฒฝ์ฐ ํฐํธ ํ์ผ ํฌ๊ธฐ๋ฅผ ํฌ๊ฒ ์ค์ผ ์ ์์ต๋๋ค. glyphhanger์ ๊ฐ์ ๋๊ตฌ๊ฐ ์ฌ์ฉ๋์ง ์๋ ๋ฌธ์๋ฅผ ์๋ณํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
- ํฌ๋งท ๋ณํ: TTF๋ EOT์ ๊ฐ์ ์ค๋๋ ํฌ๋งท๋ณด๋ค ๋ ๋์ ์์ถ๋ฅ ์ ์ ๊ณตํ๋ WOFF2์ ๊ฐ์ ์ต์ ํฐํธ ํฌ๋งท์ ์ฌ์ฉํ์ธ์.
- ์์ถ: Brotli๋ Gzip์ ์ฌ์ฉํ์ฌ ํฐํธ ํ์ผ์ ์์ถํ์ธ์.
- ๋ฏธ๋ฆฌ ๋ก๋ํ๊ธฐ(Preloading): ํฐํธ๊ฐ ํ์ํ๊ธฐ ์ ์ ๋ค์ด๋ก๋๋์ด ์ฌ์ฉ ๊ฐ๋ฅํ๋๋ก ๋ฏธ๋ฆฌ ๋ก๋ํ์ธ์.
<link rel="preload" as="font">
ํ๊ทธ๋ฅผ ์ฌ์ฉํ์ธ์. - ํฐํธ ํ์(Font Display):
font-display
CSS ์์ฑ์ ์ฌ์ฉํ์ฌ ํฐํธ๊ฐ ๋ก๋๋๋ ๋์ ์ด๋ป๊ฒ ํ์๋ ์ง ์ ์ดํ์ธ์. ์ผ๋ฐ์ ์ธ ๊ฐ์ผ๋ก๋swap
(์ฌ์ฉ์ ์ ์ ํฐํธ๊ฐ ๋ก๋๋ ๋๊น์ง ๋์ฒด ํฐํธ ํ์),fallback
(์งง์ ๊ธฐ๊ฐ ๋์ ๋์ฒด ํฐํธ ํ์ ํ ์ฌ์ฉ์ ์ ์ ํฐํธ๋ก ์ ํ),optional
(๋คํธ์ํฌ ์ํ์ ๋ฐ๋ผ ๋ธ๋ผ์ฐ์ ๊ฐ ์ฌ์ฉ์ ์ ์ ํฐํธ ์ฌ์ฉ ์ฌ๋ถ ๊ฒฐ์ ) ๋ฑ์ด ์์ต๋๋ค.
์์ (ํฐํธ ๋ฏธ๋ฆฌ ๋ก๋ํ๊ธฐ):
<link rel="preload" href="/fonts/my-font.woff2" as="font" type="font/woff2" crossorigin>
ํฐํธ ๋ก๋ (Webpack ์์)
Webpack์ ํฐํธ ํ์ผ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ๋ก๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
file-loader
: ํฐํธ ํ์ผ์ ์ถ๋ ฅ ๋๋ ํ ๋ฆฌ๋ก ๋ด๋ณด๋ด๊ณ ๊ณต๊ฐ URL์ ๋ฐํํฉ๋๋ค.url-loader
:file-loader
์ ์ ์ฌํ์ง๋ง, ํ์ผ ํฌ๊ธฐ๊ฐ ํน์ ์๊ณ๊ฐ๋ณด๋ค ์์ ๊ฒฝ์ฐ ํฐํธ๋ฅผ base64 ๋ฐ์ดํฐ URI๋ก ์ธ๋ผ์ธ ์ฒ๋ฆฌํ ์๋ ์์ต๋๋ค.
Webpack ์ค์ ์์:
module.exports = {
// ... ๋ค๋ฅธ ์ค์
module: {
rules: [
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[hash:8].[ext]',
outputPath: 'fonts',
},
},
],
},
],
},
};
์คํ์ผ์ํธ ํธ๋ค๋ง
์คํ์ผ์ํธ๋ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ์๊ฐ์ ๋ชจ์์ ์ ์ดํ๋ ๋ฐ ํ์์ ์ ๋๋ค. ์ต์ ์๋ฐ์คํฌ๋ฆฝํธ ๋ชจ๋ ์์คํ ๊ณผ ๋ฒ๋ค๋ฌ๋ ์คํ์ผ์ํธ๋ฅผ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ๋ ์ฌ๋ฌ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
์คํ์ผ์ํธ๋ฅผ ๋ชจ๋๋ก ๊ฐ์ ธ์ค๊ธฐ
์คํ์ผ์ํธ๋ ์๋ฐ์คํฌ๋ฆฝํธ ๋ชจ๋๋ก ์ง์ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
์์ (Webpack๊ณผ ES ๋ชจ๋):
// ์คํ์ผ์ํธ ๊ฐ์ ธ์ค๊ธฐ
import './styles.css';
// ์ปดํฌ๋ํธ ์ฝ๋
function MyComponent() {
return <div className="my-component">Hello, world!</div>;
}
์ด ์์์์ styles.css
ํ์ผ์ Webpack์ ์ํด ์ฒ๋ฆฌ๋์ด ๋ฒ๋ค์ ํฌํจ๋ฉ๋๋ค.
CSS ๋ชจ๋
CSS ๋ชจ๋์ CSS ๊ท์น์ ๊ฐ๋ณ ์ปดํฌ๋ํธ์ ๋ก์ปฌ๋ก ์ค์ฝํ๋ฅผ ์ง์ ํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ ์ด๋ฆ ์ถฉ๋์ ๋ฐฉ์งํ๊ณ ๋๊ท๋ชจ ํ๋ก์ ํธ์์ ์คํ์ผ์ ๋ ์ฝ๊ฒ ๊ด๋ฆฌํ ์ ์๊ฒ ํด์ค๋๋ค. CSS ๋ชจ๋์ ๋ฒ๋ค๋ฌ ์ค์ ์์ CSS ๋ก๋์ modules
์ต์
์ ํ์ฑํํ์ฌ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์์ (Webpack๊ณผ CSS ๋ชจ๋):
// styles.module.css
.myComponent {
color: blue;
font-size: 16px;
}
// MyComponent.js
import styles from './styles.module.css';
function MyComponent() {
return <div className={styles.myComponent}>Hello, world!</div>;
}
์ด ์์์์ styles.myComponent
ํด๋์ค๋ ๋น๋ ๊ณผ์ ์์ ๊ณ ์ ํ ํด๋์ค ์ด๋ฆ์ผ๋ก ๋ณํ๋์ด ๋ค๋ฅธ ์คํ์ผ๊ณผ ์ถฉ๋ํ์ง ์๋๋ก ๋ณด์ฅํฉ๋๋ค.
CSS-in-JS
CSS-in-JS ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋ ๋ด์์ ์ง์ CSS๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ์ด๋ ๋ค์๊ณผ ๊ฐ์ ์ฌ๋ฌ ์ด์ ์ ์ ๊ณตํฉ๋๋ค:
- ์ปดํฌ๋ํธ ์์ค ์ค์ฝํ: ์คํ์ผ์ด ๊ฐ๋ณ ์ปดํฌ๋ํธ๋ก ๋ฒ์๊ฐ ํ์ ๋ฉ๋๋ค.
- ๋์ ์คํ์ผ๋ง: ์ปดํฌ๋ํธ์ props๋ state์ ๋ฐ๋ผ ์คํ์ผ์ ๋์ ์ผ๋ก ์์ฑํ ์ ์์ต๋๋ค.
- ์ฝ๋ ์ฌ์ฌ์ฉ์ฑ: ์คํ์ผ์ ๋ค๋ฅธ ์ปดํฌ๋ํธ์์ ์ฝ๊ฒ ์ฌ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ธ๊ธฐ ์๋ CSS-in-JS ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- Styled Components: ํ๊ทธ๋ ํ ํ๋ฆฟ ๋ฆฌํฐ๋ด์ ์ฌ์ฉํ์ฌ CSS๋ฅผ ์์ฑํ๋ ์ธ๊ธฐ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
- Emotion: ๋ค์ํ ์คํ์ผ๋ง ์ ๊ทผ ๋ฐฉ์์ ์ง์ํ๋ ๊ณ ์ฑ๋ฅ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
- JSS: ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ์คํ์ผ์ ์ ์ํ๋ ํ๋ ์์ํฌ์ ๊ตฌ์ ๋ฐ์ง ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
์์ (Styled Components):
import styled from 'styled-components';
const MyComponent = styled.div`
color: blue;
font-size: 16px;
`;
function App() {
return <MyComponent>Hello, world!</MyComponent>;
}
์คํ์ผ์ํธ ์ต์ ํ ์ ๋ต
์คํ์ผ์ํธ ์ต์ ํ๋ ํ์ผ ํฌ๊ธฐ๋ฅผ ์ค์ด๊ณ ํ์ด์ง ๋ก๋ ์๊ฐ์ ๊ฐ์ ํ๋ ๋ฐ ๋งค์ฐ ์ค์ํฉ๋๋ค. ๋ค์ ์ ๋ต์ ๊ณ ๋ คํด ๋ณด์ธ์:
- ์์ถ(Minification): CSS ํ์ผ์์ ๋ถํ์ํ ๊ณต๋ฐฑ๊ณผ ์ฃผ์์ ์ ๊ฑฐํ์ธ์.
- ์ฌ์ฉํ์ง ์๋ CSS ์ ๊ฑฐ: ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ฌ์ฉ๋์ง ์๋ CSS ๊ท์น์ ์ ๊ฑฐํ์ธ์. PurgeCSS์ ๊ฐ์ ๋๊ตฌ๊ฐ ์ฌ์ฉ๋์ง ์๋ CSS๋ฅผ ์๋ณํ๊ณ ์ ๊ฑฐํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
- ์ฝ๋ ๋ถํ (Code Splitting): CSS๋ฅผ ํ์์ ๋ฐ๋ผ ๋ก๋ํ ์ ์๋ ๋ ์์ ์ฒญํฌ๋ก ๋ถํ ํ์ธ์.
- ํต์ฌ CSS(Critical CSS): ํ์ด์ง์ ์ด๊ธฐ ๋ทฐ๋ฅผ ๋ ๋๋งํ๋ ๋ฐ ํ์ํ CSS๋ฅผ ์ธ๋ผ์ธ์ผ๋ก ํฌํจํ์ธ์. ์ด๋ ์ฒด๊ฐ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
CSS ๋ก๋ (Webpack ์์)
Webpack์ CSS ํ์ผ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ๋ก๋๋ฅผ ์ฌ์ฉํฉ๋๋ค.
style-loader
:<style>
ํ๊ทธ๋ฅผ ์ฌ์ฉํ์ฌ CSS๋ฅผ DOM์ ์ฃผ์ ํฉ๋๋ค.css-loader
:@import
์url()
์import
/require()
์ฒ๋ผ ํด์ํ๊ณ ์ด๋ฅผ ํด๊ฒฐํฉ๋๋ค.postcss-loader
: CSS์ PostCSS ๋ณํ์ ์ ์ฉํฉ๋๋ค. PostCSS๋ ์๋ ์ ๋์ฌ ์ถ๊ฐ(autoprefixing), ์์ถ, ๋ฆฐํ ๊ณผ ๊ฐ์ CSS ์์ ์ ์๋ํํ๋ ๊ฐ๋ ฅํ ๋๊ตฌ์ ๋๋ค.
Webpack ์ค์ ์์:
module.exports = {
// ... ๋ค๋ฅธ ์ค์
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.module\.css$/i,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
},
},
],
},
],
},
};
๊ธ๋ก๋ฒ ์์ ๊ด๋ฆฌ๋ฅผ ์ํ ๋ชจ๋ฒ ์ฌ๋ก
์ ์ธ๊ณ ์ฌ์ฉ์๋ฅผ ๋์์ผ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ ๋๋ ์์ ๊ด๋ฆฌ๋ฅผ ์ํด ๋ค์๊ณผ ๊ฐ์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๊ณ ๋ คํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค:
- ์ฝํ ์ธ ์ ์ก ๋คํธ์ํฌ(CDN): CDN์ ์ฌ์ฉํ์ฌ ์ ์ธ๊ณ ์ฌ๋ฌ ์๋ฒ์ ์์ ์ ๋ฐฐํฌํ์ธ์. ์ด๋ ์ง์ฐ ์๊ฐ์ ์ค์ด๊ณ ๋ค๋ฅธ ์ง๋ฆฌ์ ์์น์ ์๋ ์ฌ์ฉ์์ ๋ค์ด๋ก๋ ์๋๋ฅผ ํฅ์์ํต๋๋ค. ์ธ๊ธฐ ์๋ CDN ์ ๊ณต์ ์ฒด๋ก๋ Cloudflare, Amazon CloudFront, Akamai ๋ฑ์ด ์์ต๋๋ค.
- ํ์งํ(Localization): ๋ค๋ฅธ ์ธ์ด์ ์ง์ญ์ ๋ง๊ฒ ์์ ์ ์กฐ์ ํ์ธ์. ์ฌ๊ธฐ์๋ ์ด๋ฏธ์ง์ ํ ์คํธ ๋ฒ์ญ, ๋ค๋ฅธ ์คํฌ๋ฆฝํธ์ ์ ํฉํ ํฐํธ ์ฌ์ฉ, ์ง์ญ๋ณ ์ด๋ฏธ์ง ์ ๊ณต ๋ฑ์ด ํฌํจ๋ฉ๋๋ค.
- ์ ๊ทผ์ฑ: ์ฅ์ ๊ฐ ์๋ ์ฌ์ฉ์๋ ์์ ์ ์ ๊ทผํ ์ ์๋๋ก ๋ณด์ฅํ์ธ์. ์ฌ๊ธฐ์๋ ์ด๋ฏธ์ง์ ๋ํ ๋์ฒด ํ ์คํธ ์ ๊ณต, ์ ์ ํ ํฐํธ ํฌ๊ธฐ์ ์์ ์ฌ์ฉ, ์น์ฌ์ดํธ๊ฐ ํค๋ณด๋๋ก ํ์ ๊ฐ๋ฅํ๋๋ก ํ๋ ๊ฒ์ด ํฌํจ๋ฉ๋๋ค.
- ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง: ์์ ์ ์ฑ๋ฅ์ ๋ชจ๋ํฐ๋งํ์ฌ ๋ณ๋ชฉ ํ์์ ์๋ณํ๊ณ ํด๊ฒฐํ์ธ์. Google PageSpeed Insights๋ WebPageTest์ ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ์น์ฌ์ดํธ์ ์ฑ๋ฅ์ ๋ถ์ํ์ธ์.
- ์๋ํ๋ ๋น๋ ๋ฐ ๋ฐฐํฌ: ์ผ๊ด์ฑ๊ณผ ํจ์จ์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํด ๋น๋ ๋ฐ ๋ฐฐํฌ ํ๋ก์ธ์ค๋ฅผ ์๋ํํ์ธ์. Jenkins, CircleCI ๋๋ GitHub Actions์ ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋น๋, ํ ์คํธ ๋ฐ ๋ฐฐํฌ๋ฅผ ์๋ํํ์ธ์.
- ๋ฒ์ ๊ด๋ฆฌ: ๋ฒ์ ๊ด๋ฆฌ(์: Git)๋ฅผ ์ฌ์ฉํ์ฌ ์์ ๋ณ๊ฒฝ ์ฌํญ์ ์ถ์ ํ๊ณ ๋ค๋ฅธ ๊ฐ๋ฐ์์ ํ์ ํ์ธ์.
- ๋ฌธํ์ ๋ฏผ๊ฐ์ฑ ๊ณ ๋ ค: ์์ ์ ์ ํํ๊ณ ์ฌ์ฉํ ๋ ๋ฌธํ์ ์ฐจ์ด๋ฅผ ์ ๋ ํ์ธ์. ํน์ ๋ฌธํ์์ ๋ถ์พํ๊ฑฐ๋ ๋ถ์ ์ ํ ์ ์๋ ์ด๋ฏธ์ง๋ ํฐํธ ์ฌ์ฉ์ ํผํ์ธ์.
๊ฒฐ๋ก
ํจ๊ณผ์ ์ธ ์๋ฐ์คํฌ๋ฆฝํธ ๋ชจ๋ ๋ฆฌ์์ค ๊ด๋ฆฌ๋ ๊ณ ์ฑ๋ฅ์ ํ์ฅ ๊ฐ๋ฅํ๊ณ ์ ์ง๋ณด์ ๊ฐ๋ฅํ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋ฐ ํ์์ ์ ๋๋ค. ๊ฐ๋ฐ์๋ ๋ชจ๋ ์์คํ , ๋ฒ๋ค๋ฌ, ์์ ํธ๋ค๋ง ๊ธฐ๋ฒ์ ์๋ฆฌ๋ฅผ ์ดํดํจ์ผ๋ก์จ ์ ์ธ๊ณ ์ฌ์ฉ์๋ฅผ ์ํด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ต์ ํํ ์ ์์ต๋๋ค. ๋น ๋ฅด๊ณ ๋งค๋ ฅ์ ์ธ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ง๋ค๊ธฐ ์ํด ์ด๋ฏธ์ง ์ต์ ํ, ํฐํธ ๋ก๋ฉ ์ ๋ต, ์คํ์ผ์ํธ ๊ด๋ฆฌ์ ์ฐ์ ์์๋ฅผ ๋๋ ๊ฒ์ ๊ธฐ์ตํ์ธ์.