이번주 스프린트로 프로젝트 셋팅을 맡았다. Package Manager(yarn berry)와 Development Environment(Eslint, Prettier, husky)를 리서치 및 셋팅하는 것이다. 꼬박 이틀에 걸친 힘든 싸움이였다..한장에 다 정리하려고 하니 천천히 알아보자
1. Package Manager
Package란?
- Module을 하나의 블럭이라고 했을 때 이러한 블럭들의 뭉치
NPM의 등장
- 여러 버전의 동일한 패키지를 한 프로젝트에서 사용할 수 있게 하자
- 설치 방식을 통일하자
- 패키지 관련 정보가 들어있는 메타 데이터를 간소화 하자
- 누구나 배포할 수 있도록 하자
Yarn의 등장
- 병렬화를 통한 속도 개선
- 자동화 된 lock 생성
- 의존성 트리 알고리즘 변경
- 캐시 사용
Pnpm & Yarn berry가 나오게 된 배경
NPM 계열의 한계
1. 비효율적 의존성 검색
- 부모 디렉터리부터 root 까지 순차적으로 node_modules를 뒤지면서 패키지 찾음
2. 유령 의존성(호이스팅)
- A, C만 사용하고 싶은데, B까지 딸려오는 경우 발생
3. 너무 무거운 node_modules
Pnpm의 등장
- 기본적인 npm 구조를 가져가지만 평탄화되지 않은 node_modules를 사용
- root 디렉터리에 pnpm store라는 레지스토리를 자체적으로 생성 -> node_modules를 그곳에 단 한번만 저장
Yarn berry의 등장
- node_modules와 node에 내장된 의존성 관리 없이 의존성을 관리하면 어떨까?
- Cache에 패키지를 zip 파일로 저장
- Zero Install (Yarn install을 불필요)
- 오프라인시에 캐싱기능으로 사용 가능
- ci 배포시에 clone만 하면 의존성이 다 있기 때문에 배포 속도 감소
-------------------------
그래서 뭐가 좋냐?
용량 비교
속도 비교
1.2 Yarn berry 설치
a. 터미널
npm install -g yarn
yarn set version berry
yarn install
b. vscode 사용자인 경우, vscode Extenstion > ZipFS 다운
c. sdk 설치
yarn dlx @yarnpkg/sdks vscode
d. zero install 사용
# .gitignore/
.yarn/*
!.yarn/cache
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
eslint 오류 발생시
1. 터미널
yarn add -D eslint-config-react-app
2. yarnrc.yml 최상단에 추가 후, 아래 코드 작성
packageExtensions:
react-scripts@*:
peerDependencies:
eslint-config-react-app: "*"
Yarn berry 사용 방법
❗️다른 명령어 필요없이 바로 git clone 후 사용하면 된다.
2. Eslint 및 Prettier
ESLint란?
- 자바스크립트 코드를 정적 분석해 잠재적인 문제를 발견하고 수정을 도와주는 도구
ESLint는 어떻게 코드를 분석할까?
- 자바스크립트 코드를 문자열로 읽는다.
- 파서(parser)로 코드를 구조화한다.
- 2번에서 구조화한 트리를 AST(Abstract Syntax Tree)라 하고, 이 트리를 기준으로 각종 규칙과 대조한다.
- 규칙과 대조했을 때 이를 위반한 코드를 알리거나 수정한다.
estlint-plugin
- 리액트, import 등 특정 프레임워크나 도메인과 관련된 규칙을 묶어서 제공하는 패키지
eslint-config
- 위 eslint-plugin을 묶어서 한 세트로 제공하는 패키지
- 여러 프로젝트에 걸쳐 동일하게 사용할 수0
- ex) eslint-config-airbnb, @titicaca/triple-config-kit, eslint-config-next
위의 리서치 결과에 따라 나는 eslint-config-airbnb를 사용하기로 했다.
2.2 Eslint 및 Prettier 설치
까다로웠던 부분만 따로 정리했다.
a. "yarn berry eslint prettier" 구글링하면 정보가 많이 나온다. 먼저 한두개정도 찾아보고 설치한 뒤, 오류가 뜨면 아래로 내려오는 걸 추천한다.
b. eslint airbnb 아래부분 참고해서 설치
[참고] https://github.com/iamturns/eslint-config-airbnb-typescript
주의할 점은 꼭 peer dependencies에 버전을 명시 해줘야하는 것이다.
여기서 나는 혹시 오류를 대비해서 FAQ > 에 있는 tsconfig.eslint.json 파일을 만들어 주는 것까지 했다.
c. eslint도 버전 다운그레이딩(v.9 -> v.8)을 해주었다.
주의할 점은 파일명이 .eslintrc -> eslint.config.js로 변경됬다는 점이다.
(맨 아래 전체 코드 참고)
3. Husky - lint-staged 설치
a. 터미널
yarn add -D husky
yarn husky install
yarn add -D lint-staged
b. yarn berry에 맞게 설치없이 다른 팀원들이 사용할 수 있게 아래 코드를 넣는다.
{
"scripts": {
...
"postinstall": "husky install"
},
...
"lint-staged": {
"*.tsx": "eslint --fix",
"*.ts": "eslint --fix"
}
}
c. pre-commit 설정
// .husky
echo pre-commit
이 전의 글을 참고하면 husky에 파일 만들고 편집하는 방법이 자세히 나온다.
d. pre-commit 작성
// .husky/pre-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
yarn lint-staged
husky 사용법
- 다른 명령어가 없다. git add -A -> git commit -m "커밋 메세지" 하면 add한 파일들만 자동으로 검사해준다.
아래는 전체 코드다. package.json을 복사하고 yarn install을 한 뒤, 오류를 해결해도 좋을 것 같다.
// package.json
{
"name": "co-task",
"version": "0.1.0",
"private": true,
"dependencies": {
"@types/node": "^16.18.96",
"@types/react": "^18.2.78",
"@types/react-dom": "^18.2.25",
"@typescript-eslint/eslint-plugin": "^7.0.0",
"@typescript-eslint/parser": "^7.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"typescript": "^4.9.5"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"postinstall": "husky install",
"lint": "eslint './src/**/*.{ts,tsx,js,jsx}'",
"lint:fix": "eslint --fix './src/**/*.{ts,tsx,js,jsx}'"
},
"lint-staged": {
"*.tsx": "eslint --fix",
"*.ts": "eslint --fix"
},
"eslintConfig": {
"extends": [
"react-app",
"airbnb",
"prettier"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@eslint/js": "^9.1.1",
"eslint": "^8.34.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-react-app": "^7.0.1",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.6",
"eslint-plugin-simple-import-sort": "^12.1.0",
"eslint-plugin-unused-imports": "^3.1.0",
"globals": "^15.0.0",
"husky": "^9.0.11",
"lint-staged": "^15.2.2",
"typescript-eslint": "^7.7.0"
}
}
// tsconfig.eslint.json
{
"extends": "./tsconfig.json",
"include": ["src/**/*.ts", "src/**/*.js", "test/**/*.ts"]
}
// eslint.config.js
module.exports = {
env: {
browser: true,
es2021: true,
},
parser: '@typescript-eslint/parser',
extends: [
'airbnb',
'airbnb-typescript',
'airbnb/hooks',
'plugin:import/errors',
'plugin:import/warnings',
'plugin:prettier/recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react/jsx-runtime',
'prettier',
],
overrides: [
{
env: {
node: true,
},
files: ['.eslintrc.{js,cjs}'],
parserOptions: {
sourceType: 'script',
},
},
],
parserOptions: {
ecmaVersion: 'latest',
ecmaFeatures: {
jsx: true,
},
sourceType: 'module',
project: './tsconfig.eslint.json',
},
plugins: ['react', '@typescript-eslint', 'prettier'],
rules: {
'react/jsx-uses-react': 'off',
'no-duplicate-imports': 'error',
'no-empty-function': 'off',
'spaced-comment': ['error', 'always'],
'import/no-duplicates': 'error',
'import/order': [
'error',
{
groups: [
'builtin',
'external',
'internal',
'parent',
'sibling',
'index',
'object',
],
alphabetize: { order: 'asc', caseInsensitive: true },
},
],
'@typescript-eslint/no-explicit-any': [
'error',
{ ignoreRestArgs: false },
],
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-unused-vars': 'warn',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/consistent-type-exports': 'error',
'@typescript-eslint/consistent-type-imports': 'error',
},
};
// .prettierrc.json
{
"endOfLine": "lf",
"singleQuote": true,
"semi": true,
"trailingComma": "all",
"tabWidth": 4,
"bracketSpacing": true,
"useTabs": true,
"printWidth": 80
}
// .prettierignore
**/\*.css
**/\*.scss
'co-task 프로젝트' 카테고리의 다른 글
[#5] Atomic Design Pattern 적용하기 (1) | 2024.04.30 |
---|---|
[#4] 프론트엔드 개발자가 만드는 Figma 디자인 | 깔끔한 todoList UI (0) | 2024.04.30 |
[#2] Github Actions로 Github Issue 생성시, Jira Issue 자동화 (0) | 2024.04.15 |
[#1] Jira 협업툴 github과 연동 | Husky로 commit message Jira 티켓번호 자동화 (0) | 2024.04.14 |