최근에 개인 프로젝트를 하나 시작했습니다. 개인 프로젝트라 협업은 아니지만 협업 과정에 있어서 프로젝트 초기 설정은 상당히 중요한 부분이라고 생각하기에 해당 프로젝트의 초기 설정 과정은 어떻게 진행했는지 그리고 필요한 부분들이 뭐가 있는지 다시 한번 상기하고 학습을 위해 글을 작성했습니다.
❗️본 프로젝트는 Vite, TypeScript, npm 기반 프로젝트이며 ESLint는 airbnb config를 사용했습니다.
과거에는 CRA
를 통해 프로젝트를 생성했었지만 Vite
를 배우고 경험한 뒤에는 항상 Vite를 사용하는 편입니다. Vite에 관한 글은 해당 글을 참고하시기 바랍니다. TypeScript를 사용할 예정이기에 React-ts 템플릿을 이용하여 프로젝트를 생성했습니다.
npm create vite@latest . -- --tamplate react-ts
프로젝트를 생성하면 다음과 같은 디렉토리 및 파일들이 생성됩니다.
먼저 vite.config.ts
를 수정했습니다. 초기 코드는 다음과 같습니다.
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
});
우선 Vite 템플릿을 사용해서 프로젝트 생성시 기본 localhost 주소는 http://localhost:5173
으로 지정됩니다. 흔히 사용하는 CRA
환경의 localhost 주소인 http://locahost:3000
을 사용하기 위해 server port를 3000으로 수정해주었습니다.
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
server: {
port: 3000,
},
});
그리고 프로젝트에서 svg 파일 사용을 위해 svgrPlugin
을 설치하고 코드에 추가해줍니다.
npm install vite-plugin-svgr
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import svgrPlugin from "vite-plugin-svgr";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react(), svgrPlugin()],
server: {
port: 3000,
},
});
마지막으로 프로젝트에서 path의 절대 경로 사용을 위해 vite-tsconfig-paths
, @types/node
를 설치해주고 코드를 다음과 같이 수정합니다.
npm install -D vite-tsconfig-paths @types/node
import * as path from "path";
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
import svgrPlugin from "vite-plugin-svgr";
export default defineConfig({
plugins: [react(), svgrPlugin()],
server: {
port: 3000,
},
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
});
프로젝트 생성 시 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
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
본인은 다음과 같이 수정했습니다. 변경한 내용만 간단히 알아보겠습니다.
{
"compilerOptions": {
"target": "ESNext",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"types": ["vite/client", "vite-plugin-svgr/client"],
"module": "ESNext",
"skipLibCheck": true,
"useDefineForClassFields": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
},
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"moduleResolution": "node",
"allowImportingTsExtensions": true,
"allowSyntheticDefaultImports": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src", "src/custom.d.ts"]
}
"target": "ESNext"
ESNext는 TypeScript가 지원하는 가장 높은 버전을 나타냅니다.
"types": ["vite/client", "vite-plugin-svgr/client"]
svg 파일 사용을 위해 정의했습니다.
"baseUrl": "."
, "paths": {"@/*": ["./src/*"]},
절대 경로 사용을 위해 정의했습니다.
"moduleResolution": "node"
node module 방식 사용을 위해 정의했습니다.
"allowSyntheticDefaultImports": true
흔히 우리가 아는 다음과 같은 import 방식 사용을 위해 정의했습니다.
import React from "react";
"include": ["src/custom.d.ts"]
svg 파일 사용을 위해 정의했습니다. custom.d.ts
파일은 다음과 같습니다.
declare module "*.svg" {
import React = require("react");
export const ReactComponent: REact.FC<React.SVGProps<SVGSVGElement>>;
const src: string;
export default src;
}
svg 파일은 그냥 사용하면 자바스크립트 모듈처럼 사용이 불가능하기에 import
방식으로 사용을 위해 설정해주었습니다.
이외에 tsconfig 관련은 공식문서를 확인하시면 더 세부적인 내용을 확인하실 수 있습니다.
ESLint 설정을 확인하기 전에 ESLint, Lint에 대해 모르는 분들을 위해 간단히 알아보겠습니다.
❗️ ESLint는 린트(lint) 작업을 해주는 린터(Linter)이다.
린트(lint)
는 소스 코드에 문제가 있는지 탐색하는 작업을 의미합니다. 린터(linter)
는 이 작업을 도와주는 소프트웨어입니다.
자바스크립트는 컴파일 과정이 없는 인터프리터 언어이기에 런타임 에러가 자주 발생하곤 합니다. 린트 작업을 통해 사전에 에러를 최대한 확인하고 수정할 수 있습니다.
ESLint
는 린터중 하나이며 최근 개발자들이 많이 사용하는 린터입니다.
vite 템플릿을 이용해 프로젝트 생성 시 lint 설정이 이미 담겨있습니다.
본 포스트는 해당 설정들을 다 지웠다는 가정 하에 설정합니다.
우선 ESLint
를 설치해주어야 합니다. ESLint와 동시에 필요한 parser와 plug-in도 함께 설치해주었습니다.
npm install -D eslint@8.2.0 @typescript-eslint/eslint-plugin @typescript-eslint/parser
ESLint를 일부로 8.2.0 버전으로 설치해주었는데 이유는 뒤에서 언급하겠습니다.
여러 회사들이 ESLint를 사용중인데 airbnb-config
는 airbnb사에서 사용하고 있는 ESLint 규칙입니다. airbnb-config
사용을 위해 필요한 dependency들은 다음 명령어를 통해 확인 할 수 있습니다.
npm info "eslint-config-airbnb@latest" peerDependencies
하나하나 명령어를 통해 설치할 수 있지만 npm
version이 5 이상이라면 다음 명령어를 사용해 한번에 설치할 수 있습니다.
npx install-peerdeps --dev eslint-config-airbnb
사진을 확인하면 알 수 있듯 airbnb-config는 eslint의 version이 8.2.0 아래여야 합니다. 현 시점 eslint의 최신 버전은 8.5.0이므로 위에서 일부로 8.2.0 버전을 설치해주었습니다.
설치를 완료했으니 설정을 위해 root 디렉토리
에 .eslintrc.json
파일을 생성해줍니다. 그 후 다음과 같이 파일을 작성해줍니다.
{
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint"
],
"extends": [
"airbnb",
"airbnb/hooks",
"plugin:@typescript-eslint/recommended",
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": "latest",
"sourceType": "module"
},
}
설정을 완료했으니 테스트로 안쓰는 변수 하나를 선언하고 터미널에 npm run lint
를 실행하면 다음과 같은 오류를 확인할 수 있습니다.
ESLint rule 등 자세한 내용은 추후에 다시 알아보도록 하겠습니다.
Prettier
또한 모르는 분들을 위해 간단히 알아보겠습니다.
Prettier
는 코드 포맷의 통일성을 유지시켜주는 JavaScript 라이브러리입니다. 깔끔한 코드와 협업을 위해서는 일관성 있는 통일된 코드 스타일을 유지하는 것이 매우 중요합니다. ESLint
가 코드 퀄리티를 일관적으로 유지해준다면 Prettier
는 일관적인 코드 스타일을 유지할 수 있게 도와주는 툴입니다.
ESLint는 문법 에러를 잡아주거나 더 좋은 코드 구현 방식을 사용하도록 해준다면 Prettier는 줄 바꿈, 공백, 들여쓰기 등과 같은 스타일을 정할 수 있습니다.
우선 Prettier
를 설치해 줍니다.
npm install -D prettier eslint-config-prettier
그 후 root
디렉토리에 .prettierrc 파일을 생성해줍니다. 해당 파일에 필요한 rule을 추가하면 됩니다. 이 파일이 없으면 기본값으로 세팅됩니다.
prettier rule은 다음과 같은 옵션들이 있습니다.
{
"arrowParens": "avoid", // 화살표 함수 괄호 사용 방식
"bracketSpacing": false, // 객체 리터럴에서 괄호에 공백 삽입 여부
"endOfLine": "auto", // EoF 방식, OS별로 처리 방식이 다름
"htmlWhitespaceSensitivity": "css", // HTML 공백 감도 설정
"jsxBracketSameLine": false, // JSX의 마지막 `>`를 다음 줄로 내릴지 여부
"jsxSingleQuote": false, // JSX에 singe 쿼테이션 사용 여부
"printWidth": 80, // 줄 바꿈 할 폭 길이
"proseWrap": "preserve", // markdown 텍스트의 줄바꿈 방식 (v1.8.2)
"quoteProps": "as-needed" // 객체 속성에 쿼테이션 적용 방식
"semi": true, // 세미콜론 사용 여부
"singleQuote": true, // single 쿼테이션 사용 여부
"tabWidth": 2, // 탭 너비
"trailingComma": "all", // 여러 줄을 사용할 때, 후행 콤마 사용 방식
"useTabs": false, // 탭 사용 여부
"vueIndentScriptAndStyle": true, // Vue 파일의 script와 style 태그의 들여쓰기 여부 (v1.19.0)
"parser": '', // 사용할 parser를 지정, 자동으로 지정됨
"filepath": '', // parser를 유추할 수 있는 파일을 지정
"rangeStart": 0, // 포맷팅을 부분 적용할 파일의 시작 라인 지정
"rangeEnd": Infinity, // 포맷팅 부분 적용할 파일의 끝 라인 지정,
"requirePragma": false, // 파일 상단에 미리 정의된 주석을 작성하고 Pragma로 포맷팅 사용 여부 지정 (v1.8.0)
"insertPragma": false, // 미리 정의된 @format marker의 사용 여부 (v1.8.0)
"overrides": [
{
"files": "*.json",
"options": {
"printWidth": 200
}
}
], // 특정 파일별로 옵션을 다르게 지정함, ESLint 방식 사용
}
본인은 다음과 같이 설정해주었습니다. 여러 rule들이 있기에 협업 초기 설정 단계에서 논의하고 필요한 rule들을 추가해주면 좋을 거 같습니다.
{
"singleQuote": false,
"parser": "typescript",
"semi": true,
"tabWidth": 2,
"trailingComma": "all",
"useTabs": true,
"printWidth": 80
}
추가적으로 ESLint 관련 2가지 설정을 더 해주었습니다.
프로젝트 저장할 때 자동으로 lint:fix
가 실행되게 설정할 수 있습니다. 설정창을 켜고
code action on save
을 검색한 후 settings.json에서 편집
에 들어갑니다.
다음과 같은 코드를 추가해줍니다.
"editor.codeActionsOnSave": {
"source.fixAll": true,
},
"editor.formatOnSave": false,
이러면 프로젝트에서 코드 수정 후 저장 시 자동으로 lint:fix
가 작동하는 것을 확인하실 수 있습니다.
❗️husky는 프로젝트와 git이 연결되어 있는 상태여야 사용이 가능합니다.
husky
는 간단히 얘기하면 git hooks을 쉽게 사용할 수 있도록 도와주는 패키지입니다. 해당 프로젝트에서는 git commit 이전에 lint 및 prettier를 점검 및 체크할 수 있게 사용했습니다.
우선 husky와 lint-staged를 설치해줍니다.
npm install -D husky lint-staged
commit을 하기 직전에 lint 체크를 위해 명렁어를 통해 husky 디렉토리와 pre-commit 파일을 생성해줍니다.
npx husky add .husky/pre-commit "npx lint-staged
그럼 다음 사진과 같이 디렉토리와 pre-commit 파일이 생성됩니다.
package.json
파일에 다음과 같은 코드를 추가해줍니다.
"scripts": {
"prepare": "husky install"
},
"lint-staged": {
"src/**/*.{js,jsx,ts,tsx}": [
"eslint --fix"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
}
그 후 commit을 진행해보면 lint 명령어가 자동으로 실행되는 것을 확인할 수 있습니다. 동일하게 사용하지 않는 변수를 테스트로 생성하고 commit을 진행하면 lint에 걸려서 commit이 진행되지 않는 것을 확인할 수 있습니다.
위에서 언급했던 설정들 이외에도 협업 과정 프로젝트 초기 설정 단계에서 맞춰가야 하는 부분들이 더 있다고 생각합니다. Git flow
와 PR, ISSUE
tamplate 작성 같은 github 적인 요소나 code convention 등 프로젝트를 진행하면서 맞춰가도 되지만 구조와 틀을 정해놓고 시작하는게 프로젝트 과정 및 완성도에 중요한 역할을 한다고 생각해서 개인 프로젝트를 시작하는 김에 하나씩 작성해보았습니다.
간단하게 다루었지만 세부적인 각각의 내용들은 추후 다시 알아볼 예정입니다.
Vite 공식 문서
https://vitejs.dev/
tsconfig 공식 문서
https://www.typescriptlang.org/ko/tsconfig
ESLint 공식 문서
https://eslint.org/
Prettier 공식 문서
https://prettier.io/
Husky 공식 문서
https://typicode.github.io/husky/
svg 관련
https://stackoverflow.com/questions/44717164/unable-to-import-svg-files-in-typescript
airbnb-config npm 문서
https://www.npmjs.com/package/eslint-config-airbnb
ESLint와 Prettier가 무엇이며 왜 필요하고 어떻게 사용하는지
https://velog.io/@treejy/React-ESLint%EC%99%80-Prettier%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%B4%EB%A9%B0-%EC%99%9C-%ED%95%84%EC%9A%94%ED%95%98%EA%B3%A0-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94%EC%A7%80#prettier%EB%9E%80
eslint를 사용할 때 prettier의 설정
https://heewon26.tistory.com/262
VS Code ESLint 저장 시 자동 Fix, Format 설정하기
https://streamls.tistory.com/entry/VS-Code-ESLint-%EC%A0%80%EC%9E%A5-%EC%8B%9C-%EC%9E%90%EB%8F%99-Fix-Format-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0#google_vignette
[React] husky
https://velog.io/@hanei100/React-husky