CRA(create-react-app) ํ๊ฒฝ์์ ์ ๋๊ฒฝ๋ก / ์ ์ญ Sass ์ฌ์ฉํ๊ธฐ
CRA
- ๋ฆฌ์กํธ ํ๋ก์ ํธ๋ฅผ ๋๋ฑ ์์ํ ์ ์๊ฒ ๋๋ ๋ณด์ผ๋ฌ ํ๋ ์ดํธ* (*์์ฃผ ์ฐ๋ ์์, ๋ช ๋ น์ด ๋ฑ์ ๋ฏธ๋ฆฌ ์ ๋ ฅํด ๋๋ ๊ฒ)
- ๊ทธ๋์ ๋ฒ๊ฑฐ๋กญ๊ฒ Babel, ESLint, Webpack ๋ฑ์ ๋ฐ๋ก ์ค์นํ ํ์๊ฐ ์๋ค
CRA(create-react-app)์์ config ๊ฑด๋๋ฆฌ๊ธฐ
์ ๋๊ฒฝ๋ก ์ค์ (alias)์ ํ๋ ค๋ฉด Webpack์ config๋ฅผ ๊ฑด๋๋ ค์ผ ํ์ง๋ง, CRA๋ก ์์ฑํ๋ฉด ๊ธฐ๋ณธ์ ์ผ๋ก config ํ์ผ์ ๋ณผ ์ ์๋ค.
eject ํ๋ฉด ์จ๊ฒจ์ ธ ์๋ config ํ์ผ์ ๋ฐ์ผ๋ก ๊บผ๋ผ ์ ์์ง๋ง, ์ด๊ฑฐ ํ ๋ฒ ํ๋ฉด ๋ชป ๋๋ฆฌ๋ ์ต์ ์ธ๋ฐ.... ์นํฉ์ด๋ ์ ์นํ๋ฐ.... ๐ฅบ
์ด๋ด ๋ CRACO(Create React App Configuration Override) ๋ฅผ ์ฌ์ฉํ์! eject ์์ด ์ค์ ์ ๊ฑด๋๋ฆด ์ ์๋ค ๐
$ yarn add @craco/craco
$ yarn add -D craco-sass-resources-loader
์ค์นํ ํ config ํ์ผ๋ค์ ์ฅ์ฅ ๋ง์ ธ์ค๋ค.
1. craco๊ฐ ๋ช ๋ น์ด๋ฅผ ์คํํ๋๋ก ๋ฐ๊พธ๊ธฐ
/* package.json ์์ */
{
...
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
},
...
}
2. craco.config.js ํ์ผ ์ค์
- ํ์ ์คํฌ๋ฆฝํธ ํ๊ฒฝ์ด์ฌ์ plugins.options.source ๋ฅผ tsconfig ๋ก ์ค์ ํ๋ค. (์๋ฐ์คํฌ๋ฆฝํธ ํ๊ฒฝ์ด๋ผ๋ฉด jsconfig)
/* craco.config.js ์์ฑ */
const CracoAlias = require('craco-alias');
module.exports = {
plugins: [
{
plugin: CracoAlias,
options: {
source: 'tsconfig',
tsConfigPath: 'tsconfig.paths.json'
}
}
]
};
3. tsconfig.paths.json ์์ฑ ํ ๊ฒฝ๋ก ์ค์
- ๋ณ๋ ํ์ผ๋ก ๋ถ๋ฆฌํ์ง ์๊ณ config.js ๋ด์ ์ง์ ์ ๋ ฅํด๋ ๋ฌด๊ด!
/* tsconfig.paths.json ์์ฑ */
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
// ๋๋ "@components/*": ["src/components/*"] ์ฒ๋ผ ์ง์ ๊ฐ๋ฅ
}
}
}
4. tsconfig.json ์์
- ์ปดํ์ผํ๋ ๋ฐ ํ์ํ ๋ฃจํธ ํ์ผ๊ณผ ์ปดํ์ผ๋ฌ ์ต์ ์ ์ง์ ํ๋ ํ์ผ
- extends
: ๋ค๋ฅธ ํ์ผ์ ์ค์ ์ ์์
- include
: ์ปดํ์ผ ํ ๋ ํฌํจํ ํด๋๋ ํ์ผ
/* tsconfig.json ์์ */
{
"extends": "./tsconfig.paths.json",
"compilerOptions": {
//...
},
"include": ["src", "tsconfig.paths.json"]
}
์ด๋ ๊ฒ ํ๋ฉด @/components/button ๋๋ @/styles/_mixin.scss ์ ๊ฐ์ด ๋ถ๋ฌ์ ์ธ ์ ์๋ค.
์ด์ craco.config.js ์์ ๊ธ๋ก๋ฒ๋ก ์ ์ฉํ ์คํ์ผ์ @/styles/๋ก ์ง์ ํด ์ค ์ ์๋ค.
const CracoAlias = require('craco-alias');
module.exports = {
style: {
sass: {
loaderOptions: {
additionalData: `
@import "@/styles/_variable.scss";
@import "@/styles/_mixin.scss";
`
}
}
},
plugins: [
{
plugin: CracoAlias,
options: {
source: 'tsconfig',
tsConfigPath: 'tsconfig.paths.json'
}
}
]
};
๋ง1) CRA ๊ธฐ๋ฐ Storybook์์ ์ ์ญ ๋ณ์ ์ดํดํ๊ฒ ๋ง๋ค๊ธฐ
์... ์ด๋ง๋ฌด์ํ ์ฝ์ง!!
์ด๋ ๊ฒ๋ง ํ๋๋ ์คํ ๋ฆฌ๋ถ์์๋ ์ ์ญ ๋ณ์๋ฅผ ์ดํดํ์ง ๋ชปํด์ ์ฌ๋ฌ ๋ฐฉ๋ฉด์ผ๋ก ํ์ผ๋ฌ๋ณด๋ค๊ฐ (์ ์ดํดํ์ง ๋ชปํ๋ใ ใ !!)
์คํ ๋ฆฌ๋ถ์ main.js ์์ sass-loader ์ additionalData ๋ฃ๋ ๊ฑธ๋ก ํด๊ฒฐ.
/* .storybook/main.js */
module.exports = {
//...
webpackFinal: async (config, { configType }) => {
config.module.rules.push({
test: /\.scss$/,
use: [
{
loader: 'sass-loader',
options: {
additionalData: `
@import "./src/styles/_variable.scss";
@import "./src/styles/_mixin.scss";
`
}
}
]
});
return config;
}
};
์ด์ ๋ ๋ชจ๋ฅด๊ฒ ์ผ๋ sass-loader ์ธ์ style-loader ๋ css-loader๋ ๊ฐ์ด ์ง์ ํ๊ฒ ๋๋ฉด,
"import API from "!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js";" ์๋ฌ๊ฐ ๋ถ๋ถ์ณ.
์๋ฌด๋๋ ๊ธฐ๋ณธ ์ค์ ์ด๋ ์ด๋๊ฐ์์ ์ถฉ๋์ด ๋๋ ๊ฒ ๊ฐ์ง๋ง ์ง๊ธ์ผ๋ก์ ์ ์ ์๋ค... ๐ญ
๋ง2) Vite ํ๊ฒฝ์์ ์ค์ ํ๊ธฐ
CRACO ์์ด tsconfig.json, vite.config.js ํ์ผ์ ์ค์ ํด์ฃผ๋ฉด ๋๋ค.
๊ตณ์ด paths.json ์ผ๋ก ๋นผ์ง ์๊ณ tsconfig.json ์ ๊ฒฝ๋ก๋ฅผ ์ ๋ ฅํด์ฃผ๊ณ , vite.config.ts์ alias๋ฅผ ์ง์ ํด ์ค ๋ชจ์ต๐
/* tsconfig.json */
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}
/* vite.config.ts */
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import * as path from 'path';
// <https://vitejs.dev/config/>
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
},
css: {
preprocessorOptions: {
scss: {
additionalData: `
@import '@/styles/_variable.scss';
@import '@/styles/_mixin.scss';
`,
},
},
},
});
๋ง๋ฌด๋ฆฌ๋ ์ญ์...