티스토리 뷰
교내 캡스톤프로젝트을 하며 FE 역할을 맡게 되었다. 3인 1팀에서 혼자 FE 개발을 맡아 모든 일을 다 전담하게 되었다😮 프로젝트 스캐폴딩을 직접 해본 건 처음이었는데, 한 번 그 과정을 기록해보려 한다.
사용한 기술 스택은 다음과 같다.
Yarn Berry
Eslint & Prettier
TailwindCSS
배포는 Vercel (일단)
Yarn Berry 활용하기
1. 프로젝트 생성
먼저 yarn으로 넥제 프로젝트를 생성해줬다. 생성하고 나면 여러 질문들이 나오는데, 나는 권장해주는 설정들로 선택했다. (typescript, tailwind, eslint 등등.. 많은 옵션들이 나온다!)
yarn create next-app ${project name}
2. yarn version 체크
yarn 버전을 체크해보면 당시 나는 1.22.19가 나왔다. Yarn v1의 경우 package.json 파일을 기반으로 의존성 트리를 생성해 node_modules 디렉토리 구조를 만들지만, 졸업 프로젝트에서는 Plug'n'Play를 써보고 싶어 버전 업그레이드가 필요하다..!
yarn -v
# v 1.22.19 나와버렷죠
일단 버전 체크만 해보고 넘어간다.
3. node_modules 폴더 삭제
우리는 yarn berry 버전을 사용할 것이므로 node_modules 폴더는 필요하지 않다. 때문에 삭제를 해주자!
4. yarn berry로 버전 업그레이드
아래 명령어로 yarn 버전을 업그레이드해주자. 그리고 다시 yarn 버전을 체크해보면 아래와 같이 달라진 것을 볼 수 있었다.
yarn set version stable
# 씁 그리고 yarn -v 하니깐 v 4.1.1 나와버렸다.. 높아라
5. yarnrc.yml 파일 수정하기
4번 과정까지 하고 yarn install을 다시 해주면 아마 node_modules 폴더가 그대로 다시 생기는 것을 볼 수 있을 것이다. 이는 우리가 yarnrc.yml 파일을 수정해주지 않았기 때문이다. yarnrc 파일은 yarn의 내부 설정과 관련된 파일이다. 아마 아래와 같이 적혀있을 것이다.
yarnPath: .yarn/releases/yarn-4.1.1.cjs
nodeLinker: node_modules
여기 있는 내용이 무엇을 뜻하는지 알아보자
우선 yarnPath는 yarn의 위치를 담고 있는 루트이다. 또한 nodeLinker의 경우 node 패키지들을 어떻게 설치할지 명시해주는 부분이다. 작성할 수 있는 옵션들로는 pnp, pnpm, node-modules가 있다. 처음 코드에서는 nodeLinker가 node_modules로 되어있기 때문에 yarn 설치를 하면 node_modules 폴더가 자동으로 추가 된다. 현 프로젝트에서는 Plug'n'Play를 사용할 것이므로 pnp로 수정을 해준다. 아래와 같이 작성해주면 된다.
nodeLinker : pnp
그리고 다시 yarn install 명령어로 yarn을 재설치해준다.
6. zero-install 설정해주기
yarn berry를 활용하는 김에, 한 번 zero-install 설정도 해보고 싶었다.
gitignore 파일에서 설정이 가능하다. 만약 zero install을 활용해보고 싶으면 윗 부분의 명령어로 수정해주면 되고, 사용해보고 싶지 않다면 아래 명령어로 설정해주면 된다.
# using zero install (나는 요거)
.yarn/*
!.yarn/cache
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
# not using zero install
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
7. ZipFS 설치
6번까지 해보면 모든 모듈들에 빨간 줄이 쳐지는 당황스러운 순간을 맞이한다. 수많은 빨간줄에 아득해지지만 이는 모듈을 불러오는 데 에러가 발생하는 것이다. pnp 모드의 경우 node_modules와 같이 낱개 파일로 의존성을 관리하지 않고 zip 파일로 관리를 하게 된다. 때문에 zip 파일들을 읽을 수 있도록 ZipFS라는 확장 프로그램을 설치해줘야 한다.
그리고 추가적으로 타입스크립트를 사용하는 경우 개별 모듈의 타입 파일을 읽고 파싱할 수 있도록 툴킷을 설치해줘야 한다. 이는 아래 명령어로 설치가 가능하다.
yarn dlx @yarnpkg/sdks vscode
그리고 나서 ts 파일에 들어가보면 팝업이 뜰 수도 있다. 팝업을 봤을 때 캡처를 못해서 다른 블로그의 그림으로 대체하지만 아래와 같은 모습의 팝업이 뜬다. 이는 vscode 작업 환경을 타입스크립트로 설정해줄 것이냐는 의미인데, 여기서 Allow를 눌러주면 된다.
만약 팝업을 놓쳤어도 괜찮다. Cmd+alt+shift (윈도우 기준)을 누르고 > Select Typescript Version > Use VS Code's version을 선택해주면 된다. 여러번 프로젝트 스캐폴딩 삽질을 하면서 때로 vscode에서 해당 부분이 뜨지 않는 경우도 종종 발생했던 것 같은데, 이럴 때는 vscode를 재실행해서 해결을 할 수 있었다. code . 라는 명령어를 이용해 새로운 vscode 창을 띄워서 체크할 수도 있다.
여튼 여기까지 해보면 아래와 같이 필요한 부분 설치가 잘 되는 것을 볼 수 있고, ts 파일에 그어져있던 무수히 많은 빨간 줄들이 없어진 것을 확인할 수 있다. 굿굿!
8. Cache 폴더가 없다!?
분명 yarn berry 설정이 잘 되고 다시 yarn install을 해주면 분명히 .yarn 하위 폴더로 cache 폴더가 만들어지고, 그 안에 여러 의존성 파일들이 zip 파일 형태로 추가가 되었어야 했다. 하지만 이상하게 아예 생성이 되지 않았고, 따라서 깃헙 레포지토리에 설치한 의존성들을 푸시하려고 해도 할 게 없었다.
사실 이 이슈를 해결하려 여러 번 삽질을 반복했다. 이전에 초기셋팅에서 문제가 있었던건가 싶어 생성한 프로젝트를 싹 다 지우고 다시 설치도 해보고 그랬다. 하지만 문제는 반복이 되었고, 알고보니 문제의 원인은 다른 곳에 있었다.
캐시 폴더(cacheFolder)가 설치된 위치를 찾아보기 위해 yarn config 명령어를 입력해보자 아래와 같은 위치에서 cacheFolder를 찾을 수 있었다. 잘 보면 캐시 폴더가 현재 프로젝트 안에 .yarn/cache 이런 식으로 주소가 설정이 되어있는게 아니라 엉뚱한 위치로 설정이 되어있는 것을 볼 수 있다. 이렇게 설정이 된 이유는 찾아 보니 아래와 같았다.
yarn berry에서 설정할 수 있는 옵션들 중 enableGlobalCache가 존재한다. 이는 기본적으로 true라고 지정이 되어있는데, 이를 허용하면 전역 캐시 디렉토리를 사용하게 된다고 한다. 따라서 나는 yarn을 셋팅해줄 때 cacheFolder 경로를 지정해주지 않았기 때문에 자동으로 로컬 전역으로 cacheFolder가 생성이 된 것이다. 전역적인 global cache folder을 사용하고 싶은 게 아니라 cacheFolder를 생성하고 싶으면 어디에 생성이 되면 좋을지 명시적으로 써줘야 한다. 아래와 같이 써주면 된다.
//yarnrc.yml
yarnPath: .yarn/releases/yarn-4.1.1.cjs
nodeLinker: pnp
// 여기 아래 내용 추가해주기
enableGlobalCache: false
cacheFolder: ./.yarn/cache
그리고 나서 yarn cache를 한 번 비워주고, 다시 yarn install을 하면!?
yarn cache clean
yarn install
cacheFolder가 현 프로젝트 폴더에 잘 생긴 것을 볼 수 있고, 실제로 필요한 의존성 관련 파일들이 zip 파일로 .yarn/cache 폴더에 들어있는것을 확인할 수 있다.
Eslint, Prettier 셋팅
다음으로는 eslint랑 prettier 설정하기! 사실 이 부분은 이번 프로젝트에는 꼭 필요한 부분은 아니다. 나 혼자 FE 파트로 참여를 하기 때문에😅 eslint랑 prettier는 여럿이 협업할 때 필요한거라..
그치만 해보고 싶어서 함 해봤습니다 가보자고 (근데 조금 정신없을 수 있음 주의⚠️)
1. Eslint 설치
아래 명렁어로 eslint를 설치한다.
yarn eslint --init
그럼 아래처럼 초기 셋팅을 어떻게 할거냐는 식의 질문이 쭉 나온다.
상황에 맞게 대답을 하다 보면 필요한 종속성들도 추가로 설치해주고, .eslintrc.json 파일도 변경이 된다.
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"standard-with-typescript",
"plugin:react/recommended"
],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"react"
],
"rules": {
}
}
2. eslint rule 추가해주기
eslint rule을 추가해본 건 처음이라.. 조금 미숙한 부분이 있지만 아래 공식 문서를 참고하며 필요한 규칙들을 추가해줬다.
https://eslint.org/docs/latest/rules/#site_top
3. Typescript 설정 추가해주기
아래 명령어로 typescript 관련 eslint 플러그인 등을 추가해준다.
yarn add --dev @typescript-eslint/eslint-plugin @typescript-eslint/parser
4. 마주친 yarn lint 이슈
아래와 같이 이슈가 하나 떴었던 것 같다.
⚠ The Next.js plugin was not detected in your ESLint configuration. See https://nextjs.org/docs/basic-features/eslint#migrating-existing-config
Warning: React version not specified in eslint-plugin-react settings. See https://github.com/jsx-eslint/eslint-plugin-react#configuration .
여기서 아래와 같이 추가 설정을 해주고 eslintrc.json 부분에 추가를 해주는 것으로 해결이 되었다.
yarn add @next/eslint-plugin-next
//eslintrc.json 일부
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:prettier/recommended",
"plugin:@next/next/recommended", //이거 추가!
"prettier"
],
TailwindCSS 활용하기
최근에 한 프로젝트에서 테일윈드를 처음 사용해봤었다. 근데 그 때 추가 라이브러리들과 함께 사용을 했었는데 정말 너무 유연했고 깔끔했다. (짱짱) 그래서 해당 프로젝트에서 사용한 라이브러리들과 함께 셋팅을 해보려 한다.
이번 프로젝트에서 사용해주려는 라이브러리는 총 2개! tailwind merge와 clsx이다. 사실 찾아보면 tailwind merge + clsx + cva 조합으로 많이 사용을 하는 모습을 볼 수 있다. cva 라이브러리도 코드를 간결하게 만들어주는 것 같긴한데.. 그렇게 큰 필요성을 느끼지 못해 tailwind merge와 clsx를 조합해 활용을 해보려 한다.
1. Tailwind merge 설치
실제 설치를 하기 전에 tailwind merge 라이브러리를 사용하는 이유를 간단하게만 얘기를 해보려 한다.
TailwindCSS를 사용하면서 많이 겪는 상황 중에 하나는 컴포넌트 안에 일부 스타일을 변경하지 못한다는 것이다. 만약 중복된 스타일이 적용되었을때, 평소 같으면 css cascading으로 인해 뒤에 적힌 스타일이 우선적으로 적용된다. 하지만 Tailwind의 경우 { className 안에 있는 스타일의 순서 != 스타일의 우선순위 } 이고, tailwind에서 정의한 순서에 따라 스타일의 우선순위가 적용이 되기 때문에 원하는 대로 스타일이 적용되지 않을 수도 있다. Tailwind 우선순위와 관련해서 더 알고싶다면 여기 자세히 설명이 되어있다.
이런 이슈가 있는데, tailwind merge의 경우 'Last conflicting class wins' 라는 특징이 있다. 이 말은 중복된 스타일이 존재하면 가장 뒤에 적힌 스타일이 적용되도록 해준다는 것이다. 이런 특징 때문에 우리는 taliwind merge 라이브러리를 사용할 것이다.
https://www.npmjs.com/package/tailwind-merge
아래 명령어로 tailwind merge를 설치해준다.
yarn add tailwind-merge
2. clsx 설치
clsx도 마찬가지로 설명을 좀 해보도록 하겠다.
clsx 라이브러리의 경우 조건부 렌더를 작성하기 쉬워지는 장점을 제공한다. 특정 조건에 따라 스타일을 변경해야 하는 경우, 원래라면 길어질 수 있는 코드를 간단하게 줄일 수 있다.
https://www.npmjs.com/package/clsx
아래 명령어로 clsx를 설치해준다.
yarn add clsx
cf) classnames의 cn 라이브러리 vs clsx 차이
둘은 거의 비슷한데, clsx 번들 사이즈가 더 작다고 한다. 내부 알고리즘도 clsx가 더 빠르다고 저번에 팀원 분이 알려주셨당
물론 사실 별 차이 없다는 얘기도 덧붙이심..
cf2) 이 둘을 그냥 dependency에 넣을지 devdependency에 넣을지 고민이 있었지만, dependency에 우선 넣었다. 흠
3. cn 유틸 함수 작성해주기
깔끔한 코드 작성을 위해 cn 유틸 함수를 추가해준다.
tailwind-merge 라이브러리의 twMerge를 사용하면 클래스들 간 충돌이 나는 걸 방지할 수 있고, 마지막으로 넘긴 클래스로 override를 할 수 있다. (이 기능이 내가 tailwind-Merge 라이브러리를 쓰는 이유이기도 하고!) clsx의 경우 그렇게 넘겨주는 클래스들을 조건부로 설정할 수 있게 하기 위해서 활용을 하는데, clsx를 이용해서 클래스들을 모두 넘겨주면 마지막에 그 결과를 twMerge가 받아서 처리하는 게 필요하다. 매번 이를 코드를 작성할 때마다 둘을 함께 써줘야 하면 번거로워질 수 있으니, 따로 유틸리티 함수를 만들어주는 것이다.
따라서 아래와 같이 추가를 해주자!
import clsx, { ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
export default function Button({className, ...props}: ButtonProps) {
const [pending, setPending] = useState(false);
return (
<button
className={cn("bg-blue-500 py-2, px-4", className, {
"bg-gray-500" : pending, //clsx 덕분에 조건문 처리 가능
})}
{...props}
>
Submit
</button>
);
}
졸업 프로젝트 기초 셋팅은 이 정도로 마무리했다. 배포 CI/CD 쪽도 다뤄보고 싶긴했는데.. 이 부분은 좀 고민 중이라 초기 셋팅 때는 다루지 않았다:0 만약 정리가 된다면 추가로 작성해보도록 하겠습니닷.
'💻 Web' 카테고리의 다른 글
[React] 리액트를 다루는 기술 1장 - 리액트 시작 (0) | 2023.04.09 |
---|
- Total
- Today
- Yesterday
- JWT 토큰
- access token
- 리액트
- 로컬스토리지
- Subnet
- route table
- 쿠키
- 투포인터
- 이분탐색
- AWS
- NaCl
- refresh token
- VPC
- cloud
- ceos
- AwsCloudClubs
- 로그인 기능 구현
- 바리바리
- vpc peering
- 그리디
- 프론트엔드
- react
- TypeScript
- DOM
- jwt
- 리액트를 다루는 기술
- 세오스
- IGW
- 면접을 위한 CS 전공지식 노트
- 정렬
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |