들어가며
이번에 Next.js App Router 기반의 새로운 팀 프로젝트를 시작하면서 처음으로 환경 세팅을 해보게 되었습니다. 이미 잘 세팅된 환경에서만 작업해본 경험 뿐이라 막막했지만, 팀원들의 가이드와 도움을 받아 시도할 수 있었습니다.
Next.js 프로젝트 생성
우선 Next.js의 App Router 방식을 사용해 프로젝트를 생성했고, TypeScript, ESLint, Tailwind CSS 등의 옵션도 함께 선택했습니다.
npx create-next-app@latest
설치 옵션:
- TypeScript: Yes
- ESLint: Yes
- Tailwind CSS: 필요 시 Yes
- App Router: Yes
- Turbopack: Yes
이렇게 하고 나니 기본적인 프로젝트 구조가 잡혔고,
그다음 단계로 팀 코드 환경을 통일하는 작업에 들어갔습니다.
Node 버전 통일
팀원들마다 Node 버전이 다를 수 있어서, 나중에 의존성 충돌이 생길까 봐
처음부터 .nvmrc를 만들어 팀의 Node 버전(22.14.0)을 명시해두었습니다.
(echo "22.14.0" > .nvmrc 명령어로 작성하거나, 수동으로 입력해도 됩니다.)
이렇게 하면 nvm use로 같은 버전을 쉽게 맞출 수 있고,
package-lock.json 충돌을 예방할 수 있습니다. 🙂
Prettier, Stylelint, ESLint, Husky 단계적 세팅
처음엔 Prettier부터 시작해서, Stylelint, ESLint, Husky까지 순차적으로 세팅했습니다.
- Prettier
자동 코드 포맷터.
세미콜론, 들여쓰기, 따옴표 등 코드 스타일을 자동으로 맞춰주는 도구.
“코드의 모양(스타일)”을 통일시켜서 협업 때 불필요한 수정 충돌을 방지!
// .prettierrc
{
"trailingComma": "all",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"printWidth": 100,
"endOfLine": "auto",
"useTabs": false,
"arrowParens": "always",
"htmlWhitespaceSensitivity": "ignore"
}
- Stylelint
CSS, SCSS 등의 스타일 코드 검사기.
잘못된 스타일 문법이나 일관성 없는 코드를 잡아주며,
CSS도 팀 규칙에 맞게 쓰도록 도와줍니다.
// .stylelintrc.json
{
"extends": [
"stylelint-prettier",
"stylelint-config-standard-scss",
"stylelint-config-idiomatic-order"
],
"plugins": ["stylelint-scss", "stylelint-order"],
"rules": {
"scss/no-global-function-names": null,
"function-url-quotes": "never",
"property-no-vendor-prefix": null,
"selector-pseudo-class-no-unknown": null,
"no-descending-specificity": null,
"order/properties-order": [
{
"groupName": "positioning",
"emptyLineBefore": "never",
"properties": ["position", "top", "right", "bottom", "left", "z-index"]
},
{
"groupName": "box-model",
"emptyLineBefore": "never",
"properties": [
"display",
"flex-direction",
"flex-wrap",
"justify-content",
"align-items",
"align-self",
"order",
"width",
"height",
"margin",
"margin-top",
"margin-right",
"margin-bottom",
"margin-left",
"padding",
"padding-top",
"padding-right",
"padding-bottom",
"padding-left",
"border",
"border-width",
"border-style",
"border-color",
"border-radius",
"box-sizing"
]
},
{
"groupName": "typography",
"emptyLineBefore": "never",
"properties": [
"font",
"font-family",
"font-size",
"font-weight",
"font-style",
"line-height",
"letter-spacing",
"text-align",
"text-decoration",
"text-transform",
"color"
]
},
{
"groupName": "visual",
"emptyLineBefore": "never",
"properties": [
"background",
"background-color",
"background-image",
"background-repeat",
"background-position",
"background-size",
"background-clip",
"background-origin",
"box-shadow",
"opacity",
"outline",
"outline-width",
"outline-style",
"outline-color",
"outline-offset",
"filter",
"mix-blend-mode",
"isolation",
"backdrop-filter"
]
},
{
"groupName": "misc",
"emptyLineBefore": "never",
"properties": [
"cursor",
"pointer-events",
"visibility",
"clip",
"clip-path",
"overflow",
"overflow-x",
"overflow-y",
"transform",
"transform-origin",
"transition",
"transition-property",
"transition-duration",
"transition-timing-function",
"transition-delay",
"animation",
"animation-name",
"animation-duration",
"animation-timing-function",
"animation-delay",
"animation-iteration-count",
"animation-direction",
"animation-fill-mode",
"animation-play-state"
]
}
],
"order/properties-alphabetical-order": null
}
}
- ESLint
JavaScript/TypeScript 코드 검사기.
문법 오류부터 코드 품질, 팀 규칙까지 전반적으로 검사!
airbnb나 prettier 등과 함께 팀 스타일을 유지하기 위한 룰을 쉽게 관리할 수 있습니다.
// .eslintrc.json
{
"extends": ["airbnb", "airbnb-typescript", "next/core-web-vitals", "plugin:prettier/recommended"],
"parserOptions": {
"project": "./tsconfig.json"
},
"rules": {
"semi": ["error", "always"],
"quotes": ["error", "single"],
"array-callback-return": "off",
"react/require-default-props": "off",
"react/no-array-index-key": "off",
"react/function-component-definition": [2, { "namedComponents": "arrow-function" }],
"react/jsx-props-no-spreading": "off",
"jsx-a11y/click-events-have-key-events": 0,
"jsx-a11y/label-has-associated-control": 0,
"jsx-a11y/no-noninteractive-element-interactions": 0,
"jsx-a11y/no-static-element-interactions": 0,
"jsx-a11y/mouse-events-have-key-events": 0,
"jsx-a11y/anchor-is-valid": 0,
"react/no-unstable-nested-components": 0,
"react/react-in-jsx-scope": 0,
"react/prefer-stateless-function": 0,
"react/jsx-filename-extension": 0,
"react/jsx-one-expression-per-line": 0,
"no-nested-ternary": 0,
"no-undef": "off",
"no-useless-escape": "off",
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "error",
"import/prefer-default-export": "off",
"prettier/prettier": [
"error",
{
"endOfLine": "auto",
"useTabs": false
}
],
"indent": ["error", 2, { "SwitchCase": 1 }],
"@typescript-eslint/no-empty-interface": "off",
"no-empty-interface": "off",
"react/button-has-type": "off",
"import/extensions": "off"
}
}
예상 못한 문제: eslint airbnb 룰 충돌
처음엔 airbnb 룰을 기본으로 쓰려 했는데, Next.js가 사용하는 eslint 9 버전과 airbnb가 지원하는 8 버전이 충돌나서 한참 헤맸습니다.
결국 eslint를 8로 내리고 airbnb, airbnb-typescript를 다시 설치!
airbnb 룰에서 필요없는 것들은 덮어써서 팀 스타일에 맞췄습니다.
- Husky
Git hook 관리 도구.
커밋하기 전에 lint나 테스트가 통과됐는지 자동으로 검사.
“커밋 전에 자동으로 검사/포맷”을 실행해서 팀 코드 품질을 지켜줍니다.
마치며
Prettier, Stylelint, ESLint, Husky까지 순서대로 세팅하면서,
팀 코드 스타일을 단계적으로 통일하고, 협업 환경을 정비할 수 있었습니다.
작업 중에는 예상 못한 충돌이나 작은 실수도 있었지만,
그 헤매는 과정 덕분에 그냥 지나쳤을 것들을 한번 더 볼 수 있었던 것 같습니다.
차근차근 해결하면서 “환경 세팅이 단순히 도구 설치가 아니라, 협업 문화를 만드는 출발점”이라는 걸 느꼈습니다.
아직 공부가 더 필요하지만, 앞으로는 예전보다 겁먹지 않고 환경 세팅을 더 자연스럽게 진행할 수 있을 것 같습니다!
많이 도와주고 기다려준 팀원들 늘 감사합니다.🫶