본문 바로가기
REACT

CRA 없이 리액트 세팅하기

by 해-온 2023. 7. 4.

 

레벨 3 프로젝트에서는 CRA 없이 react를 세팅해야 했다.

우테코 시작 전에는 react를 설치할 땐 무조건 CRA 방법밖에 없는 줄 알았던 나...

이번을 기회로 CRA 없이 리액트를 세팅해 보기로 했다.

 

잠깐! CRA는 무엇이며, 장단점은 무엇일까?

CRA는 'Create React App'의 준말로 React 기반의 프론트엔드 웹 애플리케이션을 빠르게 구축하는데 도움을 주는 툴이다.

CRA를 사용하면 React 개발 환경을 쉽게 설정하고 복잡한 설정이나 빌드 작업을 없이 시작할 수 있다.

다만, 사용하지 않는 라이브러리가 같이 설치되고, 초기 번들 크기가 크다.

또, 자기 입맛대로 커스터마이징 하기에 제한이 있다.

 

어떤 걸 개발 의존성으로 설치해야 할까부터

평소에 무슨 의미인지 몰랐던 설정까지 하나하나 뜯어보느라 쉽지 않았다.

 

그 과정을 아래에 적어보며 다시 정리해보려 한다.

 

(연습용 저장소는 'npm'으로, 본 프로젝트는 'yarn'으로 했으나 본 글에서는 연습용 저장소 기준인 'npm'으로 작성해 보겠다.)


 

먼저, package.json을 생성한다.

 

npm init -y

 

다음으로는 react를 설치한다.

 

npm install react react-dom

 

그다음 TypeScript로 개발을 한다면 관련된 것을 설치한다.

나는 TypeScript를 개발 의존성으로 설치하였다.

 

npm install -D typescript @types/react @types/react-dom

 

webpack을 설치한다.

 

여기서 webpack-cli란 webpack을 명령 줄 인터페이스(Command Line Interface)에서 사용할 수 있게 해주는 도구이다.

webpack-cli를 사용해 터미널에서 webpack 명령을 실행할 수 있다.

 

npm install -D webpack webpack-cli

 

추가로 webpack과 관련된 것을 더 설치할 수 있다.

 

webpack-dev-server는 webpack을 사용하는 애플리케이션에서 실시간 리로딩을 지원하는 개발용 웹 서버이다.

웹 페이지를 자동으로 새로고침해주는 기능이 있어, 코드를 수정하고 저장할 때마다 바로 변경 사항을 볼 수 있다.

 

html-webpack-plugin은 webpack을 사용하는 애플리케이션에서 HTML 파일을 생성하고 관리하는데 도움을 주는 플러그인이다.

webpack 빌드 과정에서 자동으로 HTML 파일을 생성하고, 생성된 HTML에 자동으로 번들된 JavaScript와 CSS 파일을 삽입한다.

 

마지막으로 ts-loader의 경우 webpack에서 TypeScript 코드를 JavaScript로 변환하는 데 사용하는 로더이다.

webpack은 JavaScript 모듈 번들러이기 때문에 TypeScript 코드를 JavaScript로 변환해야 한다.

이 과정에서 ts-loader가 유용하게 사용된다.

 

npm install -D webpack-dev-server html-webpack-plugin ts-loader

 

이렇게 webpack에 관한 설치를 다 끝냈다면 webpack을 설정해야 한다.

webpack.config.js를 만드는데, 우리 팀은 개발 환경과 프로덕션 환경을 분리했기 때문에 파일 또한 따로 만들어주었다.

 

먼저, 두 환경 공통으로 사용되는 부분을 webpack.common.js로 만들었다.

 

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.tsx',
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js',
    clean: true,
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js'],
    alias: {
      '@': path.resolve(__dirname, './src'),
      '@components': path.resolve(__dirname, './src/components'),
    },
  },
  module: {
    rules: [
      {
        test: /\.(ts|tsx|js)$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'ts-loader',
          },
        ],
      },
      {
        test: /\.(png|jpeg|jpg)$/,
        type: 'asset/resource',
      },
    ],
  },
};

 

  • entry: webpack 빌드의 시작점을 지정한다. 여기서는./src/index.tsx 파일이 시작점이다.
  • output: webpack 빌드 결과물의 설정을 지정한다.
    • path: 빌드 결과물이 저장될 디렉터리를 지정한다. 여기서는 dist 폴더에 결과물이 저장된다.
    • filename: 빌드 결과물의 파일 이름을 지정한다. 여기서는 bundle.js로 설정된다.
    • clean:true: webpack 빌드 이전에 생성된 결과물을 자동으로 삭제한다.
  • resolve: webpack에서 파일 경로를 해석하는 방법을 설정한다.
    • extensions: ['ts', 'tsx', 'js']: webpack이 해석할 수 있는 파일 확장자를 나열한다.
    • alias: 설정한 경로의 별칭을 지정한다. 이를 사용해 코드 내에서 짧은 경로로 참조할 수 있다.
  • module: 로더를 설정한다.
    • rules: 로더를 설정하는 배열이다.
      • test: 로더가 처리할 파일 유형을 지정한다.
      • exclude: 로더에서 제외할 파일 또는 폴더를 지정한다.
      • use: 사용할 로더를 지정하는 배열이다.

 

다음은 dev 환경에서 실행될 webpack.dev.js 설정을 해 준다.

 

const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = merge(common, {
  mode: 'development',
  devtool: 'eval',
  devServer: {
    historyApiFallback: true,
    port: 3000,
    hot: true,
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
      minify: false,
      hash: true,
    }),
  ],
});

 

  • module.exports = merge(common, {... }): webpack 설정을 내보낸다. common과 해당 파일을 병합해 내보낸다.
  • mode: 모드를 설정할 수 있다. 여기서는 'development'로 개발 모드이다.
  • devtool: webpack에서 sourceMap을 생성하는 방식을 설정하는 옵션이다. sourceMap은 빌드된 코드와 원본 소스 코드 사이의 매핑을 제공하여 디버깅을 더 쉽게 할 수 있도록 도와준다. 
  • devServer: webpack 개발 서버의 설정을 지정한다.
    • historyApiFallback:true: SPA에서 404 응답을 index.html로 리다이렉션 하도록 설정한다.
    • port: 개발 서버가 구동될 포트를 지정한다.
    • hot:true: 개발 서버에서 Hot Module Replacement를 활성화한다. 변경 사항이 발생하면 페이지 전체를 새로고침하지 않고 특정 모듈만 변경하여 개발 효율성을 높인다.
  • plugins: webpack 플러그인을 설정하는 배열이다.
    • HtmlWebpackPlugin: webpack 번들을 자동으로 HTML 파일에 주입해 준다.

 

이제 프로덕션 환경 세팅을 해 준다.

파일명은 webpack.prod.js이다.

 

const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = merge(common, {
  mode: 'production',
  devtool: 'hidden-source-map',
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true,
      },
      hash: true,
    }),
  ],
});

 

프로덕션 환경에서의 devtool은 hidden-source-map으로 되어있는데,

이는 빌드 결과물에 sourceMap이 포함되지 않게 해 사용자에게 노출되지 않게 해준다.

또한, HtmlWebapckPlugin collapseWhitespace와 removeCommnets 설정을 통해 빌드 시 공백과 주석을 제거해 준다.

 

 

마지믹으로 webpack을 실행시켜 줄 script를 추가한다.

package.json의 scripts에 (없으면 작성) 추가해 준다.

 

"scripts": {
  "start": "webpack serve --open --config webpack.dev.js",
  "build": "webpack --config webpack.prod.js"
}

 

이제 tsconfig.json을 설정한다.

(babel-loader와 ts-loader 중 어느 것을 설치해야 할지 고민이 많았는데, 최신 브라우저에서는 ECMAScript를 지원하기 때문에 현재 상황에서는 도입하지 않기로 했다. 나중에 필요한 상황이 오면 그때 다시 고민해 보도록 하자.)

 

{
  "compilerOptions": {
    "target": "es6",
    "lib": ["dom", "dom.iterable", "esnext"],
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true,
    "jsx": "react-jsx",
    "outDir": "./dist",
    "baseUrl": ".",
    "paths": {
      "@*": ["src/*"]
    }
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}

 

  • compilerOptions: TypeScript 컴파일러에 대한 옵션을 설정한다.
  • target: JavaScript 코드의 ECMAScript 버전을 ES6로 설정한다.
  • lib: TypeScript 프로젝트에서 사용되는 전역 라이브러리 파일을 지정한다.
  • esModuleInterop:true: ES 모듈과 CommonJS 모듈 간의 호환성을 용이하게 한다.
  • module:ESNext: 프로젝트에서 사용하는 모듈 시스템을 설정하는 역할을 한다.
    • ESNext: 가장 최신의 ECMAScript 표준 모듈 시스템으로 최신 웹 브라우저 대부분에서 지원된다. 트리 쉐이킹 등 최적화 기능을 사용할 수 있다.
  • moduleResolution: 모듈을 해석하고 가져올 때 사용하는 알고리즘 방식을 설정하는 옵션이다.
  • resolveJsonModule: JSON을 import 하여 사용할 수 있도록 한다.
  • forceConsistentCasingFileNames: 파일 이름의 대소문자 일관성을 강제한다.
  • strict: TypeScript 코드의 타입 검사를 엄격하게 수행하도록 한다.
  • skipLibCheck: 선언 파일(*. d.ts)에 대한 타입 검사를 건너뛰도록 설정한다.
  • jsx: TypeScript 파일 내에서 JSX 문법을 사용하는 방식을 설정한다.
    • preserve: jsx를 출력 파일에 그대로 보존한다. babel과 같은 다른 변환 단계에서 추가로 사용 가능하다.
    • react: React.createElement로 출력한다.
    • react-jsx: JSX를 React.jsx로 변환한다. React 17 이상에서 사용하는 새로운 JSX 변환 방식을 적용한다.
  • outDir: 컴파일된 JavaScript 파일들을 출력할 디렉터리를 지정한다.
  • baseUrl: 모듈 이름을 처리할 기준 디렉터리를 지정한다.
  • paths: 프로젝트 내에 경로를 재정의한다.
  • include: TypeScript 컴파일러가 컴파일 과정에서 포함할 파일이나 디렉터리를 지정한다.
  • exclude: TypeScript 컴파일러가 컴파일 과정에서 제외할 파일이나 디렉터리를 지정한다.

 

prettier를 설정해 준다.

. prettierrc 파일을 만든 후 팀별 스타일을 정의한다.

 

{
  "printWidth": 120,
  "singleQuote": true,
  "endOfLine": "auto",
  "semi": true,
  "tabWidth": 2
}

 

  • printWidth: 한 줄의 최대 글자 수를 설정한다.
  • singleQuote: 문자열에 작은따옴표를 사용하도록 설정한다.
  • endOfLine: 줄 바꿈으로 사용할 문자를 자동으로 결정하도록 설정한다.
  • semi: 문장 끝에 세미콜론을 사용하도록 설정한다.
  • tabWidth: 들여 쓰기 크기를 설정한다.

 

이제 설치는 모두 끝났다.

마지막으로 폴더 설정만 하면 된다.

 

src 폴더를 만들고 그 안에 index.tsx 파일을 생성한다.

 

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

 

그리고 src 폴더 안에 App.tsx 파일을 생성한다.

 

const App = () => {
  return <></>;
};

export default App;

 

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>Document</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

 

이제 npm start를 터미널에 입력해 리액트를 실행시켜 보자.

제대로 작동하면 끝!!!

 

'REACT' 카테고리의 다른 글

React Hooks란?  (0) 2024.01.29
React에서 shape divider color-black으로 나올 때 사용법  (0) 2021.12.24
REACT favicon 변경  (0) 2021.12.05
REACT 이미지 올리기 <img src...>  (0) 2021.12.05
Router  (0) 2021.12.01

댓글