React + Typescript + Webpack의 Boiler-plate를 만들었는가?
기존 프로젝트를 하면서 Builder인 Webpack을 지금보다 잘 사용하고 싶다는 관심은 있었습니다. 다만, 지금까지 CRA로 작업하다보니 해당 프로젝트를 eject해서 Webpack의 사용법을 익혀나가기에는 코드의 양과 수준이 방대하고 높았습니다.
그래서 Boiler-Plate를 만들고 프로젝트를 git clone해서 사이드 프로젝트를 시작하고 Webpack의 사용법도 점진적으로 익혀나가면 좋을 것 같다는 생각이 들었습니다.
시작은 당연하지만, Webpack 문서를 참고했습니다.
npm init -y
npm install webpack webpack-cli html-webpack-plugin --save-dev
> + webpack-dev-server
문서에 추가로 개발 서버를 운영할 예정이기 때문에 webpack-dev-server library도 설치합니다.
ㄴ package.json
npm init
를 실행하면 위와 같이 package.json 이 생성됩니다.
ㄴ src
ㄴ index.js
ㄴ public
ㄴ index.html
package.json
webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
module.exports = {
mode: "development",
devServer: {
port: 3000,
hot: true,
},
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.join(__dirname, "dist"),
},
resolve: {
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
],
};
devServer는 webpack-dev-server를 위한 option 입니다.
npm install react react-dom
로 React 관련 Library를 설치합니다.
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
src/index.js 에 위와 같이 React javascript 소스를 작성하고 public/index.html
<!DOCTYPE html>
<html>
<head></head>
<body>
<div id="root"></div>
</body>
</html>
React가 생성한 Virtual DOM을 가져올 root를 지정합니다.
{
...,
"scripts": {
"webpack": "webpack",
"start": "webpack-dev-server"
},
}
이제 Project를 로컬에서 실행시키기 위한 작업은 다 끝난 것처럼 보입니다.
npm run-script start
로 실행하면 아래와 같은 에러를 마주하게 됩니다.
Babel관련 내용은 공식 웹페이지를 참고해주세요.
위 이슈는 Babel 관련 Library를 적용하여 해결이 가능합니다.
npm install @babel/core @babel/preset-env @babel/preset-react babel-loader
바벨관련 라이브러리를 설치 후에 아래와 같이 webpack.config.js를 수정합니다.
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
},
]
},
npm run-script start
로 프로젝트를 실행하면 아래와 같이 프로젝트가 실행되는 것을 확인할 수 있습니다.
Webpack의 Typescript Docs를 참고
tsc --init
으로 tsconfig.json을 생성하면 옵션 리스트가 주석처리 되어 리스트 업됩니다. 그 중에서 target, module ("es6"), allowJs, jsx ("react"), outDir, strict, noImplicitAny, moduleResolution, esModuleInterop, forceConsistentCasingInFileNames 옵션을 사용합니다.
{
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": true,
"esModuleInterop": true,
"module": "es6",
"target": "es5",
"jsx": "react",
"allowJs": true,
"moduleResolution": "node”,
“strict” : true,
“forceConsistentCasingInFileNames” : true
}
}
다음으로 npm install ts-loader
로 ts-loader library를 설치하고 webpack.config.js를 수정합니다.
module: {
resolve: {
alias: {
components: path.resolve(__dirname, "..", "src"),
},
extensions: [".js", ".jsx", ".ts", ".tsx"],
},
rules: [
...,
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
]
},
tsconfig.json 및 webpack.config.js 수정이 제대로 되지 않고 npm run-script start
로 실행하면 아래와 같은 에러를 마주합니다.
resolve : {
alias: {
components: path.resolve(__dirname, "..", "src"),
},
extensions : [".js", ".jsx", ".ts", ".tsx"]
}
위의 코드가 빠졌기 때문인데
Resolve Alias
Resolve Extensions
를 참고해주세요.
또한, 위와 같은 에러가 발생하는데 tsconfig.json 의 strict option으로 인한 에러입니다.
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
- const root = ReactDOM.createRoot(document.getElementById("root"));
+ const rootEl = document.getElementById("root")!;
const root = ReactDOM.createRoot(rootEl);
root.render(<App />);
root Element가 없을 수도 있기 때문에 발생한 에러인데, rootEl를 반드시 존재하도록 강제하거나 없을 경우 Default Object를 선언하여 해결할 수 있습니다.
References :
Webpack Docs Get-started
Bable Docs
Babel-loader
Typescript Docs
Resolve Alias
Resolve Extensions