React + Typescript + Webpack (without CRA)

seohyun Kang·2023년 2월 7일
0

React

목록 보기
4/9

Why?

React + Typescript + Webpack의 Boiler-plate를 만들었는가?

기존 프로젝트를 하면서 Builder인 Webpack을 지금보다 잘 사용하고 싶다는 관심은 있었습니다. 다만, 지금까지 CRA로 작업하다보니 해당 프로젝트를 eject해서 Webpack의 사용법을 익혀나가기에는 코드의 양과 수준이 방대하고 높았습니다.

그래서 Boiler-Plate를 만들고 프로젝트를 git clone해서 사이드 프로젝트를 시작하고 Webpack의 사용법도 점진적으로 익혀나가면 좋을 것 같다는 생각이 들었습니다.

Get-started

시작은 당연하지만, 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 이 생성됩니다.

Project Directory

ㄴ src
	ㄴ index.js
ㄴ public
	ㄴ index.html
package.json
webpack.config.js

Webpack Configuration

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 입니다.

React Preperation

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를 지정합니다.

Write Scripts

{
  ...,
  "scripts": {
    "webpack": "webpack",
    "start": "webpack-dev-server"
  },
}

이제 Project를 로컬에서 실행시키기 위한 작업은 다 끝난 것처럼 보입니다.

npm run-script start로 실행하면 아래와 같은 에러를 마주하게 됩니다.

Babel 적용

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"],
          },
        },
      },
    ]
  },

Start Project

npm run-script start 로 프로젝트를 실행하면 아래와 같이 프로젝트가 실행되는 것을 확인할 수 있습니다.

Typescript 적용

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/,
      },
    ]
  },

Trouble Shooting

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

0개의 댓글