React + TypeScript + Webpack Without CRA

Eamon·2021년 7월 6일
4

ReactStudy

목록 보기
2/3
post-thumbnail

CRA 가 편하잖아? 왜 없이 해보려는 건데?

처음에 해보려했던 이유는 모두가 한 번씩 해보길래 따라서 해봐야지.. 라는 생각에서 출발했습니다. 그러나 한 번 해보고 나서 이렇게 해보는게 여러가지 생각을 해보게 하는 트리거가 되게 끔 한다는 것을 알았습니다. 또한 무거운 CRA 보다는 가볍고 스스로가 원하는 대로 커스텀한 webpack 을 만들어서 배포와 개발을 진행할 수 있다는 것을 느꼈습니다.

위에서 말한 여러가지 생각들을 공유해보려합니다.

Webpack & babel & loader

여러 프레임워크를 쓸때 우리도 모르게 이 삼총사들의 도움을 받고있습니다. 그러나 이들은 프레임 워크를 쓰는 사용자 입장에서는 알수없도록 물 밑에서 작동하고 있기때문에 react 만 써보신 분이라면 각각이 어떤 역할을 하는지 알아채기 어려울 것입니다.

  1. webpack

    • 공식 문서에는 모듈 번들러 라고 설명이 되어있습니다.
    • 모듈 번들러라는 말을 모듈 + 번들러로 쪼개서 이해해 보면, 우리는 성격이 비슷한 기능들을 하나의 의미 있는 파일로 관리하는 단위를 모듈이라고 합니다. 또, bundle 이라는 뜻은 묶음 이라는 의미를 가지고 있습니다. 풀어서 설명하면, 파일들을 하나로 병합하거나 묶어주는 녀석이라는 뜻을 유추해 볼 수 있겠네요!
    • 실제로 위에서 제가 유추한 뜻과 비슷한 일을 하는 녀석입니다. webpack공식 문서에서는 webpack 을 웹 애플리케이션을 구성하는 자원(HTML, CSS, Javscript, Images 등)을 모두 각각의 모듈로 보고 이를 조합해서 병합된 하나의 결과물을 만드는 도구 라고 정의하고 있습니다.
    • 모듈 번들러로는 Webpack, Rarcel, Rollup 등 다양한 종류가 있습니다.

    빌드, 번들링, 변환 이 세 단어 모두 같은 의미입니다.

  2. babel

    • babel은 webpack 과 다르게 트랜스파일러입니다.

    • 트랜스 파일러는 말그대로 트랜스(Trans) + piler 변환 해주는 도구입니다.

    • 브라우져 마다 지원하는 js의 버젼이 다르기 때문에 JSX 나 ES6+ 로 작성된 JS 코드들을 ES5코드로 변환 하는 과정이 필요합니다. 그 역할을 해주는 것이 트랜스파일러 이며 그 중에 하나가 babel 입니다.

  3. loader

    • loader 의 역할은 json 과 js 밖에 해석하지 못하는 webpack 을 위해서 css 나 HTML 등 다른 자원들을 변환 할 수 있도록 하는 속성입니다.

    • test : 로더를 적용할 파일 유형 (일반적으로 정규 표현식 사용)

    • use : 해당 파일에 적용할 로더의 이름

    • babel-loader

      • webpack에 babel 을 이용해서 js를 바꾸고 번들하도록 하는 loader

dependencies와 devDependencies의 차이점

dependencies와 devDependencies의 차이점은 실제 상품에서 사용할 패키지와 개발용 패키지의 차이이다.

즉, 개발 시 필요한 라이브러리들은 devDependencies에 적어주고, (개발자가 필요한것)

진짜 기술스펙으로 사용되어야할 라이브러리들은 dependencies에 설치해준다.

즉, 어떤 Library가 프로젝트의 컴파일(빌드) 타임에 필요하면, devDependencies에 넣고, 런타임에도 계속 쓰이는 것이면 dependencies에 넣는다.

webpack + tsconfig + babel.config 설정

1. 프로젝트를 생성할 파일을 만들어줍니다.

mkdir {프로젝트 이름}
cd {프로젝트 이름}

npm init -y // package.json 생성

2. 프로젝트 에 필요한 패키지를 설치합니다.

npm install --save -D webpack webpack-dev-server webpack-cli html-webpack-plugin// webpack 

npm install --save -D babel-loader @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript //babel
npm install --save react react-dom //react
npm install --save @types/react @types/react-dom //typescript

3. tsconfig.json , webpack.config.js, babel.config.js 생성

  • tsconfig.json
tsc --init // 타입스크립트 전역으로 설치시
{
  "compilerOptions": {
    "outDir": "./dist",
    "target": "es5",
    "module": "esnext",
    "jsx": "react",
    "noImplicitAny": true,
    "allowSyntheticDefaultImports": true,
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
  },
  "include": [
    "src"
  ]
}
  • babel.config.js
module.exports = {
  presets: ['@babel/preset-react', '@babel/preset-env', '@babel/preset-typescript'],
};
  • webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const mode = process.env.NODE_ENV || 'development';

module.exports = {
  mode,
  devServer: {
    historyApiFallback: true,
    inline: true,
    port: 3000,
    hot: true,
    publicPath: '/',
  },
  entry: {
    app: path.join(__dirname,  'index.tsx'),
  },
 
  resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx'],
  },

  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: ['babel-loader', 'ts-loader'],
      },
    ],
  },

	output: {
    path: path.join(__dirname, '/dist'),
    filename: 'bundle.js',
  },

  plugins: [
		new webpack.ProvidePlugin({
      React: 'react',
    }),
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
    new webpack.HotModuleReplacementPlugin(),
  ],
};

webpack-dev-server : 웹팩 데브 서버로 빌드한 결과물이 파일 탐색기에서 보이진 않지만 정상적으로 애플리케이션에 로딩되어 돌아도록 합니다. CRA 에서 start 를 입력해도 번들된 파일이 생성되지 않는 이유가 이녀석 때문이죠.

 devServer: {
    historyApiFallback: true,
    inline: true,
    port: 3000,
    hot: true,
    publicPath: '/',
  },

위의 조건들을 변경하면서 dev 서버 환경을 바꿀 수 있습니다.

HtmlWebpackPlugin : index.html 템플릿을 기반으로 빌드 결과물을 추가해 주기위한 plug-in 입니다.

entry : webpack 이 코드를 번들링하기 위해서 알아야하는 복잡하게 얽힌 코드들의 맨 처음 시작점

output: 번들링한 결과물 파일이름과 위치 설정

module : 다양한 로더들을 불러올수 있는 곳입니다. test 는 로더를 적용할 파일 유형 (일반적으로 정규 표현식 사용) 을 적고 use 에는 해당 파일에 적용할 로더의 이름을 적습니다.

4. 리액트 entry file 설정

위의 webpack 의 엔트리 설정해준 것에 따라서 파일을 생성하고 만들어줍니다.

index.tsx

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

 
ReactDOM.render( 
 <React.StrictMode> 
  <div>요호</div>
  <App/>
 </React.StrictMode>,
 document.getElementById('root') 
);
 

App.tsx

import React from 'react'

function App() {
    return (
        <div>~
        </div>
    )
}

export default App

index.html

<!DOCTYPE html>
<html lang="en">
  <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>   

index.html에는 반드시 root라는 id값을 가진 div를 생성해 줘야 한다.

Babel 설정

5. package.json 의 scripts 수정

"scripts": {
    "dev": "webpack server --mode development --open --hot",
    "build": "webpack --mode production",
    "prestart": "cross-env NODE_ENV=production npm run build",
    "start": "webpack --mode development"
  },
  • dev 서버와 배포 서버가 나누어지는 이유
    • React의 개발 모드는 버그로 이어질만한 많은 부분을 미리 경고해주는 검증 코드가 포함되어 있다. 하지만, 이런 코드는 번들 크기를 증가시키고 앱 속도를 느리게 할 수 있다.
    • 개발모드에서의 느린 앱 속도는 문제가 되지 않는다. 개발모드에서 느리게 수행되는 코드는 개발자의 빠른 장비와 일반 기기 사이의 성능 차이를 줄일 수 있어 도움이 될 수도 있다.
    • 배포이후에 속도가 빨라지는 이유는 이러한 이유!

참고 : https://ui.toast.com/weekly-pick/ko_20191212

  • cross-env ?

보통 nodeJS 에서 NODE_ENV 의 env 변수를 조작해서 dev 모드와 production 를 구분하게 되는데 윈도우는 scripts 명령어로 env 변수를 바꿀수 없기때문에 설치하는 모듈이다.

npm run dev

를 실행하면 localhost:3000 에서 dev 서버가 열립니다.

profile
Steadily , Daily, Academically, Socially semi-nerd Front Engineer.

0개의 댓글