Javascript/React

[React] Spring Boot with React 채팅 서버 : 1. webpack 설정하기

noahkim_ 2022. 3. 9. 00:33

플랫폼 API 서버에 채팅 기능을 확인해보기 위해 프론트를 구현하였다.

저는 백엔드만 해오다가 토이프로젝트에 프론트가 필요해서 하게 되었는데 처음이라 발등에 불이 떨어져 해보게 되었다.

코딩하는데 생활코딩과 인프런에 올라와있는 조현영님의 slack clone강의를 많이 참고하였다.

프론트에서는 설정할게 많은것 같다. 실제 강의에서도 설정이 힘들다 하셨고 따라하는데 한참걸렸다..
(하지만 되니까 기분은 좋네 ㅎ)

아무튼 짧은 실력이지만 최대한 꼼꼼히 포스팅 해봐야겠다

1. 프론트엔드 초기 세팅하기

설치 모듈

프로젝트에서는 typescript를 사용할 것이다.

  • react, react-dom
  • typescript, @Types/react, @Types/react-dom
  • package-lock.json
    • 모듈들이 transitive하게 의존하고 있음
    • 서로 의존관계가 버전에 따라 가지고 있음
      • 각각의 모듈들이 의존하는 모듈의 버전을 적어줌

코드 작성시 helper 모듈

  • eslint
    • 코드 검사 도구
      • 안쓰고 있는 변수, 오타 검사
    • .eslintrc
      • eslint 설정파일 (따로 코드 적을것 없이 생성만 해주면 됨)
  • prettier
    • 코드를 자동 정렬해주는 도구
    • 정렬해주는 스타일을 커스터마이징할 수 있는 범위가 좁음
    • .prettierrc
      • prettier 설정파일 (따로 코드 적을것 없이 생성만 해주면 됨)
  • eslint, prettier 를 서로 연결해서 사용하면 좋음
    • eslint-plugin-prettier, eslint-config-prettier
  • tsconfig.json
    •  typescript 컴파일시 세부설정 코드
      • ts 파일들을 .js 파일로 변환할 때 어떻게 변환할것인지 세부설정이 가능함
    • {
        "compilerOptions": {
          "esModuleInterop": true, // import 형식으로 모듈 가져오기 (import React from 'react';)
          "sourceMap": true, // 에러 발생시 map으로 에러 정보 리턴
          "lib": [
            "ES2020",
            "DOM"
          ],
          "jsx": "react", // 사용하는 jsx 모듈 지정
          "module": "esnext",
          "moduleResolution": "Node",
          "target": "es5", // 변환할 형식
          "strict": true, 
          "resolveJsonModule": true, // import json 허가
          "baseUrl": ".",
          "paths": { // 편하게 import 하기 위해 경로에 별명을 지어줌
            "@hooks/*": [ "hooks/*" ],       
            "@components/*": ["components/*"],      
            "@layouts/*": ["layouts/*"],
            "@pages/*": ["pages/*"],
            "@utils/*": ["utils/*"],
            "@typings/*": ["typings/*"]
          }
        }
      }

2. babel과 webpack 설정하기

babel

  • ES6+ 버전 이상의 js, jsx, ts, tsx를 하위버전의 js로 변환시켜 어떠한 브라우저에서라도 호환되도록 하는 역할
  • frontend 작업시에 사용되는 html, css, image 등등의 파일을 모두 jsx로 바꿔주므로 데이터 타입이 같아지는 효과를 얻음
  • 설치모듈 : webpack, @babel/core, babel-loader, @babel/preset-env, @babel/preset-react

wepback

  • 모듈 번들러
    • 여러개의 모듈을 하나의 파일로 묶어 내보내줌
  • 기본구조
    • Bundle : 참조관계에 있는 모듈을 모아 하나의 파일로 묶어줌
    • Entry : 각 모듈간 참조관계를 해석해 의존성 그래프를 만듬
    • Output : 만들어진 의존성관계를 토대로 번들과정을 거치면 Output에 설정된 정보를 기반으로 번들된 파일이 생성됨 
    • Mode : 모드키로 빌드환경을 구분지을 수 있는 기능을 제공함
    • Loader : 웹팩은 모든 파일을 모듈로 관리하므로 js 뿐만아니라 이미지, 폰트 등이 전부 모듈이다. 
                     따라서 js가 아닌 파일을 웹팩이 이해할 수 있도록 변경하는 역할을 로더가 맡는다
    • Plugin : 웹팩의 기본적인 동작 외 추가적인 기능을 제공하는 속성. 주로 결과물의 형태를 바꾸는 역할을 함
  • 해당 프로젝트에서는 typescript를 javascript로 바꾸어주는 역할도 해주어야 함 
  • webpack.config.ts
import path from 'path';
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
import webpack, {Configuration as WebpackConfiguration} from "webpack";
import {Configuration as WebpackDevServerConfiguration} from "webpack-dev-server";
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
import WebpackDevServer from 'webpack-dev-server';

declare module 'webpack' {
    interface Configuration {
        devServer?: WebpackDevServer.Configuration;
    }
}

const isDevelopment = process.env.NODE_ENV !== 'production'; // 환경변수의 모드값에 따라 개발환경이 달라지도록 하였음

const config: Configuration = {
    name: 'hcs',
    mode: isDevelopment ? 'development' : 'production',
    devtool: isDevelopment ? 'hidden-source-map' : 'inline-source-map',
    resolve: {
        extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'], // babel이 변환해줄 확장자 목록
        alias: { // 코드에서 사용될 별명들을 webpack에게 명시해준다. 해당 값들은 tsconfig에서 설정한 값과 대응되어야 함
            '@hooks': path.resolve(__dirname, 'hooks'),
            '@components': path.resolve(__dirname, 'components'),
            '@layouts': path.resolve(__dirname, 'layouts'),
            '@pages': path.resolve(__dirname, 'pages'),
            '@utils': path.resolve(__dirname, 'utils'),
            '@typings': path.resolve(__dirname, 'typings'),
        },
    },
    entry: { // 결과물의 이름을 적어준다. 여러개로 결과물에 이름을 붙여 적을 수 있다.
        app: './client',
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/, // babel이 변환할 파일의 형식.
                loader: 'babel-loader',
                options: {
                    presets: [ // 변환 시 babel이 신경쓰도록 켜주는 설정
                        [
                            '@babel/preset-env',
                            {
                                targets: {browsers: ['IE 10']}, // browser의 값에 호환될 수 있도록 변환함
                                debug: isDevelopment,
                            },
                        ],
                        '@babel/preset-react',
                        '@babel/preset-typescript',
                    ],
                    env: {
                        development: {
                            plugins: [require.resolve('react-refresh/babel')],
                        },
                    },
                },
                exclude: path.join(__dirname, 'node_modules'),
            },
            {
                test: /\.css?$/,
                use: ['style-loader', 'css-loader'], // css를 js로 변환할때 사용
            },
        ],
    },
    plugins: [
        new ForkTsCheckerWebpackPlugin({ // 타입스크립트를 사용할 경우 쓰임
            async: false,
        }),
        new webpack.EnvironmentPlugin({NODE_ENV: isDevelopment ? 'development' : 'production'}), // react에서 NODE_ENV를 사용할 수 있도록 지원
    ],
    output: { // 번들링된 파일의 형식 및 결과물에 대해 설정
        path: path.join(__dirname, 'dist'),
        filename: '[name].js', // entry에서 적은 값이 name으로 주입됨
        publicPath: '/dist/',
    },
    devServer: {
        historyApiFallback: true,
        port: 3090,
        devMiddleware: {publicPath: '/dist/'},
        static: {directory: path.resolve(__dirname)},
    },
};

if (isDevelopment && config.plugins) {
    config.plugins.push(new webpack.HotModuleReplacementPlugin());
    config.plugins.push(new ReactRefreshWebpackPlugin({
        overlay: {
            useURLPolyfill: true
        }
    }));
}

export default config;

 

3.  웹팩 데브 서버 세팅하기

  • 코드의 변경사항을 감지하여 브라우저에 변경된 점을 자동으로 반영해 줌
  • 빠른 실시간 리로드 기능을 갖춘 개발서버로 메모리 컴파일을 사용하므로 컴파일이 빠름
  • 소스 파일이 변경될 경우 변경된 모듈만 새로 번들링하고 브라우저에 전송
  • 브라우저는 변경을 인지하고 세로고침되어 변경사항이 반영된 페이지를 로드함
  • package.json의 scripts에 실행 명령을 정의하여 사용
  "scripts": {
    "dev": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack-config.json\" webpack serve --env development"
  }

 

4. tsconfig-for-webpack-config.json

  • webpack 설정에 맞게 별도의 typescript 설정을 만듬
{
  "compilerOptions": {
    "module": "commonjs",
    "moduleResolution": "Node",
    "target": "es6",
    "esModuleInterop": true
  }
}