velog
graduation
Migration

Intro

졸업 프로젝트에서 프론트엔드 개발을 맡은 과정에서 가장 큰 변화는 기술 스택의 변경이었습니다. 이러한 마이그레이션 과정을 통해 이전에 알지 못했던 새로운 기술들을 학습하게 되었고, 각 기술의 특징을 명확히 이해할 수 있는 기회를 얻게 되었습니다.


TypeScript를 선택한 이유

  1. 통신 비용 절감을 위한 타입 안정성 강화
  1. 디버깅 및 오류 처리 시간 절약, 코드 안정성 향상

TypeScript는 JavaScript의 슈퍼셋 언어로, JavaScript에 정적인 타입 개념을 도입한 언어입니다.

JavaScript에서 동적으로 관리되던 타입을 엄격하게 관리하며, Interface / Enum / Generic 등 JavaScript에서는 제공하지 않는 타입이나 문법 또한 포함되어 있습니다.

Vite를 선택한 이유

  1. 모듈 번들러에 대한 이해도 증진
  1. ES 모듈 기반의 빌드 시스템 도입으로 빠른 개발 및 빌드 속도 제공
  2. HMR(핫 모듈 리로딩) 기능의 도움으로 코드 변경 시 즉시 반영

Vite는 ES 모듈 기반으로 한 dev 서버로, 대표적인 모듈 번들러 중 하나인 webpack에 비해 실행 시간이 수십 배 이상 빠르다는 장점이 있습니다.


마이그레이션 과정

TypeScript를 사용하는 Vite 기반 React 프로젝트를 초기 설정하는 명령어는 다음과 같습니다.

pnpm create vite@latest client --template react-ts

CRA와 JavaScript로 구성하였던 이전 프로젝트와 달라진 점은 다음과 같습니다.

1. vite.config.ts

Vite 프로젝트에 대해 전반적인 설정을 먼저 진행했습니다.

dev환경과 배포 시 prod환경을 구분하기 위해 mode 매개변수를 사용하였고, 이에 맞게 환경 변수를 분리 적용하였습니다.

Rollup 옵션을 설정하여 빌드 결과물의 형태를 css, img, js로 구분하도록 지정하였습니다.

Tailwind CSS를 새롭게 적용하고자 플러그인에 추가하였고,

로컬 서버 설정 및 절대 경로를 사용하는 과정에서 경로에 대한 별칭 설정까지 지정하였습니다.

import { defineConfig, loadEnv } from 'vite';
import react from '@vitejs/plugin-react';
import tsconfigPaths from 'vite-tsconfig-paths';
import dts from 'vite-plugin-dts';
import tailwindcss from 'tailwindcss';
 
// https://vitejs.dev/config/
export default ({ mode }) => {
  const isProduction = mode === 'production';
 
  const devEnv = loadEnv(mode, process.cwd(), '');
  const prodEnv = loadEnv(mode, process.cwd(), '');
 
  return defineConfig({
    build: {
      rollupOptions: {
        output: {
          assetFileNames: (assetInfo) => {
            let extType = assetInfo.name!.split('.').at(1) as string;
            if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType)) {
              extType = 'img';
            }
            return `assets/${extType}/[name]-[hash][extname]`;
          },
          chunkFileNames: 'assets/js/[name]-[hash].js',
          entryFileNames: 'assets/js/[name]-[hash].js',
        },
      },
      sourcemap: true,
      emptyOutDir: true,
    },
    css: {
      postcss: {
        plugins: [tailwindcss],
      },
    },
    define: {
      'process.env': isProduction ? prodEnv : devEnv,
    },
    plugins: [react(), tsconfigPaths(), dts({ rollupTypes: true })],
    server: {
      host: true,
      port: 3000,
    },
    resolve: {
      alias: [{ find: '@', replacement: '/src' }],
    },
  });
};
 

2. tsconfig.json / tsconfig.node.json

TypeScript를 새롭게 적용하였기 때문에 tsconfig.json과 tsconfig.node.json를 통해 Typescript 컴파일러가 JavaScript로 변환하는 방법을 정의하였습니다.

주요 적용한 점은 다음과 같습니다.

  1. ECMAScript 2020을 타겟으로 지정하고, 클래스 필드에 대해 define 방식을 사용

  2. ECMASCript 2020, DOM, DOM.iterable 라이브러리 사용

  3. ESNext 모듈 설정

  4. bundler 설정 및 TS 확장자 import 허용

  5. JSON 모듈 해석 허용

  6. 엄격한 타입 검사 및 사용되지 않는 변수, 매개변수 검사 활성화

  7. 절대 경로 및 모듈 해석을 위한 경로 매핑 설정

tsconfig.json

 
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
 
    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
 
    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "noImplicitAny": false,
    "types": [
      "kakao.maps.d.ts"
    ],
    /* Absolute Path */
    "baseUrl": ".",
    "paths": {
      "@/*":["src/*"]
    },
 
    /* Storybook */
    "esModuleInterop": true
 
  },
  "include": ["src", "**/*.ts", "**/*.tsx"],
  "references": [{ "path": "./tsconfig.node.json" }]
}
 

tsconfig.node.json

{
  "compilerOptions": {
    "composite": true,
    "skipLibCheck": true,
    "module": "ESNext",
    "moduleResolution": "bundler",
    "allowSyntheticDefaultImports": true
  },
  "include": ["vite.config.ts"]
}

3. vite-env.d.ts

Vite 프로젝트로 진행하며 환경 변수 설정과 관련하여 CRA 프로젝트와 다르게 지정해야 함을 알게 되었습니다.

CRA에서는 Node.js 환경에서 환경 변수를 참조하는 표준적인 방법인 process.env를 통해 환경 변수를 설정했었는데, Vite에서는 import.meta 객체를 통해 설정한 환경 변수에 접근할 수 있었습니다.

이유는 Vite가 ES 모듈 시스템을 사용하고 있기 때문이었습니다.

/// <reference types="vite/client" />
interface ImportMetaEnv {
  readonly VITE_CUSTOM_ENV_VARIABLE: string;
}
 
interface ImportMeta {
  readonly env: ImportMetaEnv;
}

구현 과정에서 알게된 점

제가 처음으로 기술 스택을 변경하는 과정은 JS에서 TS로의 전환과 CRA를 기반으로 한 프로젝트를 Vite로 변경하는 과정이었습니다.

프로젝트 구성 방식의 변화로 인해 마이그레이션 과정에서는 이전과는 다른 측면을 고려해야 했습니다. 새로운 기술의 특징과 차이점을 정확히 이해해야만 안정적으로 전환할 수 있음을 깨달았습니다.

특히, 각 기술의 특징을 가장 정확하게 설명한 참고 자료 중 하나는 공식 문서였습니다. 이러한 문서는 영어로 작성되어 있고 방대한 내용을 다루기 때문에 처음에는 이해하기 어려웠습니다. 그러나 지속적인 학습을 통해 공식 문서를 활용하는 방법에 익숙해지고자 노력하고 있습니다.

이 방법은 이후에도 React-Query, StoryBook, Playwright, Next.JS 등의 기술을 적용할 때도 도움이 되었으며, 이전에 잘못 적용한 부분에 대한 수정을 하고 있는 현재에도 적극 활용하고 있습니다.


참고 문헌

[서적] 기초부터 완성까지 프런트엔드 - 이재성 | 한정

Vite 공식문서 - ko (opens in a new tab)