SPA (Single Page Application)
의미
- 하나의 HTML 페이지로 구성된 웹 애플리케이션
- 클라이언트 측에서 페이지 전환을 처리
특징
- 최초 로드 후 추가적인 페이지 요청 없이 동작
- 빠른 사용자 경험
- React, Vue, Angular로 구현 가능
장점
서버 부하 감소화 됩니다.
- 초기로드 이후에는 필요한 데이터만 전송하기 때문입니다.
단점
SEO 최적화 어려움
( JavaScrpit 렌더링이 필요한 콘텐츠는 검색엔진이 인식하기 어렵습니다.
그리고 각 페이지별 메타태그가 존재하지 않기 때문입니다. )
작동방식
초기 로드 시 전체 애플리케이션을 다운로드(번들구성(번들.js)하고 이후 웹에서 사용자 상호 작용에 따라 필요한 데이터만 서버에서 가져와 동적으로 페이지를 업데이트 합니다.
MPA (Multi Page Application)
의미
여러 HTML 페이지로 구성된 전통적인 웹 애플리케이션
특징
- 페이지 구성 : 각 페이지가 독립적인 html파일로 존재
- 페이지 이동 : 사용자가 새로운 페이지로 이동할때마다 서버에서 해당 html파일을 받아 브라우저에서 랜더링
- 랜더링 방식 : 주로 SSR방식을 사용
장점
- SEO에 최적화 : 각 페이지가 독립된 URL과 콘텐츠를 가지고 있어, 검색 엔진이 쉽게 크롤링하고 인덱싱 할 수 있음
- 브라우저 호완성 : 오래된 브라우저에서 잘 작동하며 특별한 기술이나 라이브러리가 필요하지 않습니다.
- 보안 : 서버측에서 추가적인 보안제어가 가능합니다.
단점
- 페이지 로딩 : 새로운 페이지로 이동할 때 마다 전체 페이지를 다시 로드해야므로 로딩 시간이 길어질 수 있습니다.
- 서버 부하 : 사용자의 모든 요청을 서버가 처리해야 하므로 트레픽이 많은 경우 서버의 부담이 큽니다.
- 사용자 경험 : 페이지 전환 시 화면 전체가 깜박이며, 다시 로딩되므로 사용자 경험에 좋지 않습니다.
CSR (Client-Side Rendering)
의미
웹 애플리케이션 렌더링을 사용자의 브라우저에서 수행하는 방식입니다.
JavaScprit를 사용하여 브라우저에서 웹 사이트나 애플리케이션을 렌더링 합니다.
작동방식
- 초기요청 : 사용자가 웹 페이지를 요청하면 서버는 최소한의 html파일과 함께 JavaScrpit, css를 포함하여 응답합니다.
- 리소스 다운로드 : 브라우저는 해당 html파일을 파싱하고 css와 JavaScript파일을 다운로드 합니다.
- 렌더링 : 다운로드된 JavaScript가 실행되어 페이지에 콘텐츠를 동적으로 생성하고 사용자 인터페이스를 구성합니다.
장점
- 서버 부하 감소(서버는 최소한의 html과 정적 데이터만 제공함으로 서버 부하를 줄어듭니다.)
- 동적 인터렉티브 경험 : csr은 사용자 사용작용에 즉각적으로 반응할 수 있는 동적이고 인터렉티브한 웹 에플리케이션을 구축하는데 적합합니다. 이는 실시간 업데이트가 필요한 어플리케이션에 유리 합니다.
- 빠른 후속 페이지 로드 : 초기 로드 이후에는 페이지 전환이 빠르게 이루어 지며 전체 페이지를 다시 로드할 필요 없이 필요한 데이터만 갱신합니다.
단점
- SEO 문제 : 초기 html이 빈상태로 제공되므로 검색엔진 크롤러가 콘텐츠를 제대로 인식하지 못할 수 있어 SEO에 불리합니다.
- 초기 로딩 시간 증가 : 초기 페이지 로딩 시 브라우저가 모든 JavaScrpit파일을 다운로드하고 실행하므로 시간이 더 걸릴 수 있습니다.
- 일관적이지 못한 사용자 경험 : CSR은 클라이언트 디바이스 상태에 따라 사용자 경험이 달라질 수 있습니다. 이는 인터넷 연결 속도나 브라우저 호환성에 따라 영향을 받을 수 있습니다.
SSG (Static Site Generation)
의미
빌드 시점의 모든 페이지를 정적 html파일로 생성하는 방식 입니다.
- 대표적인 사례로 블로그, 포토폴리오, 웹 사이트, 마케팅 페이지, 문서 사이트와 같은 정적 영역이 필요한 경우에 사용됩니다. 도구로는 Gatsby, Next.js, Hugo가 있습니다.
장점
- 매우 빠른 페이지 로딩 속도
- 높은 보안성
- 호스팅 비용 절감
- SEO 최적화 유리
단점
- 동적 콘텐츠 처리가 제한
- 대규모 사이트인 경우 빌드 속도가 느려질 수 있음
- 콘텐츠가 업데이트 된다면 전체 사이트 재 빌드 필요
ISR (Incremental Static Regeneration)
의미
정적 생성과 서버사이드 랜더링의 장점을 결합한 것 입니다.
작동 방식
- 빌드 시 일부 페이지를 정적으로 생성
- 설정된 시간 간격으로 백그라운드에서 페이지를 재 생성
- 새로운 요청이 들어오면 캐시된 버전을 제공 후 업데이트 된 버전으로 교체
장점
- SEO에 유리합니다.
- 서버부화 감소
- 빠른 페이지 로드와 최신 데이터 제공 균형
단점
- 실시간 데이터가 필요한 경우에는 적합하지 않음
Next.js 예시
export async function getStaticProps() {
return {
props: { data },
revalidate: 10, // 10초마다 데이터 재생성
};
}
SSR (Server-Side Rendering)
의미
서버에서 페이지에 html을 생성하고 클라이언트에게 전송하는 방식 입니다.
작동 방식
- 사용자가 페이지를 요청합니다.
- 서버에서 필요한 데이터를 가져와 html을 생성합니다.
- 생성된 html을 클라이언트로 전송합니다.
- 클라이언트에서 JavaScrpit를 로드하여 인터렉티브 기능이 활성화 됩니다.
장점
- SEO에 매우 유리하다(검색 엔진이 완성된 html 을 크롤링이 가능합니다.)
- 초기 페이지 로드 속도가 빠릅니다.
- 메타 데이터 제공하기가 용이합니다.
단점
- 서버 부하가 증가할 수 있습니다.
- 페이지 전환 시 전체 페이지를 다시 로드 해야 할 수 있습니다.
- 개발 학습 곡선이 큽니다.
Webpack과 Rollup은 모두 JavaScrpit 모듈 번들러 입니다.
웹에플리케이션의 자원을 최적화 하고 관리하는데 사용됩니다.
Webpack
특징
- 다양한 자원(JavaScrpit, CSS, img 등)을 모듈로 처리할 수 있음
- 코드 분활(Code Splitting)과 동적 이미지를 지원
- Hot Module Replacement(HMR)를 지원하여 개발경험을 향상시킴
장점
- 다양한 최적화된 옵션을 제공
- 복잡한 어플리케이션의 의존성 관리
단점
- 설정이 복잡함
- 초기 빌드 시간이 상대적으로 김
Hot Module Replacement(HMR) = 웹 개발 과정에서 애플리케이션의 성능을 향상시키고 개발경험을 개선시키는 중요한 기능을 합니다.
장점
- 상태유지 : 어플리케이션의 현재 상태를 유지한채 변경된 부분만 교체 됩니다.
- 개발속도향상 : 빠른 피드백을 통해 개발 효율성이 크게 향상 됩니다.
Rollup
의미
경량화된 모듈 번들러. ES6 모듈 지원에 강점
특징
- ES모듈의 초점을 맞춤
- Tree Shaking을 효과적으로 수행하여 번들 크기를 최소화 합니다.
- 설정이 상대적으로 간단합니다.
장점
- 더 작고 효율적인 번들을 생성합니다.
- 빠른 빌드 속도를 보여줍니다.
Tree Shaking은 JavaScrpit개발에서 사용되지 않는 코드 DeadCode를 제거하여 최종 번들 크기를 줄이는 최적화된 기법 입니다.
기본원리 : Tree Shaking은 어플리케이션 의존성 그래프를 분석하여 실제로 사용되지 않는 코드를 식별하고 제거 합니다.
작동방식 : ES6모듈 시스템의 정적 import와 export문을 활용하여 code의 사용여부를 확인합니다.

ESLint
- JavaScript 코드의 문제점을 찾고 수정하는 데 도움을 주는 정적 분석 도구입니다.
사용 이유
- 코드의 일관성 유지 : 코드 스타일 가이드를 준수하여 일관성 있는 코드를 작성하도록 합니다.
- 버그 및 오류 방지 : 잠재적인 버그나 오류를 사전에 찾아내고 수정할 수 있도록 합니다.
- 팀 협업 강화 : 팀원 간에 코드 품질을 통일시켜 협업 효율을 높일 수 있습니다.
주요 기능
- 코드 스타일 검사 : 들여쓰기, 따옴표, 세미콜론(;) 등 스타일 규칙을 검사합니다.
- 오류 검사 : 잘못된 변수를 사용, 선언되지 않은 변수 사용 등 오류를 검출합니다.
- 경고 및 권고사항 : 최적화, 가독화를 향상 등을 위한 경고와 권고사항을 표시해줍니다.
작동 원리
- ESLint는 코드 품질을 검사하는 '두뇌파' 역할을 하고, Prettier는 코드를 자동으로 포맷팅하는 '행동파' 역할을 합니다.
- eslint-config-prettier는 ESLint와 Prettier 간의 충돌을 방지하여 Prettier의 포맷팅 규칙이 우선적으로 적용되도록 합니다.
자동화 설정
코드 저장 시 자동으로 포맷팅과 린팅이 적용되도록 설정되어 있어, 별도의 명령어 실행 없이도 일관된 코드 스타일을 유지할 수 있습니다. 이는 팀 프로젝트에서 특히 유용하며, 코드 품질과 일관성을 자동으로 유지할 수 있게 해줍니다.
규칙
- off or 0 : 규칙을 해제하고 해당 규칙을 사용하지 않음
- warn or 1 : 규칙을 경고로 설정하고 규칙을 강제하지는 않지만 경고만을 제공하기 위함
- error or 2 : 규칙을 에러로 설정하고 통합 테스트, build, PR등의 경우에 오류를 발생시킴
패키지 설치
npm install --save-dev eslint prettier eslint-config-prettier eslint-plugin-prettier
ESLint 설정
- .eslintrc.json 파일을 프로젝트 루트에 생성합니다.
규칙 값 설정
{
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"rules": {
"semi": ["error", "always"],
"quotes": ["error", "single"],
"no-console": "warn",
"indent": ["error", 2]
}
}
Plugin 추가
{
"plugins": ["prettier", "@typescript-eslint", "react"],
"extends": ["plugin:prettier/recommended"]
}
실행 환경 설정
{
"env": {
"browser": true,
"es2021": true
},
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
}
}
vite에서 eslint.config.js파일 설정
export default [
{ ignores: ["dist"] },
{
files: ["*/.{js,jsx}"],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
ecmaVersion: "latest",
ecmaFeatures: { jsx: true },
sourceType: "module",
},
},
settings: {
react: { version: "18.3" },
prettier: {
printWidth: 100,
tabWidth: 2,
useTabs: false,
semi: true,
singleQuote: true,
trailingComma: "es5",
bracketSpacing: true,
jsxBracketSameLine: false,
arrowParens: "avoid"
}
},
plugins: {
react,
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
prettier: prettier
},
rules: {
...js.configs.recommended.rules,
...react.configs.recommended.rules,
...react.configs["jsx-runtime"].rules,
...reactHooks.configs.recommended.rules,
...eslintConfigPrettier.rules,
"react/jsx-no-target-blank": "off",
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
"prettier/prettier": ["error"],
"arrow-body-style": "off",
"prefer-arrow-callback": "off"
},
},
];
Prettier 설정
- 파일 생성 : .prettierrc
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"jsxBracketSameLine": false,
"arrowParens": "avoid"
}