CRA를 사용하지 않고 React 초기 세팅하기

chaelin.s·2021년 10월 7일
13
post-thumbnail

웹팩4 + 리액트는 구글에 참 많은 자료가 있다. 리액트 + 타입스크립트도 많다. 웹팩4 + 리액트 + 타입스크립트도 있다. 그런데 웹팩5 + 타입스크립트 + 리액트 초기세팅에 대한 자료는 별로 없다!
있는데 못찾았을 가능성이 더 큼... 자료가 있어도 한번에 정리해놓은 자료는 별로 없는 것 같아서 블로그에 정리해 봅니다. 미래의 나에게 도움이 되길😆

폴더 생성

터미널에 다음 명령어로 폴더를 생성해 줍니다.

mkdir <폴더 이름>

React 설치

터미널에 명령어를 입력해서 리액트를 설치해 줍니다.

npm install --save react react-dom

Typscript 설치

타입스크립트를 설치하면 이전에 설치했던 라이브러리의 type들이 필요하기 때문에 reactreact-dom@types도 설치해줍니다.

npm install --save typescript
npm install --save-dev @types/react @types/react-dom

Webpack 설치

웹팩은 모던 자바스크립트 애플리케이션을 위한 정적 모듈 번들러입니다. 이 포스트는 초기 세팅을 설명하기 때문에 웹팩에 대한 자세한 설명은 넘어가도록 하겠습니다. 웹팩과 로더들을 설치해줍니다.

npm install --save-dev webpack webpack-cli webpack-dev-server babel-loader css-loader file-loader html-loader html-webpack-plugin style-loader url-loader

Babel 설치

바벨을 설치해줍니다.

npm install --save-dev @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript

Babel 세팅

.babelrc 파일을 만들어줍니다.

//.babelrc
{
  "presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript"]
}

tsconfig.json 세팅

터미널에 다음 명령어로 tsconfig.json 파일을 생성해줍니다.

tsc --init

tsconfig.json 파일은 프로젝트를 컴파일 하는 방법에 대한 옵션을 설정할 수 있습니다.

//tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "lib": ["dom", "ES2015", "ES2016", "ES2017", "ES2018", "ES2019", "ES2020"],
    "allowJs": true,
    "jsx": "react",
    "outDir": "./dist",
    "isolatedModules": true,
    "strict": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}
옵션설명
compilerOptions컴파일 옵션을 정의
target컴파일된 코드가 es5 환경에서 실행되도록 정의
module컴파일된 코드가 어떤 모듈 시스템을 사용할지 정의
lib현재 프로젝트에서 사용할 수 있는 특정 기능에 대한 문법(타입)을 추가
allowJsjs파일을 허용
jsxpreserve, react-native, react, react-jsx, react-jsxdev와 같은 jsx코드 생성을 지정
outDir컴파일된 파일이 어디에 저장될지 경로를 정함
isolatedModules각 파일을 별도의 모듈로 변환
strict모든 타입 체킹 옵션 활성화
esModuleInteropcommonjs 모듈 형태로 이루어진 파일을 es2015 모듈 형태로 불러올 수 있게 해줌
forceConsistentCasingInFileNames동일한 파일에 대해 대소문자가 일치하지 않는 참조를 허용하지 않음
include어떤 파일을 컴파일할 것인지 설정
exclude어떤 파일을 컴파일에서 제외할 것인지 설정
  1. target: () => return 'a'같은 es6문법으로 작성된 코드를 function() return 'a'같은 es5 문법으로 컴파일 해줍니다.
  2. module: commonjs으로 설정하면 export default App이라는 코드는 export.default = App로 변환됩니다. es2015로 설정하면 export default App 코드가 그대로 유지됩니다.
  3. lib: 타입스크립트가 프로젝트에서 사용할 수 있는 특정 기능에 대한 문법(타입)을 알게 되는 것 뿐이지 runtime에 해당 기능을 추가해주는 것이 아님을 주의해야 합니다.

저는 제가 원하는 옵션만 활성화 해줬지만, tsconfig에는 훨씬 많은 옵션을 설정할 수 있습니다. tsc --init으로 tsconfig.json 파일을 생성했다면 파일 안에 사용할 수 있는 옵션들과 설명이 적혀있습니다. 읽어보시고 원하는 옵션이 있다면 활성화해서 사용하세요!

Webpack 세팅

폴더에 webpack.config.js 파일을 만들어줍니다. 만든 파일에 아래의 코드를 입력해주세요.

//webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'production',
  entry: './src/index.tsx',
  output: {
    path: path.join(__dirname, 'build'),
    filename: '[name].[contenthash].js',
    chunkFilename: '[name].bundle.js',
    publicPath: '/',
  },
  module: {
    rules: [
      {
        test: /\.(ts|js)x?$/,
        exclude: /nodeModules/,
        use: {
          loader: 'babel-loader',
        },
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/, //폰트 파일이 로더될 수 있도록 함
        use: [
          {
            loader: 'file-loader',
            options: {
              name: 'fonts/[name]-[hash].[ext]',
            },
          },
        ],
      },
      {
        test: /\.(png|svg|jpe?g|gif)$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: false,
            name: 'images/[name]-[hash].[ext]',
          },
        },
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: 'html-loader',
          },
        ],
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
    ]
  },
    resolve: {
    extensions: ['.tsx', '.ts', '.js', '.json'],
  },
  plugins: [new HtmlWebpackPlugin({ template: './public/index.html' })],
}
이름설명
output파일이 번들되면 어디로 보낼지 설정하는 옵션
path번들 파일이 저장될 디렉토리 이름
filename웹팩 실행 후 생성된 새로운 번들 파일에 대해 설정할 이름
chunkFileChunkFile의 이름을 설정
pulicPath어플리케이션의 기본 경로 설정
module파일 번들링 규칙을 지정하는 옵션
rules모듈이 생성되는 방식을 수정
test특정 로더의 대상이 되어야 하는 파일 확장자
exclude번들러가 무시해야 하는 파일 지정
loader사용할 로더 종류
배열로 작성하면 배열의 순서대로 실행됨
resolve모듈 해석에 대한 설정
extensions확장자를 순서대로 해석함
pluginsplugin을 추가할 수 있음
HtmlWebpackPlugin웹팩이 html 파일 템플릿을 알 수 있도록 하는 플러그인
  1. extension: 여러 파일에서 이름이 동일하지만 다른 확장자를 가진 경우, 배열의 앞에서부터 파일을 해석하고 남은 것은 해석하지 않음

저는 개발용 웹팩 설정을 따로 만들어 주는게 더 편해서 파일을 하나 만들어 주도록 하겠습니다.
webpack.config.dev.js라는 이름으로 만들었습니다.

//webpack.config.dev.js
const path = require('path');
const HtmlWebPackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'development',
  entry: './src/index.tsx',
  output: {
    filename: '[name].[contenthash].js',
    chunkFilename: '[name].bundle.js',
    publicPath: '/',
    path: path.resolve(__dirname, 'build'),
  },
  devtool: 'inline-source-map',
  devServer: {
    https: true,
    host: 'localhost',
    compress: true,
    hot: true,
    port: 3000,
    open: true,
    client: {
      progress: true,
    },
  },
  stats: {
    cachedModules: false,
  },
  module: {
    rules: [
      {
        test: /\.(ts|js)x?$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: 'fonts/[name]-[hash].[ext]',
            },
          },
        ],
      },
      {
        test: /\.(png|svg|jpe?g|gif)$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: false,
            name: 'images/[name]-[hash].[ext]',
          },
        },
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: 'html-loader',
          },
        ],
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js', '.json'],
  },
  plugins: [new HtmlWebPackPlugin({ template: './public/index.html' })],
};
이름설명
devtool소스 맵이 생성되는지 여부와 생성 방법을 제어
inline-source-map원본 소스와 난독화된 소스를 매핑
devServerwebpack-dev-server의 동작을 변경할 수 있는 옵션
httpshttps를 사용할지 http를 사용할지 설정
hosthost 이름 설정
compress제공되는 모든 항목에 대해 gzip 압축 활성화
hot웹팩으로 빌드한 결과물이 웹 애플리케이션에 실시간으로 반영될 수 있게 하는 설정
portport 번호 설정
open서버가 시작된 후 브라우저(예, 크롬)을 열도록 하는 옵션
progress브라우저에서 컴파일 진행률을 백분율로 보여줌
stats표시되는 번들 정보를 제어할 수 있는 옵션
cachedModules빌드되지 않고 캐시된 모듈에 대한 정보를 추가하지 않음

두 파일을 모두 작성이 끝나면 package.json 파일 script에 다음 코드를 작성해 줍니다.

//package.json
  "scripts": {
    "build": "webpack --config webpack.config.js",
    "start": "webpack serve --config webpack.config.dev.js",
  },

React 파일 추가

폴더에 public 폴더를 만들어 주고 그 안에 index.html을 작성해 줍니다.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, inital-scale=1.0" />
    <title>React using webpack5 but without CRA</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

src 폴더를 만들어 주고 그 안에 index.tsx와 App.tsx파일을 작성해 줍니다.

//index.tsx
import React from 'react';
import ReactDom from 'react-dom';
import App from './App';

ReactDom.render(<App />, document.getElementById('root'));
//App.tsx
import React, { useState } from 'react';

function App() {
  const [click, setClick] = useState('');
  const clickButton = () => {
    setClick('click');
  };

  return (
    <>
      <p>Hello, World!!!!!</p>
      <button onClick={clickButton}>button</button>
      {click}
    </>
  );
}

export default App;

완성된 폴더 구조

앱 실행🚀

터미널에 npm start를 입력하여 앱을 실행 해줍니다.

npm start

앱이 정상적으로 실행되었습니다!✨


참고
https://velog.io/@thyoondev/CRA%EC%97%86%EC%9D%B4-React-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0Webpack5
https://velog.io/@xortm854/Typescript-React-Webpack-%ED%99%98%EA%B2%BD%EC%84%A4%EC%A0%95-4%ED%8E%B8-Webpack-%EC%84%A4%EC%A0%95%EC%9D%84-%ED%95%B4%EB%B3%B4%EC%9E%90
https://joshua1988.github.io/web-development/webpack/caching-strategy/
https://webpack.js.org/

잘못된 부분이 있으면 댓글로 남겨주시면 감사하겠습니다.👍

profile
프론트엔드 개발자 Frontend dev

0개의 댓글