프론트엔드 개발 환경을 제공하는 Vite(비트)와, React를 이용하여 프로젝트 구조를 알아보자.
먼저, Vite 공식페이지을 참고하여 Vite를 설치한다.
npm을 사용하고 있기 때문에 다음의 명령어를 통해 vite를 이용하여 프로젝트를 생성해준다.
npm create vite@latest
프로젝트 이름과, 사용할 프레임워크를 선택해준다.
React를 사용할 것이므로, React를 선택해준다.
또한, TypeScript를 사용할 것이므로, 선택해준다.
이렇게 선택을 마치면, 다음과 같이 프로젝트 구조가 어느정도 잡힌 상태로 프로젝트가 생성된다.
── test
├─ eslint.config.js
├─ index.html
├─ package.json
├─ public
│ └─ vite.svg
├─ README.md
├─ src
│ ├─ App.css
│ ├─ App.tsx
│ ├─ assets
│ │ └─ react.svg
│ ├─ index.css
│ ├─ main.tsx
│ └─ vite-env.d.ts
├─ tsconfig.app.json
├─ tsconfig.json
├─ tsconfig.node.json
└─ vite.config.ts
이제 npm i
를 이용하여 package.json의 라이브러리들의 설치를 수행해주고,
npm run dev
를 통해, 기본적인 웹 애플리케이션이 로컬서버에서 구동되게 된다.
vite로 프로젝트를 구성하면 기본적으로 http://localhost:5173/
로 서버가 열리기 때문에 해당 url로 접속하면 vite + react 앱의 동작을 확인할 수 있다.
자동으로 구성된 파일들 하나하나를 살펴보자.
── Vite 프로젝트
├─ eslint.config.js
├─ index.html
├─ package.json
├─ public
│ └─ vite.svg
├─ README.md
├─ src
│ ├─ App.css
│ ├─ App.tsx
│ ├─ assets
│ │ └─ react.svg
│ ├─ index.css
│ ├─ main.tsx
│ └─ vite-env.d.ts
├─ tsconfig.app.json
├─ tsconfig.json
├─ tsconfig.node.json
└─ vite.config.ts
Vite로 프로젝트를 생성하면, 이 public 폴더 안에 vite.svg라는 파일이 생성되어 있다.
index.html에서 <link rel="icon" type="image/svg+xml" href="/vite.svg" />
에 사용되는 favicon 이미지 파일이다.
이 public 디렉토리에 위치한 파일들은 기본적으로 /
루트에서 제공되고, 빌드 과정에서 파일의 변환없이 정적 파일로 배포된다.
즉, 정적 파일을 모아두는 디렉토리이다.
소스 코드, 즉 앱의 핵심 파일들이 위치하는 디렉토리이다.
이 디렉토리에서 apis
, pages
, styles
, stores
types
, components
, contexts
, hooks
, models
등의 목적에 맞게 폴더를 생성하여 코드들을 관리할 수 있다.
애플리케이션에서 사용되는 정적 리소스들을 보관하는 폴더이다.
App.tsx의 CSS를 정의한다.
main.tsx의 파일에서 컴포넌트로써 사용된다.
프로젝트의 핵심 기능을 App.tsx에 작성한다.
즉, 작성한 컴포넌트들을 이 파일에 적절히 배치하면 된다.
전역 CSS 스타일을 정의하는 파일이다.
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
}
위처럼 모든 컴포넌트에 공통적으로 적용할 CSS를 지정할 수 있다.
브라우저 간의 css 격차를 줄이기 위해 보통 reset CSS
라는 것을 사용하는데,
그러한 공통 css가 이 파일에 설정될 수 있다.
이 파일을 src
> styles
폴더에 작성하여 스타일 파일들끼리 모아두는 것도 방법이다.
(이 경우에는 당연히 main.tsx
파일의 import './index.css'
부분을 경로와 파일명에 맞게 변경해줘야 한다.)
index.html에서 script의 모듈로써 인식되는 js파일이다.
즉, 애플리케이션의 진입점이다.
main.tsx에는 App
컴포넌트가 들어있다.
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
)
즉,
App.tsx
-> main.tsx
-> index.html
로 전달하여 렌더링된다.
Vite에서 자동으로 생성된 TypeScript 선언 파일이다.
Vite 관련 전역 타입 정의가 포함되어 있으며, TypeScript가 Vite의 특수한 환경을 이해하고 타입 체크를 수행할 수 있도록 하는 역할이다.
딱히 설정을 건드릴 필요는 없다.
eslint.config.js
★★ - prettierESLint 설정파일이다. 먼저 ESLint에 대해 간단하게 말하자면, 코드의 문제점을 찾아내고 일관성을 유지하도록 도와주는 도구이다. 예를 들어, 선언은 되었지만 사용되지 않는 변수에 대해 경고를 나타낸다든가, ==
대신 ===
를 사용한다든가 하는 상황에서 경고를 발생시킨다.
내용은 다음과 같다.
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
)
config 파일에 내용을 추가하여 설정을 추가할 수 있다.
특히, prettier를 같이 사용하고자 한다면 추가 설정을 해줘야 하는데, 하단에서 기술하겠다.
애플리케이션이 시작되는 html파일이다.
Vite를 통해 기본 작성된 내용은 다음과 같다.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
script 태그를 보면 알겠지만, main.tsx 자바스크립트 파일이 삽입되면서 리액트를 통해 작성한 코드가 변환되어 html에 올바르게 렌더링 될 수 있는 것이다.
프로젝트의 dependencies, scripts 등이 정의된 파일이다.
특정 라이브러리를 추가하거나 모듈을 설치하면 이 파일에 추가가 된다.
github를 이용할 때, 모듈들이 설치된 node_modules
폴더는 제외하고 업로드하는데,
package.json이 포함된 프로젝트를 git clone한 뒤, npm i
명령을 수행하면 package.json을 참고하여 필요한 라이브러리들이 설치된다.
프로젝트에 대한 설명을 마크다운 언어로 작성할 수 있는 파일이다.
프로젝트에 대한 소개, 라이선스, 사용 방법 등이 들어갈 수 있다.
TypeScript 설정 파일로, 애플리케이션 코드에 적용되는 TypeScript 컴파일러 옵션을 정의한다.
특정 환경(앱 코드, 테스트 코드 등)에 대한 설정이 포함될 수 있다.
이 파일도 보통은 딱히 설정을 건드릴 필요는 없다.
TypeScript 컴파일러 옵션을 설정하는 파일이다.
TypeScript 설정을 정의하고, TypeScript 컴파일러가 어떻게 코드를 해석하고 JS파일로 변환할지 지시한다.
비어있는 디렉토리에 tsc --init
명령어를 입력하면, 상세한 tsconfig.json 파일이 생성되는데, 해당 파일을 확인해보면 어떤 옵션들이 있는지 확인할 수 있다.
Vite가 자동생성한 tsconfig.json에는 다음과 같이 작성되어 있다.
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}
여기서 주로 추가되는 설정들은 다음과 같다.
{
"compilerOptions" : {
"target" : "esnext", // ECMAScript 버전
"module" : "esnext", // 모듈 시스템. esnext-최신 버전
"strict" : true, // 엄격한 타입 검사 ( true 권장 )
"esModuleInterop" : true, // CommonJS 모듈을 ES6 모듈처럼 사용 가능
// import * as fooModule from './commonjs-module'를
// import foo from './commonjs-module'; 로 사용 가능하게 해줌.
// 즉, default import, named import 모두 사용 가능
// 아래의 "allowSyntheticDefaultImports" 옵션과 같이 사용하는 경우가 많음.
"skipLibCheck" : true, // 라이브러리 파일의 타입 검사를 건너뜀.
"forceConsistentCasingInFileNames" : true, // 파일 이름의 대소문자 일관성 강제
"baseUrl" : ".", // 모듈 해석을 위한 기본 디렉토리 지정.
// 예를 들어, baseUrl : "." 일땐, ./src/abcd.ts 로 입력,
// baseUrl : "./src" 일땐, ./abcd.ts 로 입력
"paths" : {
"@/*" : ["src/*"]
}, // `@` 는 `/src` 경로를 의미하도록 별칭 설정
"typeRoots" : ["node_modules/@types"] // ["node_modules/@types"] 가 default
// 타입 정의 파일이 위치하는 디렉토리를 지정
// include 옵션에서 이미 .d.ts 파일이 포함된 경우, typeRoots는 type.d.ts 파일을 자동으로 인식되므로 지정하지않아도 됨
// typeRoots를 추가적으로 지정했을 경우, ["node_modules/@types"]는 반드시 작성해야함.
// 외부 모듈을 사용할 때, Could not find a declaration file for module 오류가 발생하면,
// 1. @type/모듈명 을 설치하거나, 2. 직접 정의해서 이 부분에 추가해야함.
"types" : ["node"], // typeRoots의 경로에서 찾은 특정 타입 선언 파일만 포함하도록 제한
"allowSyntheticDefaultImports" : true, // CommonJS 모듈을 ES6 스타일로 import 가능.
// default export를 하지 않아도, default import 문법을 사용 가능
"jsx": "react-jsx" // React 16이하의 버전일때,
// React.createElement을 createElement로 작성해도 알아서 변환이 가능하게 함.
"moduleResolution" : "node" // TypeScript가 모듈을 어떻게 해석할지 결정.
// "node" - Node.js 스타일의 모듈 해석을 사용
// "classic": TypeScript의 오래된 모듈 해석 방식. 레거시 코드에서만 사용
// 예를 들어, "node" 설정 시, src/components/Button.tsx 파일을
// src/components/Button으로 해석
// default값은 "node" 임
}
"include" : ["src/**/*"], // 또는, "include": ["src/**/*.ts", "src/**/*.tsx"]
// 컴파일할 파일이나, 디렉토리 지정
"exclude" : ["node_modules", "dist"], // 컴파일에서 제외할 파일/디렉토리 지정,
"files" : ["src/index.ts"], // 특정 파일만 컴파일. 보통은 사용 X, include 옵션으로.
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
] // 다른 파일의 설정들을 참조한다. 사실, 위에서 설명한 옵션들은 대부분
// tsconfig.app.json이나, "tsconfig.node.json"에 명시되어 있다.
// 필요한 부분만 tsconfig.json에 추가하면 되겠다.
}
tsconfig.json의 paths 설정과,
vite.config.ts 의 alias 설정이 헷갈릴 수 있다.
파일 | 목적 |
---|---|
tsconfig.json - paths |
TS 컴파일러가 모듈의 경로를 해석할 때 사용 TS의 타입검사와 코드 완성 기능에 영향 |
vite.config.ts - alias | 런타임에서 모듈을 찾는데에 사용 |
특정 경로에 대해 별칭을 설정하고 싶다면, tsconfig.json의 paths 설정과,
vite.config.ts의 alias 설정을 모두 동일하게 설정해주는 편이 좋다.
ex)
// tsconfig.json
{
"compilerOptions": {
"paths": {
"@/*": ["src/*"]
}
},
// vite.config.ts
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
});
Node.js 관련 TypeScript 설정을 정의하는 파일이다.
vite.config.ts와 같은 Vite의 설정 파일을 컴파일할 때 사용된다.
이 파일도 딱히 설정을 건드릴 필요는 없다.
Vite의 설정 파일이다.
이 파일에서 Vite의 동작을 커스터마이징 할 수 있다.
플러그인을 추가하거나, ./src
경로를 @
로 단축해서 사용할 수 있는 alias 를 설정할 수 있다.
Vite를 이용해서 프로젝트를 생성하면, src폴더에는 asset폴더 외에는 별다른 폴더가 없다.
따라서, 동료들과 상의 후에 목적에 맞는 폴더들을 추가하면 된다.
예를 들면 다음과 같다.
├─ src
│ ├─ assets // 정적 파일들을 모아두는 폴더
│ ├─ apis // api들을 모아두는 폴더
│ ├─ components // 공통 컴포넌트들을 모아두는 폴더
│ ├─ contexts // context api들을 모아두는 폴더
│ ├─ hooks // 커스텀 훅을 모아두는 폴더
│ ├─ models // 모델을 모아두는 폴더
│ ├─ stores // global state의 store을 모아두는 폴더
│ ├─ styles // 스타일을 모아두는 폴더
│ ├─ types // 타입에 대한 정의를 모아두는 폴더
│ ├─ pages // 페이지들을 모아두는 폴더
동료들과 동일한 개발 환경을 구축하기 위해, 필요한 라이브러리들은 미리 설치해두면 좋다.
Prettier는 코드의 줄바꿈, 큰따옴표 작은따옴표 등 일관성을 유지시켜주는 extension이다.
Prettier를 사용하기 위해서는 다음과 같은 셋업이 필요하다.
prettier 설치
npm install --save-dev --save-exact prettier
.prettierrc
파일을 생성한다.ex)
{
"printWidth": 80,
"tabWidth": 2,
"semi": true,
"singleQuote": false,
"trailingComma": "all",
"bracketSpacing": true,
"arrowParens": "avoid",
"endOfLine": "lf"
}
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"bracketSpacing": true,
"jsxSingleQuote": false,
"jsxBracketSameLine": false,
"arrowParens": "always",
"endOfLine": "auto"
}
"scripts": {
"format": "prettier --write ."
}
위와 같이 package.json을 설정해두면, npm run format
명령어가 모든 파일을 일관된 스타일로 포맷팅해준다.
vscode extension 설치 - Prettier - Code formatter
vscode - 저장 시 코드 포매팅 설정
ctrl + ,
로 setting 창을 열고, Default Formatter
를 검색한다.Prettier - Code formatter
로 설정한다.Format on save
를 검색하고, 체크한다.이제 ESLint 설정에 대해 알아보자.
Vite를 사용하면 eslint.config.ts
파일이 생성되고 작성되지만, 만약 prettier와 함께 사용한다면 수정해야 할 부분이 있다.
패키지 설치
npm install eslint-plugin-prettier eslint-config-prettier --save-dev
eslint.config.ts 수정
import js from '@eslint/js';
import globals from 'globals';
import reactHooks from 'eslint-plugin-react-hooks';
import reactRefresh from 'eslint-plugin-react-refresh';
import tsParser from '@typescript-eslint/parser'; // TypeScript 파서
import tseslint from '@typescript-eslint/eslint-plugin'; // TypeScript ESLint 플러그인
import prettier from 'eslint-plugin-prettier';
import prettierConfig from 'eslint-config-prettier'; // Prettier 설정
export default tseslint.config(
{
ignores: ['dist'],
},
{
parser: tsParser, // TypeScript 파서 지정
extends: [
js.configs.recommended,
...tseslint.configs.recommended,
'plugin:prettier/recommended', // Prettier 설정 추가
],
files: ['**/*.{js,jsx,ts,tsx}'], // JavaScript 및 TypeScript 파일 포함
languageOptions: {
ecmaVersion: 2020,
sourceType: 'module',
globals: globals.browser,
},
plugins: [
'@typescript-eslint', // TypeScript ESLint 플러그인
'react-hooks',
'react-refresh',
'prettier', // Prettier 플러그인 추가
],
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
'prettier/prettier': 'error', // Prettier 포맷팅 오류를 ESLint 오류로 표시
},
}
);