평소 가볍게 개발을 공부하거나 무언가를 만들어볼 때는 빠르게 시작하기 위해서 React CRA를 이용해 개발환경을 구축하곤 했었다. CRA(Create React App) 역시 내부적으로 webpack과 babel을 사용하기는 하지만 이러한 설정이 숨겨져있기 때문에 초기 설정에 대한 고민 없이 편하게 시작할 수 있다. 하지만 확장성이 떨어지기 때문에 복잡한 프로젝트에는 부적합할 수 있으며, 내부적으로 관리하는 설정때문에 세부적인 조정이 필요한 경우, 제한이 있을 수 있어 webpack과 babel을 사용하여 개발환경을 구축하는 것이 훨씬 유리하다. 보통 회사에서는 CRA를 사용하기 보단 리액트, 뷰 등의 개발환경을 개발자가 직접 구축하는 경우가 많은데 나 역시도 웹팩과 바벨로 직접 구축한 프로젝트를 맡고 있기 때문에 새롭게 시작하는 프로젝트는 webpack과 babel로 직접 구성해보려고 한다. 중간중간 설치 에러, 버전 에러, 경로 설정 에러 등의 다양한 에러를 만났지만 하나씩 해결하며 구성을 완료했다.
1. Webpack과 babel로 개발환경의 장단점
CRA도 장점과 단점을 각각 가지고 있지만 webpack과 babel 설정을 통해 직접 개발환경을 구성할 경우 해당 설정을 직접 관리하며 세부적인 설정을 자유롭게 조정할 수 있고, 필요한 설정들을 커스터마이징하여 최적의 성능, 최적화된 빌드를 구성할 수 있다는 장점이 있다. 각각의 빌드 구성에 따라 명령어를 통해 다른 빌드 환경을 만들어나갈 수 있어 확장성이 좋은 것 같다. 단, 초기 설정에 시간이 소요될 수 있고 초보자에게는 학습 곡선이 높을 수 있다는 단점도 존재하는데 웹팩과 바벨에 대한 설정, 플러그인 등을 사용할 수 있도록 학습이 필요하기 때문이다. 또한 설정 변경으로 인한 전체적인 오류가 발생할 수 있어 유지보수에도 주의가 필요하니 이러한 부분을 잘 알고 시작하는 것이 좋다.
2. React 개발환경 구축하기 (webpack + babel + typescirpt)
1. npm 패키지 설치
가장 먼저 프로젝트 세팅을 위해 설치가 필요한 것들을 먼저 설치해준다. -D 옵션이 붙은 것들은 개발 종속성에 들어가는 패키지로 프로젝트를 개발하거나 빌드하고 테스트 하는 동안에만 필요한 패키지들을 모아 놓은 것이라고 보면 된다. 보통 빌드도구나 테스트도구 같은 것들이 추가된다.
# npm 프로젝트 세팅
npm init -y
# react 설치
npm i react react-dom
# 타입스크립트 설치
npm i -D typescript @types/react @types/react-dom ts-loader
# webpack, webpack plugin 설치
npm i -D webpack webpack-cli webpack-dev-server
npm i -D html-webpack-plugin clean-webpack-plugin
npm i -D style-loader css-loader sass-loader
# babel 설치
npm i -D babel-loader @babel/core
npm i -D @babel/preset-env @babel/preset-react @babel/preset-typescript
2. index.html, App.jsx, index.tsx 스크립트 작성
필요한 것들을 설치하는 과정이 끝났다면 public, src 폴더를 각각 생성하여 아래와 같이 스크립트를 작성해준다. 리액트 설치 버전에 따라 index.tsx 코드는 변경될 수 있다.
// public/index.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>포트폴리오</title>
</head>
<body>
<!-- 이 부분 추가 -->
<div id="root"></div>
</body>
</html>
// src/App.tsx
const App: React.FC = () => {
return <div>웹팩과 바벨을 라액트 개발환경 구성</div>;
};
export default App;
// src/index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
리액트 18버전 이상을 사용한다면 해당 코드를 실행시켰을 때 console 창에 index.tsx:15 Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. 라는 경고 메세지가 표시될 것이다. 18버전 이상부터는 ReactDOM.render을 더이상 사용하지 않아 아래 코드로 변경해주면 된다.
// React 18버전 이상
// src/index.tsx
import ReactDOM from "react-dom/client";
import App from "./App";
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
root.render(<App />);
3. webpack.config.js 작성
webpack.config.js 파일의 경우 환경변수를 통해 production 모드인지, 개발 모드인지를 분리해서 빌드할 수 있도록 설정이 가능하다. 또한 원하는 플러그인을 별도로 설치하여 각각을 컨트롤 할 수 있는데 만약 css가 아닌 scss를 사용한다면 관련 로더 설치가 필요하다.
const webpack = require("webpack");
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = (env, argv) => {
const production = argv.mode === "production";
return {
mode: production ? "production" : "development",
devtool: production ? "hidden-source-map" : "eval",
entry: { main: "./src/index.tsx" },
output: {
path: path.join(__dirname, "/dist"),
filename: "[name].js",
},
devServer: {
port: 3000, // port 번호 설정 가능
hot: true, // HMR 활성화 여부, 모듈 단위로 업데이트 적용
},
resolve: {
extensions: [".js", ".jsx", ".ts", ".tsx"], // ts를 사용할 경우 ts 추가
},
module: {
rules: [
{
test: /\.tsx?$/,
use: ["babel-loader", "ts-loader"],
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.scss$/, // scss 로더 필요
use: ["style-loader", "css-loader", "sass-loader"],
}
],
},
plugins: [
new webpack.ProvidePlugin({
React: "react",
}),
new HtmlWebpackPlugin({
template: "./public/index.html",
minify: // 압축 옵션
process.env.NODE_ENV === "production"
? {
collapseWhitespace: true, // production mode 시, 빈칸 제거
removeComments: true, // production mode 시, 주석 제거
}
: false,
}),
new CleanWebpackPlugin(),
],
};
};
4. babel.config.js 작성
babel은 자바스크립트 컴파일러로 리액트에서 작성하는 jsx 파일을 js파일로, ts파일을 js파일로 컴파일 한다던가, 코드를 실행하는 환경에 맞게 필요한 버전으로 변환해주는 역할을 수행한다. 크로스브라우징 이슈가 발생했을 때, 버전에 관한 문제라면 해당 방식으로 문제 해결을 생각해볼 수 있게 된다.
module.exports = {
presets: [
"@babel/preset-react",
"@babel/preset-env",
"@babel/preset-typescript",
],
};
5. tsconfig.json 작성
// tsconfig.json
{
"compilerOptions": {
"target": "es2016",
"jsx": "react-jsx",
"strict": true,
"skipLibCheck": true
}
}
6. package.json script 수정
"scripts": {
"dev": "webpack-dev-server --mode=development --open --hot --progress",
"build": "webpack --mode=production --progress",
"start": "webpack --mode=development --progress"
},
해당 세팅은 정말 기본적인 세팅이기 때문에 필요한 설정에 따라 추가적인 플러그인을 설치하거나 옵션을 추가할 수 있다. webpack 사이트에 가면 번들링 설정 옵션이 잘 나와있으니 참고하여 내가 원하는대로 수정해보면 될 것 같다. 이후에는 eslint, prettier 설정을 추가할 예정이다.