bluegram - 프론트 초기 세팅

박상은·2021년 12월 15일
1

🍃 blegram

목록 보기
7/20

프론트엔드쪽 코드 초기 세팅

1. util

딱히 중요한 부분은 아니고 직접 만들었던 시간 변환, 날짜 변환, 유효성 검사 등의 기능을 제공해 주는 함수들을 모아놓은 폴더입니다.
물론 좋은 라이브러리들이 많지만 실제로 한번 만들어서 사용해 보고 싶어서 만들어 놓고 보니 그냥 계속 사용하고 있습니다.

실질적으로 중요한 코드도 아니고 길이만 길어서 GitHub링크로 대체하겠습니다.

2. eslint / prettier

코드 스타일 정렬 도구 설정입니다.
지금은 초기 단계라 기본적인 설정만 해뒀고 개발하면서 추가할 사항들을 차례로 업데이트할 생각입니다.

.prettierrcjson으로 만든 이유는 js로 하면 자동완성을 지원 안 해줘서 json으로 만들었습니다.

module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 12,
    sourceType: "module",
  },
  extends: [
    // eslint와 prettier가 충돌나는 부분 비활성화 ( eslint-config-prettier )
    "prettier",
  ],
  plugins: [
    // prettier 규칙을 eslint에 적용시키게 해줌 ( eslint-plugin-prettier )
    "prettier",

    // ES2015의 import/export 구문 지원 ( eslint-plugin-import )
    "import",

    // React관련 eslint 설정 지원 ( eslint-plugin-react )
    "react",
  ],
  rules: {
    // prettier 규칙을 어기면 error 발생
    "prettier/prettier": ["error"],
  },
};
{
  "singleQuote": false,
  "semi": true,
  "useTabs": false,
  "tabWidth": 2,
  "trailingComma": "all",
  "printWidth": 120,
  "bracketSpacing": true,
  "arrowParens": "avoid",
  "endOfLine": "auto"
}

3. react-router-dom

react-router-domreact-router에서 DOM에 필요한 컴포넌트만 뺀 라이브러리입니다.
v6의 <BrowerRouter>, <Routes>, <Route>를 사용했습니다.

시작하고 나서 v6으로 업데이트 된 걸 알아서 공부를 제대로 하지 못해서 프로젝트를 진행하면서 필요한 사항에 대해 공부하며 적용하겠습니다.

import React from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { Provider } from "react-redux";

// pages
import HomePage from "@pages/HomePage";
import LoginPage from "@pages/LoginPage";
import ProfilePage from "@pages/ProfilePage";
import RegisterPage from "@pages/RegisterPage";

// store
import store from "@store/configureStore";

const App = () => {
  return (
    <Provider store={store}>
      <BrowserRouter>
        <Routes>
          <Route path="/" element={<HomePage />} />
          <Route path="/login" element={<LoginPage />} />
          <Route path="/profile" element={<ProfilePage />} />
          <Route path="/register" element={<RegisterPage />} />
          <Route path="/*" element={<div>...?</div>} />
        </Routes>
      </BrowserRouter>
    </Provider>
  );
};

export default App;

4. redux / redux-saga

상태 관리 라이브러리로 리덕스와 리덕스 사가를 사용했습니다.
실제 코드는 양이 많고 파일이 너무 분리되어 있어서 GitHub링크로 대체하겠습니다.

  • 폴더 구조
store
 └── actions ( 액션 크리에이터 함수들 모음 )
 └── api ( axios를 이용한 api요청 모음 )
 └── reducers ( reducer 모음 )
 └── sagas ( saga 모음 )
 └── types ( type 모음 )
 └── configureStore.js ( store생성 및 미들웨어 장착 부분 )

5. webpack

create-react-app을 사용하지 않았기 때문에 직접 웹팩설정을 해줬습니다.

직접 설정하는 것이라 부족한 부분도 많고 앞으로 추가해야 할 플러그인도 많아질 것이라 일지를 쓸 때마다 추가한 것에 대해 작성하겠습니다.

const path = require("path");
const RefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  // 웹펙 시작 모드 설정
  mode: "development",

  // 디버깅을 위한 설정 배포 시 eval
  devtool: "source-map",

  // 경로 및 확장자 설정
  resolve: {
    extensions: [".jsx", ".js"],
    alias: {
      "@components": path.resolve(__dirname, "src/components"),
      "@util": path.resolve(__dirname, "src/util"),
      "@store": path.resolve(__dirname, "src/store"),
      "@pages": path.resolve(__dirname, "src/pages"),
      "@css": path.resolve(__dirname, "src/css"),
    },
    // 로더 해석에 적용되지 않음
    modules: ["node_modules", path.resolve(__dirname, "app")],
  },

  // 진입점 설정
  entry: {
    app: "./index.js",
  },

  // 빌드 결과물 위치 지정
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
    publicPath: "/",
  },

  // 로더 설정
  module: {
    rules: [
      // jsx 해석을 위한 babel로더 설정
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: "babel-loader",
        options: {
          // @babel/preset-env는 브라우저 환경에 맞게 알아서 바벨 설정을 해줌
          // @babel/preset-react는 jsx 지원
          presets: ["@babel/preset-env", "@babel/preset-react"],
          // dev server을 위한 설정, async와 await를 위한 설정
          plugins: ["react-refresh/babel", "@babel/plugin-transform-runtime"],
        },
      },

      // css를 위한 로더
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
    ],
  },

  // 플러그인 설정
  plugins: [new HtmlWebpackPlugin({ title: "bluegram" }), new RefreshWebpackPlugin()],

  // 데브서버 설정
  devServer: {
    // 번들링한 결과물을 저장할 위치 ( 메모리상 )
    devMiddleware: {
      publicPath: "/dist",
    },
    // 정적 파일들의 위치 지정
    static: {
      // 내 컴퓨터에서 공유할 파일들이 있는 경로
      directory: path.resolve(__dirname, "public"),
      // 브라우저상에서 접근할 경로
      publicPath: "/",
      // 정적 파일 수정시 페이지 새로고침 여부
      watch: true,
      // index 파일 없으면 브라우저에서 폴더를 보여줄지 여부
      serveIndex: true,
    },
    // 핫 모듈 리로딩 기능 ( 새로고침해도 기존 입력 정보는 유지 )
    hot: true,
    // 포트번호 설정
    port: 8080,
    // SPA의 react-router 같은 거 사용할 때 필수적으로 적용해 줘야 하는 옵션이다.
    // 기본적으로 /login으로 요청 보내면 404에러가나기 때문에 그때 index.js로 요청을 넘기게 해주는 옵션 값
    historyApiFallback: true,
  },
};

마무리

1. 어렵고 힘들었던 점

웹팩에 대해서 공부를 어느 정도 하고 사용하긴 했지만 실제로 어떻게 동작하고 어떤 로더를 적용하고 어떤 플러그인을 적용하며, 어떤 설정값을 줘야 하는지에 대한 판단이 어렵고 앞으로도 어려울 것 같습니다.

최대한 적은 설정으로 시작해서 오류가 나거나 경고가 날 때마다 구글링으로 로더나 플러그인을 추가해 주지만 이게 과연 어떤 역할을 해주기에 추가해 주는 건지 정확하게 이해하기가 어렵다고 느껴질 때가 많습니다.

추가적으로 라우팅이 안돼서 문제가 react-router-dom이 v6으로 업데이트되면서 사용법을 정확히 몰라서 라우팅이 안되는 줄 알았습니다.
알고 보니 웹팩에서 historyApiFallback설정에 대해 몰랐기 때문에 명시해 주지 않아서 데브 서버에서 라우팅 인식을 못 하는 것이었습니다.
이것 때문에 하루 종일 고생했네요...

2. 깨달은 점

reactwebpack-dev-server를 돌리면서 라우팅 처리를 하려면 historyApiFallback에 대해서 이해를 하자는 것입니다.

0개의 댓글