리액트 프로젝트를 시작할 때 create-react-app만 사용하다 보니까 번들러에 대한 지식이 부족한 걸 느꼈다. 그래서 CRA를 사용하지 않고 CRA 예제 코드 실행하기에 도전해봤다. 웹팩에 대해서 찾아보다 보니까 확실히 복잡하긴 하다.... 나중엔 다른 번들러(Parcel? Rollup?)도 한번 공부해봐야 할 듯.
package.json 생성
일단 적당한 폴더를 만들고 아래 명령어로 package.json 파일을 생성한다.
yarn init -y
yarn을 기준으로 작성하겠음. npm도 명령어만 약간 다를 뿐 과정은 똑같다.
리액트 설치
yarn add react react-dom react-refresh
바벨 설치
yarn add @babel/core @babel/preset-env @babel/preset-react
바벨은 최신 자바스크립트 문법을 구형 브라우저에서도 동작하게, 혹은 리액트의 jsx 문법을 자바스크립트 문법으로 변환해주는 자바스크립트 트랜스파일러이다.
@babel/preset-env - 최신 자바스크립트 문법을 구형 브라우저에서도 작동하도록 변환하거나 폴리필 추가
@babel/preset-react - 리액트의 JSX 문법을 변환
babel.config.json 생성
babel.config.json은 바벨 설정 파일이다. 앞에서 바벨과 함께 설치한 프리셋을 설정해준다.
{
"presets": [
"@babel/preset-env",
["@babel/preset-react", { "runtime": "automatic" }]
]
}
React 17 이후부턴 "runtime": "automatic" 옵션을 추가해야 한다.
웹팩 설치
yarn add webpack webpack-cli webpack-dev-server
웹팩은 자바스크립트 번들러이다. 직접 작성한 코드나 여러 라이브러리의 자바스크립트 코드를 하나로 묶고 최적화해준다.
webpack-cli - 웹팩을 커맨드라인에서 실행할 수 있게 해 줌
webpack-dev-server - 파일이 변화할 때마다 실시간으로 빌드하는 개발 서버 구동
웹팩 로더 설치
yarn add babel-loader css-loader style-loader
로더는 웹팩이 파일을 빌드할 때 파일을 해석하기 위한 패키지이다.
babel-loader - jsx 파일과 최신 자바스크립트 문법을 변환(바벨과 연동)
css-loader - css 파일을 해석
style-loader - css를 dom에 삽입
웹팩 플러그인 설치
yarn add html-webpack-plugin mini-css-extract-plugin interpolate-html-plugin @pmmmwh/react-refresh-webpack-plugin
플러그인은 웹팩이 해석한 결과물을 처리하는 패키지이다.
html-webpack-plugin - html 파일에 번들링 된 js 파일을 삽입
mini-css-extract-plugin - js 파일과 css 파일을 분리
interpolate-html-plugin - html 파일에서 %ENV% 같은 템플릿 구문 사용 가능. 꼭 필요한 건 아니지만 CRA 기본 예제 파일에서 %PUBLIC_URL%을 사용하기 때문에 이를 변환하기 위해 설치
@pmmmwh/react-refresh-webpack-plugin - 좀 더 우수한 핫 리로드 패키지인 react-refresh 사용
webpack.config.js 생성
webpack.config.js는 웹팩 설정 파일이다. 앞에서 설치한 로더와 플러그인들을 넣어준다.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const InterpolateHtmlPlugin = require('interpolate-html-plugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const devMode = process.env.NODE_ENV !== 'production';
module.exports = {
entry: './src/index.js',
resolve: {
extensions: ['.js', '.jsx'],
},
output: {
path: path.resolve(__dirname, 'build'),
filename: 'static/js/[name].[contenthash:8].js',
chunkFilename: 'static/js/[name].[contenthash:8].chunk.js',
assetModuleFilename: 'static/media/[name].[hash:8].[ext]',
clean: true,
},
devtool: devMode ? 'eval-source-map' : false,
devServer: {
port: 3000,
hot: true,
open: true,
client: {
overlay: true,
progress: true,
},
},
module: {
rules: [
{
oneOf: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [['@babel/preset-env', { targets: 'defaults' }]],
plugins: devMode ? ['react-refresh/babel'] : [],
},
},
},
{
test: /\.css$/i,
use: [
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
],
},
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 10000,
},
},
},
{
type: 'asset/resource',
exclude: [/\.(js|jsx)$/, /\.html$/, /\.json$/, /^$/],
},
],
},
],
},
plugins: [
new HtmlWebpackPlugin(
Object.assign(
{},
{
template: 'public/index.html',
},
!devMode
? {
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}
: undefined
)
),
new InterpolateHtmlPlugin({ PUBLIC_URL: '' }),
].concat(
devMode ? [new ReactRefreshWebpackPlugin()] : [new MiniCssExtractPlugin()]
),
};
개발 빌드에선 style-loader를 사용하고 프로덕션 빌드에선 mini-css-extract-plugin을 사용한다. 왜 이렇게 했냐면 css-loader 문서에서 이걸 추천한대서...ㅎㅎ
CRA나 다른 글에서는 file-loader와 url-loader를 사용하는데 webpack 5부턴 자체적으로 지원해서 사용하지 않았다. 설정은 CRA 꺼 따라 했음. 약 10KB보다 작은 이미지 파일은 base64 주소로 변환돼서 결과물에 직접 삽입된다.
마지막 룰을 보면 js, html, json, 이미지 파일을 제외한 파일들은 전부 리소스로 처리해서 static/media 안에 집어넣는데 제외한 파일 정규식에 /^$/도 있는 이유가 html-webpack-plugin에서 이상한 파일을 생성하는 문제가 있어서(파일이 아니라 인라인 자바스크립트라고 함. 근대 이걸 리소스로 처리해서 문제가 생김) 이를 제외하기 위해 넣었다. (참고)
마찬가지로 html-webpack-plugin 설정도 CRA를 참고했다. 프로덕션 빌드에선 최적화된 html을 내보낸다.
리액트 컴포넌트 작성
그냥 CRA에서 기본으로 만들어주는 예제 파일을 그대로 복사한다. (src, public 폴더)
단, 예제 소스에서는 web-vitals을 사용하므로 이걸 추가로 설치해야 한다.
yarn add web-vitals
package.json에 scripts 추가
"scripts": {
"start": "webpack serve --progress --mode development",
"build": "webpack --progress --mode production"
}
yarn start - 개발 서버를 실행해 프로젝트를 바로 확인. 주소는 http://localhost:3000/
yarn build - 빌드. 결과물은 build 폴더에 생성
이걸로 리액트를 개발하기 위한 최소한의 환경 구성이 완료되었다. 공부하면서 느낀 점은 그냥 얌전히 create-react-app 쓰자...ㅎㅎ
정말 최소한의 세팅이라 eslint, prettier 등등 추가할 게 많은데 이것도 한번 정리해볼까 고민 중...
'프로그래밍 > React' 카테고리의 다른 글
CRA 없이 React 개발환경 구축하기 (Rollup편) (0) | 2022.03.05 |
---|---|
스토리북에서 CSS Modules 사용하기 (0) | 2022.02.05 |
CRA 없이 React 개발환경 구축하기 (Parcel편) (0) | 2022.01.22 |
We no longer support global installation of Create React App 오류 해결법 (0) | 2022.01.05 |
부모 컴포넌트에서 자식 컴포넌트 함수 실행하기 (0) | 2021.08.13 |
함수형 컴포넌트에서 forceUpdate 구현 (0) | 2021.07.02 |
서브 디렉터리에서 리액트 앱 실행 문제 해결 (0) | 2021.06.12 |
아파치 웹서버에 리액트 라우터 앱 올리기 (0) | 2021.05.22 |