본문 바로가기

프로젝트 개발일지/프로젝트 세팅

yarn berry + vite + react + typescript + react-query + emotion + prettier + eslint + husky + lint-staged + storybook 프로젝트 세팅을 해보자

이전에 yarn berry와 vite에 대한 글을 쓴 적이 있다.

그때는 yarn berry와 vite가 무엇인지 정도만 알아봤었는데, 이번에는 직접 프로젝트 세팅을 해보자.

yarn berry, vite, react, typescript, react-query, emotion, prettier, eslint, husky, storybook 이렇게 세팅을 해보려고 한다.

 

vite + react + typscript 프로젝트 생성

가장 먼저, vite 프로젝트를 먼저 생성해 보자.

이때, react와 typescript를 사용하도록 생성해 주면 된다.

 

아래 명령어를 통해서 생성해 주었다.

yarn create vite {project name} --template react-ts

 

추가적으로 vite에서는 절대 경로를 설정하는 것을 vite.config 파일에서 할 수 있다.

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  base: './',
  publicDir: './public',
  cacheDir: './.vite',
  resolve: {
    alias: [
      { find: '@pages', replacement: '/src/pages' },
      { find: '@components', replacement: '/src/components' },
      { find: '@lib', replacement: '/src/lib' },
      { find: '@assets', replacement: '/src/assets' },
      { find: '@styles', replacement: '/src/styles' },
      { find: '@utils', replacement: '/src/utils' },
    ],
  },
})

 

절대 경로를 설정해 주면 보다 깔끔하게 import문으로 컴포넌트 등을 불러올 수 있다.

이때까지는 상대 경로로만 불러와서 계속 불편하게 아래와 같이 import했었다.

../../../Category

 

절대 경로를 설정해 주면, 아래처럼 편하게 import할 수 있다.

@components/Category

 

하지만 이렇게 절대 경로를 사용하기 위해서는 vite.config.ts뿐만 아니라 tsconfig.json에도 별도의 설정이 필요하다.

그리고 path를 타입스크립트에서 사용하기 위해서는 @types/node 설치를 해야 한다.

 

아래 명령어를 통해 @types/node 먼저 설치해 보자.

yarn add @types/node

 

그리고 tsconfig.json에 절대 경로 관련 설정들을 추가해 주면 된다.

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "allowJs": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "allowSyntheticDefaultImports": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",

    /* Linting */
    "strict": true,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "noFallthroughCasesInSwitch": true,

    /* 절대 경로 */
    "baseUrl": ".",
    "paths": {
      "@pages/*": ["src/pages/*"],
      "@components/*": ["src/components/*"],
      "@lib/*": ["src/lib/*"],
      "@assets/*": ["src/assets/*"],
      "@styles/*": ["src/styles/*"],
      "@utils/*" : ["src/utils/*"],
    }
  },
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }],
  "jsxImportSource": "@emotion/react"
}

 

react-query 세팅

react query v4부터 tanstack query로 라이브러리 명이 변경되었다.

이번에 tanstack query를 설치해 보고 세팅해보려 한다.

 

아래 명령어를 통해 설치해 보자.

yarn add @tanstack/react-query

 

react-query-devtools도 같이 설치해 보자.

yarn add @tanstack/react-query-devtools

 

이제, main.tsx에서 리액트 쿼리 관련 간단한 세팅을 해주자.

아래와 같이 queryClient를 생성한 후 queryClientProvider를 통해 공급해 준다.

이로써 모든 컴포넌트에서 queryClient를 사용할 수 있게 된다.

import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'

const queryClient = new QueryClient()

ReactDOM.createRoot(document.getElementById('root')!).render(
    // ...
    <QueryClientProvider client={queryClient}>
      <ReactQueryDevtools />
      <App />
    </QueryClientProvider>
  )
)

export default App

 

ReactQueryDevtools 같은 경우 리액트 쿼리 관련 동작들을 편하게 볼 수 있도록 시각화해서 보여주는 툴이다.

왼쪽 아래 꽃 모양 표시가 리액트 쿼리 데브 툴이다.

해당 아이콘을 누르면 리액트 쿼리 동작 관련해서 많은 정보들을 얻을 수 있다.

 

yarn berry 세팅

아래와 같이 yarn 버전을 berry로 설정해 준다.

yarn set version berry

.yarnrc.yml 파일에 아래 내용을 추가해서 nodeLinkerpnp로 설정해줘야 한다.

nodeLinker 설정은 node.js 패키지를 어떻게 관리할 것인지 설정하는 것이다.

pnp / node_modules 등이 있는데 여기서는 pnp 설정을 사용한다.

node_modules 설정을 사용하면 기존처럼 node_modules로 패키지를 관리하게 되니까 꼭 pnp로 설정해 주도록 하자.

 

또, yarnPath는 yarn 실행 파일의 경로를 지정하는 것이다.

아래와 같이 경로를 지정해 주면 된다.

yarnPath: .yarn/releases/yarn-3.6.3.cjs
nodeLinker: pnp

 

다시 yarn install을 통해서 변경한 설정 정보들을 적용시켜 주자.

yarn install

 

아래 사진은 vite + react + typescript 프로젝트 생성 및 yarn 관련 설정이 끝난 후의 폴더 구조이다.

 

또, zero-install을 사용하기 위해서 아래 내용들을 .gitignore 파일에 추가해 준다.

# zero-install
.yarn/*
!.yarn/cache
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

 

자체적으로 types를 포함하지 않아 @types로 시작하는 별도의 타입 정의를 설치해줘야 하는 작업을 자동화해 주는 플러그인도 설치해 보자.

yarn plugin import typescript

 

에러 해결

하지만, 안타깝게도 아래와 같은 에러가 발생했다.

모듈을 인식하지 못하는 거 같았다.

 

그래서 열심히 구글링을 했다.

결론은 아래 방법대로 하면 된다는 것이다.

 

일단 아래 명령어를 실행한다.

yarn dlx @yarnpkg/sdks vscode

pnp 이용 시 typescript가 작동할 수 있도록 편집기에 대한 설정을 적용해 준다는 것이다.

typescript는 yarn 폴더 내부 zip 파일로 관리되고 있는데 편집기에 연결이 안 돼서 인식을 못하는 거라고 생각하면 된다.

 

그리고 typescript를 현재 작업 영역 버전으로 설정을 해주게 되면 아래와 같이 이제 에러가 없어진다.

Ctrl + Shift + P를 누르고 Select Typescript Version 클릭 시 작업 영역 버전 사용을 누를 수 있다.

추가적으로, yarn을 설치한 디렉터리에서 설정할 수 있다는 것도 잊지 말자.

다른 디렉터리에서는 해당 선택지가 뜨지 않을 수 있다.

 

emotion 설치

이제 emotion 라이브러리를 사용하기 위해서 다음 명령어를 통해 설치해 준다.

yarn add @emotion/react @emotion/styled

 

추가적으로 코드 최적화와 스타일을 효율적으로 관리할 수 있게 해주는 @emotion/babel-plugin을 추가적으로 설치해 주자.

yarn add --dev @emotion/babel-plugin

 

그리고 마지막으로, ts와의 호환성을 위해서 tsconfig.json에 관련 설정을 추가해주어야 한다.

"jsxImportSource": "@emotion/react", 이 설정을 추가해 주었다.

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "allowJs": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "allowSyntheticDefaultImports": 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,

    /* 절대 경로 */
    "baseUrl": ".",
    "paths": {
      "@pages/*": ["src/pages/*"],
      "@components/*": ["src/components/*"],
      "@libs/*": ["src/libs/*"],
      "@assets/*": ["src/assets/*"],
      "@styles/*": ["src/styles/*"],
      "@utils/*" : ["src/utils/*"],
    }
  },
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }],
  "jsxImportSource": "@emotion/react",
}

 

Storybook 설치

다음으로, 스토리북을 사용하기 위해서 먼저 스토리북을 다운로드한다.

이 프로젝트에서는 vite를 사용하고 있기 때문에 그에 맞는 명령어를 통해 storybook을 설치해 준다.

npx sb init --builder @storybook/builder-vite

 

그리고, core 부분에 builder 관련 설정도 추가해 준다.

import type { StorybookConfig } from '@storybook/react-vite'

import { join, dirname } from 'path'

/**
 * This function is used to resolve the absolute path of a package.
 * It is needed in projects that use Yarn PnP or are set up within a monorepo.
 */
function getAbsolutePath(value: string): any {
  return dirname(require.resolve(join(value, 'package.json')))
}
const config: StorybookConfig = {
  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
  addons: [
    getAbsolutePath('@storybook/addon-links'),
    getAbsolutePath('@storybook/addon-essentials'),
    getAbsolutePath('@storybook/addon-onboarding'),
    getAbsolutePath('@storybook/addon-interactions'),
  ],
  core: {
    builder: '@storybook/builder-vite',
  },
  framework: {
    name: getAbsolutePath('@storybook/react-vite'),
    options: {},
  },
  docs: {
    autodocs: 'tag',
  },
}
export default config

 

스토리북 관련 의존성들을 다 설치해 준 후 yarn storybook 명령어를 통해 실행시켜 보면 잘 뜨는 것을 확인할 수 있다.

 

이제 커스텀 뷰포트패딩을 추가해보도록 하자.

.storybook 폴더 내부 preview.ts 파일을 찾을 수 있을 것이다.

해당 파일에 설정 몇 가지를 추가하면 뷰포트와 패딩 설정을 추가할 수 있다.

 

뷰포트의 경우 아래와 같이 원하는 뷰포트 스타일을 만들어주고, 적용해주면 된다.

기본 값으로는 iPhone13으로 지정해주었다.

const customViewports = {
  iPhone13: {
    name: 'iPhone 13',
    styles: {
      width: '390px',
      height: '844px'
    },
    type: 'mobile'
  },
  tablet: {
    name: 'iPad Pro 11',
    styles: {
      width: '834px',
      height: '1194px',
    },
    type: 'tablet',
  },
}

const preview: Preview = {
  parameters: {
    actions: { argTypesRegex: '^on[A-Z].*' },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/,
      },
    },
    viewport: { 
      viewports: customViewports, 
      defaultViewport: 'iPhone13'
    },
  }
};

이렇게 원하는 뷰포트를 이용해서 작업할 수도 있다.

 

패딩의 경우도 원하는 대로 설정해서 사용할 수 있다.

하지만, 몇 가지 세팅이 필요하다.

 

아래 명령어를 사용해서 storybook-addon-paddings 설치 후 main.ts의 addon에 storybook-addon-paddings를 추가해줘야 한다.

yarn add -D storybook-addon-paddings
  // main.ts
  // ...
  addons: [
    getAbsolutePath('@storybook/addon-links'),
    getAbsolutePath('@storybook/addon-essentials'),
    getAbsolutePath('@storybook/addon-onboarding'),
    getAbsolutePath('@storybook/addon-interactions'),
    getAbsolutePath('storybook-addon-paddings'),
  ],
  // ...

이렇게 하면 원하는 대로 패딩을 사용할 수 있다.

 

아래 코드를 보면 알다시피, 진행하려는 프로젝트에서 필요로 하는 기본 패딩이 있다면 추가해두면 편하다.

여기서는 패딩을 적용하지 않는 none을 기본으로 했고, 필요에 따라 24px씩 패딩이 적용되어있는 margin-template을 사용할 수 있도록 했다.

const preview: Preview = {
  parameters: {
    actions: { argTypesRegex: '^on[A-Z].*' },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/,
      },
    },
    paddings: {
      values: [
        { name: 'margin-template', value: '24px' },
        { name: 'none', value: '0px' },
      ],
      default: 'none',
    },
    viewport: { 
      viewports: customViewports, 
      defaultViewport: 'iPhone13'
    },
  }
};

 

이제 이 storybook을 vercel로 배포까지 해봤다.

스토리북을 빌드하는 명령어를 입력해서 빌드해주면 storybook-static이라는 폴더가 생성되는데, 이 폴더를 root로 배포하면 된다.

storybook-static은 스토리북 빌드 시 실행 결과를 저장해두는 폴더이다.

 

아래 링크로 접속하면 배포된 스토리북을 확인할 수 있다.

https://project-setting-ghdtjgus76.vercel.app/

 

만약 코드 수정 후 변경 사항을 배포 사이트에 반영하고 싶다면 다시 스토리북을 빌드한 후 배포할 브랜치에 푸시해주면 된다.

 

eslint, prettier 설정

eslint는 작성된 코드를 분석해서 문법 오류나 안티 패턴을 찾아주고 일관된 코드 스타일로 작성하도록 도와주는 도구이다.

이번에 eslint도 함께 설정해서 사용해 보자.

 

다음과 같이 먼저 eslint부터 설치해 주자.

yarn add -D eslint

 

다음 명령어를 실행하면 eslint 관련해서 설정할 수 있는 파일인 .eslintrc.js 파일 생성과 설정을 해준다.

yarn eslint --init

이 명령어를 통해서 eslint 설정을 하는 것이 아니라 직접 .eslintrc.js 파일을 생성하는 경우에는 필요한 패키지들을 수동으로 설치해야 하는데, 이 방식으로 진행하면 자동으로 설치된다.

 

eslintrc.js 파일을 통해서 eslint 설정들을 해줄 수 있다.

아래와 같이 필요한 것들을 추가해 주었다.

module.exports = {
  env: {
    browser: true,
    es2020: true,
    node: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended',
    'plugin:react-hooks/recommended',
    'plugin:react/recommended',
    'plugin:storybook/recommended',
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module',
  },
  plugins: ['react-refresh', 'react', 'react-hooks', '@typescript-eslint'],
  overrides: [
    {
      env: {
        node: true,
      },
      files: ['.eslintrc.{js,cjs}'],
      parserOptions: {
        sourceType: 'script',
      },
    },
  ],
  rules: {
    'react/jsx-curly-brace-presence': [
      'error',
      { props: 'never', children: 'never' },
    ],
    'react-refresh/only-export-components': 'warn',
    'react/react-in-jsx-scope': 'off',
    'react/no-children-prop': 'off',
    'no-unused-expressions': 'off',
    '@typescript-eslint/no-var-requires': 'off',
    '@typescript-eslint/no-empty-function': 'off',
    'react/no-unknown-property': ['error', { ignore: ['css'] }],
    'no-unused-vars': 'off',
    '@typescript-eslint/no-unused-vars': ['warn', { ignoreRestSiblings: true }],
  },
  settings: {
    'import/external-module-folders': ['.yarn'],
  },
}

필요한 플러그인들을 추가해 주었는데, react-refresh의 경우, 코드 수정 시 새로고침하지 않고 수정 사항을 빠르게 교체해 주는 라이브러리라서 추가해 두었다.

 

rules에 대해서 조금 자세히 알아보자.

rules: {
    'react/jsx-curly-brace-presence': [
      'error',
      { props: 'never', children: 'never' },
    ],
    'react-refresh/only-export-components': 'warn',
    'react/react-in-jsx-scope': 'off',
    'react/no-children-prop': 'off',
    'no-unused-expressions': 'off',
    '@typescript-eslint/no-var-requires': 'off',
    '@typescript-eslint/no-empty-function': 'off',
    'react/no-unknown-property': ['error', { ignore: ['css'] }],
    'no-unused-vars': 'off',
    '@typescript-eslint/no-unused-vars': ['warn', { ignoreRestSiblings: true }],
  },

 

먼저, 'react/jsx-curly-brace-presence' 부분으로 문자열 값인 props와 children의 경우 중괄호를 쓰지 않도록 설정해 주었다.

아래 코드에서 첫 번째 경우처럼 쓰지 말고 두 번째처럼 쓰도록 하는 것이다.

<Paragraph variant={"h5"} heading={"A new book"} />

<Paragraph variant="h5" heading="A new book" />

 

'react-refresh/only-export-components' 부분에서 'warn' 설정을 해주었는데, react 컴포넌트만 export하도록 하는 설정이다.

만약, 이를 따르지 않으면 경고를 띄우도록 설정하였다.

'react/react-in-jsx-scope': 'off' 설정은 import React from 'react' 문을 쓰지 않아도 문제가 없도록 만들어주는 설정이다.

'react/no-children-prop': 'off' 설정은 children 속성 사용을 허용하는 설정이다.

'no-unused-expressions': 'off' 설정은 사용하지 않는 표현식에 대한 경고를 표시하지 않도록 하는 설정이다.

'@typescript-eslint/no-var-requires': 'off' 설정은 typescript 코드에서 require 문을 사용할 수 있도록 하는 설정이다.

'@typescript-eslint/no-empty-function': 'off' 설정은 빈 함수 선언을 허용하도록 하는 설정이다.

'react/no-unknown-property': ['error', { ignore: ['css'] }] 설정은 알 수 없는 jsx 속성에 대해서 경고를 표시하는 규칙을 설정하는데, css 속성은 무시하고, css를 제외한 다른 속성에 대해서 오류를 표시하도록 하는 설정이다.

'no-unused-vars': 'off' 설정은 사용하지 않는 표현식에 대해서 경고를 하지 않도록 하는 설정이다.

'@typescript-eslint/no-unused-vars': ['warn', { ignoreRestSiblings: true }] 설정은 사용하지 않는 typescript 변수에 대해서 경고를 표시하도록 하는 설정인데, 나머지 형제 변수는 무시하도록 하는 설정이다.

 

한편, prettier는 왜 따로 설정하는지 궁금할 수 있다.

개인적으로 진행하는 작은 규모의 프로젝트라면 굳이 설정해주지 않아도 큰 문제는 없을 거 같지만, 협업 프로젝트라면 prettier 설정은 필수이다.

개인마다 설정해 둔 prettier 설정이 다 다르기 때문에 코드 컨벤션 같은 것이 다 따로 놀 수 있다.

따라서 일관적으로 코드를 작성하기 위해서는 prettier 설정까지 해주는 것이 좋다.

 

먼저 prettier를 설치해 주자.

yarn add -D prettier

 

이제, eslint와 prettier가 충돌하지 않고 잘 작동하도록 eslint-config-prettiereslint-plugin-prettier를 별도로 설치해 주자.

yarn add -D eslint-config-prettier eslint-plugin-prettier

 

이제, 진짜 마지막으로 .prettierrc.json 파일을 생성해서 원하는 스타일을 적용해 주면 된다.

 

husky, lint-staged 세팅

협업하는 팀원들이 실수로 eslint, prettier를 제대로 적용하지 않는다면, 또 일관성 없는 코드 컨벤션이 생기게 된다.

이때 설정한 규칙을 따르지 않으면 git과 관련된 작업을 할 때 작업을 중단하도록 하는 git hook을 사용하도록 하면 문제가 해결된다.

git hook은 깃과 관련된 어떤 이벤트가 발생했을 때 특정 스크립트를 실행할 수 있도록 하는 것이다.

husky는 이런 복잡한 git hook 관련 설정을 도와주는 npm package라고 생각하면 된다.

 

이제 husky 관련 설치 및 세팅을 해보자.

 

아래 명령어를 통해 husky 설치를 진행해 보자.

yarn add --dev husky

이제 husky 설정 폴더를 만들자.

npx husky install

이렇게 하면 .husky라는 폴더가 생성되는 것을 볼 수 있다.

 

이제, package.json 파일에 스크립트 문을 추가해 보자.

"scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "format": "prettier --cache --write .",
    "lint": "eslint --cache .",
    "preview": "vite preview",
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build"
  },

추가한 것은 format과 lint 관련 스크립트 문인데, 해당 문장은 모든 파일을 검사하지만 이미 검사한 파일이나 항목을 cache에 저장하고 변경 사항이 없다면 해당 파일은 검사하지 않도록 하는 것이다.

이렇게 하면 실행 속도도 더 빨라지게 된다.

 

이제 pre-commit, pre-push hook을 추가해 보자.

npx husky add .husky/pre-commit "yarn format"
npx husky add .husky/pre-push "yarn lint"

이렇게 하면 git hook 관련 파일이 생성된 것을 알 수 있다.

// pre-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

yarn format
// pre-push
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

yarn lint

 

이렇게 설정해 주면 커밋하기 전에 prettier가 코드를 설정한 포맷에 맞게 수정해 주고, push 하기 전에 eslint 문법을 확인해 준다.

prettier를 통해 알맞게 코드 포맷팅을 하지 않고 커밋을 하게 되면 알아서 prettier를 잘 적용해 주고, eslint 문법에 맞지 않게 적용한 코드를 푸시하게 되면 push 작업을 중단하는 것을 확인할 수 있다.

 

이렇게 하면 우리가 원하는 대로 일관된 코드 컨벤션에 맞춰 작업할 수 있게 된다.

 

그런데 아래와 같은 에러가 났다.

이는 windows에서 발생하는 문제인데 prettier와 windows의 개행 방식이 다르기 때문에 나타난다고 하더라.

 

다음과 같이 rules에 prettier의 개행 방식에 대한 rule을 별도로 설정해 주면 에러가 사라진다.

  rules: {
    // ...,
    'prettier/prettier': [
      'error',
      {
        endOfLine: 'auto',
      },
    ],
  },

 

그런데, husky만 사용하게 되면 커밋할 때 속도가 너무 느렸다.

그래서 구글링을 해보니, lint-staged라는 패키지랑 같이 쓰면 해결된다고 한다.

이는, 모든 파일을 검사하려면 굉장히 오랜 시간이 걸리는데, lint-staged를 함께 사용하면 변경된 파일만 검사할 수 있다고 한다. (git staging area에 올라온 파일만 검사할 수 있다.)

 

그래서 lint-staged 패키지를 설치해서 몇 가지 세팅 완료 후 우리 프로젝트에도 적용해보려 한다.

 

일단 lint-staged 패키지를 다운 받아보자.

yarn add -D lint-staged

 

그리고 pre-commit 파일에 아래와 같이 커밋 전 yarn lint-staged 명령어를 실행할 수 있도록 해주자.

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

yarn lint-staged

 

package.json 파일에는 아래 설정을 추가해 주면 된다.

이는 프로젝트 내 모든 ts, tsx, js, jsx 파일에 대해서 검사하는 설정을 추가한 것이다.

"lint-staged": {
    "src/**/*.{js,jsx,ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ]
  },

 

이렇게 하니까 eslint로 인해 엄청 느린 커밋 속도가 어느 정도 빨라진 걸 체감할 수 있었다.

다음에 eslint를 사용할 때는 lint-staged를 꼭 같이 써야겠다.

 

node_modules 재생성?

위에서 세팅한 프로젝트를 yarn dev 명령어를 통해서 실행시켜 보니 다시 node_modules 폴더가 나타났다.

분명 yarn berry 설정할 때 nodeLinker 설정을 node_modules에서 pnp로 변경해 주었는데 다시 나타나서 당황스러웠다.

구글링을 해보니 아래와 같은 이유 때문에 다시 node_modules가 생기는 것이었다.

 

이전에 vite에 대해서 공부했을 때, vite는 변경이 되지 않을 만한 코드들은 사전 번들링, 즉 패키지들을 미리 트랜스파일링 후 캐싱해서 쓴다고 했다.

그런데 node_modules 폴더 내부에 이 파일들이 보이기 시작했다.

node_modules/.cache/esbuild라는 디렉터리였는데, yarn 팀에서 공식적으로 이 파일들을 node_modules/.cache/esbuild에서 관리하도록 권장한다는 것도 알게 되었다.

그 이유는 패키지들이 쓰기 접근이 제한된 저장소에 둬야 수정 위험이 덜하기 때문에 node_modules/.cache 폴더에 저장해야 한다는 것이었는데, 나는 여기서 의문이 생겼다.

yarn에서 pnp로 쓰도록 설정했는데도 node_modules 폴더가 따로 있어야 한다는 것이 이상하게 느껴졌다.

 

일단은 나는 yarn-berry로 쓰도록 결정했기 때문에 일단 node_modules가 생성되지 않도록 설정을 바꾸었다.

굳이 변경하지 않아도 되지만, 나는 node_modules 말고 yarn-berry의 특성을 잘 사용해보고 싶기 때문에...

 

그래서 아래와 같이 vite.config.ts 파일에서 cacheDir 경로를 따로 지정해 주었다.

이렇게 하니 yarn dev를 통해 실행시키더라도 node_modules 폴더가 다시 생성되지 않았다.

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  base: '/',
  publicDir: './public',
  cacheDir: './.vite',
  resolve: {
    alias: [
      { find: '@pages', replacement: '/src/pages' },
      { find: '@components', replacement: '/src/components' },
      { find: '@lib', replacement: '/src/lib' },
      { find: '@assets', replacement: '/src/assets' },
    ],
  },
})

 

참고 자료

https://velog.io/@haru/yarn-berry-settings

https://velog.io/@gene028/%EC%BB%A4%EB%B9%84%EC%83%B5-%EA%B0%9C%EB%B0%9C%EC%9D%BC%EC%A7%80-1-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%84%B8%ED%8C%85%ED%95%98%EA%B8%B0-Vite-React-Typescript

https://velog.io/@jungmiin/yarn-berry%EC%97%90%EC%84%9C%EC%9D%98-cannot-find-module-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0

https://9yujin.tistory.com/101?category=1013884 

https://velog.io/@das01063/VSCode%EC%97%90%EC%84%9C-ESLint%EC%99%80-Prettier-TypeScript-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0

https://kasterra.github.io/setting-yarn-berry/

https://github.com/ahnanne/first-vite/commit/091f22c34959ed3d7851ef83b7367664366e579c

https://ahnanne.tistory.com/95

https://shape-coding.tistory.com/entry/Vite-TypeScript-Vite-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C-%EC%A0%88%EB%8C%80-%EA%B2%BD%EB%A1%9C-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0

https://snupi.tistory.com/203

https://velog.io/@xka926/react-refresh-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%84%A4%EC%A0%95

https://velog.io/@jiynn_12/%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A1%9C-%ED%98%91%EC%97%85%ED%95%98%EA%B8%B0-husky

https://m.blog.naver.com/pjt3591oo/222645854671