Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
00699a5
init
dev-root-lee Jul 21, 2024
5428355
[Feat] BaseURL Context 구현
anheejeong Jul 30, 2024
e79b372
[Feat] 회원가입 구현
anheejeong Jul 30, 2024
06264ba
[Feat] 카테고리 API 구현
anheejeong Aug 1, 2024
4e1dc12
[Feat] product API 수정
anheejeong Aug 1, 2024
380af68
[Feat] 회원가입 구현
anheejeong Aug 1, 2024
66469fe
[Feat] Header BaseUrl 선택 구현
anheejeong Aug 1, 2024
25adc46
[Feat] 회원가입 API 구현
anheejeong Aug 1, 2024
e388562
[Feat] 이메일 로그인 API 수정
anheejeong Aug 1, 2024
852c3e1
[Feat] 주문하기 API 수정
anheejeong Aug 1, 2024
376fb4c
[Feat] 위시 구현
anheejeong Aug 1, 2024
75f3364
[Feat] type 수정 및 추가
anheejeong Aug 1, 2024
e43ef5d
[Feat] http secure 추가
anheejeong Aug 1, 2024
0082033
Resolved merge conflict in README.md
anheejeong Aug 1, 2024
c950b66
[Fix] productId -> product-id api request 수정
anheejeong Aug 2, 2024
46514af
[Feat] Route URL 수정
anheejeong Aug 2, 2024
5453f0a
[Feat] Admin 페이지 로그인 구현
anheejeong Aug 2, 2024
186b53e
[Feat] 관리자 멤버 포인트 조회 및 추가 구현
anheejeong Aug 2, 2024
ab0c2ba
[Feat] 관리자 권한 체크
anheejeong Aug 2, 2024
c3c20fb
[Refactor] console 삭제
anheejeong Aug 2, 2024
d0a81fb
[Fix] 위시리스트 api 수정
anheejeong Aug 2, 2024
4eef110
[Design] 버튼 위치 변경
anheejeong Aug 2, 2024
cd2399f
[Design] 카테고리 이미지 비율 조정
anheejeong Aug 2, 2024
9ff7d02
[Fix] 주문하기 API 포인트 추가 수정
anheejeong Aug 2, 2024
6b16a1c
[Docs] 4단계 Q&A 작성
anheejeong Aug 2, 2024
41ca855
[Chore] 배포 환경 설정
anheejeong Aug 6, 2024
dd8b74a
[Fix] code: 'ERR_REQUIRE_ESM' 오류 수정
anheejeong Aug 7, 2024
6aeb3fa
[Fix] 패키지 혼합 문제 해결 Delete package-lock.json
anheejeong Aug 7, 2024
783632a
[Docs] Update README.md
anheejeong Aug 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
extends: [
'plugin:@typescript-eslint/recommended',
'airbnb/hooks',
'airbnb-typescript',
'prettier',
'plugin:storybook/recommended',
],
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 'latest',
sourceType: 'module',
},
plugins: [
'react',
'@typescript-eslint',
'react-hooks',
'json-format',
'simple-import-sort',
'@emotion',
'prettier',
],
rules: {
'react/react-in-jsx-scope': 'off',
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
'@typescript-eslint/consistent-type-imports': 'warn',
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
},
],
'import/extensions': ['off'],
'import/no-extraneous-dependencies': ['off'],
'react/jsx-filename-extension': [
'warn',
{
extensions: ['.tsx', '.js', '.jsx'],
},
],
'@typescript-eslint/no-use-before-define': ['off'],
},
ignorePatterns: ['**/build/**/*', '.eslintrc.js', 'craco.config.js'],
settings: {
'import/resolver': {
typescript: {},
},
},
};
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

.yaml
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/.vscode
/node_modules

8 changes: 8 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"singleQuote": true,
"semi": true,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 100,
"arrowParens": "always"
}
36 changes: 36 additions & 0 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { StorybookConfig } from '@storybook/react-webpack5';
import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';
import path from 'path';

const config: StorybookConfig = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/preset-create-react-app',
'@storybook/addon-onboarding',
'@storybook/addon-interactions',
],
webpackFinal: async (config) => {
config.resolve?.plugins?.push(
new TsconfigPathsPlugin({
configFile: path.resolve(__dirname, '../tsconfig.json'),
}),
);

return config;
},
framework: {
name: '@storybook/react-webpack5',
options: {
builder: {
useSWC: true,
},
},
},
docs: {
autodocs: 'tag',
},
staticDirs: ['../public'],
};
export default config;
16 changes: 16 additions & 0 deletions .storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { Preview } from '@storybook/react';
import '@/styles';

const preview: Preview = {
parameters: {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
};

export default preview;
109 changes: 108 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,108 @@
# react-deploy
# react-deploy


🚀 Q&A


> 1. SPA 페이지를 정적 배포를 하려고 할 때 Vercel을 사용하지 않고 한다면 어떻게 할 수 있을까요?


- Github Page

1. 저장소 생성: GitHub에서 username.github.io 형식의 새로운 저장소를 생성(uername은 자신의 GitHub 사용자 이름)
2. 웹사이트 파일 업로드: 저장소에 HTML, CSS, JavaScript 파일을 업로드.
3. GitHub Pages 활성화: 저장소의 "Settings">"Pages">"Source"를 설정하고 배포할 브랜치(ex: main 또는 gh-pages)를 선택.
4. 배포 확인: 배포가 완료되면 https://username.github.io에서 웹사이트를 확인.


- CloudFlare Page

1. Cloudflare 계정 생성 및 로그인
2. 프로젝트 설정: Cloudflare 대시보드에서 "Pages"를 선택하고 새로운 프로젝트를 시작.
3. GitHub 연동: GitHub 계정을 연동하여 프로젝트 저장소를 선택.
4. 빌드 설정: 필요한 경우 빌드 명령어와 배포 디렉토리를 설정(ex: npm run build와 build 디렉토리)
5. 배포: Cloudflare가 자동으로 배포를 진행. 완료 후 제공된 URL에서 웹사이트를 확인.


- AWS S3 + CloudFront + Route53

1. S3 버킷 생성: AWS Management Console에서 S3를 선택하고 새로운 버킷을 생성. 웹사이트 호스팅을 활성화하고 정적 웹사이트 파일을 업로드.
2. CloudFront 배포 생성: CloudFront에서 새로운 배포를 생성하고 S3 버킷을 원본으로 설정. 필요한 캐싱 정책과 배포 설정을 구성.
3. Route 53 도메인 설정: Route 53에서 도메인을 구매하거나 기존 도메인을 관리하여 CloudFront 배포와 연결. A 레코드를 설정하여 CloudFront 배포의 도메인 이름으로 트래픽을 라우팅.
4. 배포 확인: 설정이 완료되면 도메인 이름으로 웹사이트를 확인.


- Netlify

1. Netlify 계정 생성 및 로그인
2. 프로젝트 연결: "New site from Git"을 선택하고 GitHub, GitLab, Bitbucket 등에서 프로젝트 저장소를 연결.
3. 빌드 설정: Netlify가 자동으로 빌드 명령어와 배포 디렉토리를 감지할 수 있지만, 필요시 설정 가능.
4. 배포: "Deploy site"를 클릭하면 Netlify가 자동으로 배포를 진행. 완료 후 제공된 URL에서 웹사이트를 확인.


- Heroku

1. Heroku 계정 생성 및 로그인
2. Heroku CLI 설치: 로컬 시스템에 Heroku CLI(Command Line Interface)를 설치.
3. 애플리케이션 준비: Heroku에서 지원하는 언어나 프레임워크에 맞게 애플리케이션을 준비. (ex: Procfile, requirements.txt, package.json 등)
4. Git 저장소 초기화: 애플리케이션 디렉토리에서 Git 저장소를 초기화하고 변경 사항을 커밋.
5. Heroku 애플리케이션 생성: heroku create 명령어를 사용하여 새로운 애플리케이션을 생성.
6. 배포: git push heroku main 명령어를 사용하여 애플리케이션을 Heroku에 배포.
7. 배포 확인: 배포가 완료되면 Heroku가 제공하는 URL에서 애플리케이션을 확인.


> 2. CSRF나 XSS 공격을 막는 방법은 무엇일까요?


**CSRF 방지 방법**


1. CSRF 토큰 사용: 각 사용자가 요청을 보낼 때 서버가 생성한 CSRF 토큰을 함께 전송하게 합니다. 서버는 요청 시 제공된 토큰과 저장된 토큰을 비교하여 요청이 유효한지 확인합니다. 이 토큰은 예측 불가능하며 각 세션마다 다르기 때문에, 공격자가 CSRF 공격을 성공시키기 어렵습니다.


2. 참조자 헤더 검사: 요청의 Referer 또는 Origin 헤더를 검사하여 요청이 신뢰할 수 있는 출처에서 왔는지 확인합니다. 공격자는 자신의 사이트에서 Referer 헤더를 조작할 수 없기 때문에 유효성 검사로 사용할 수 있습니다.


3. SameSite 쿠키 속성 사용: SameSite 쿠키 속성을 'Strict' 또는 'Lax'로 설정하면, 사용자의 브라우저가 크로스 사이트 요청에서 쿠키를 전송하지 않습니다. 이를 통해 CSRF 공격을 방지할 수 있습니다.


4. CORS 정책 설정: 적절한 CORS (Cross-Origin Resource Sharing) 설정을 통해 신뢰할 수 있는 출처만 요청을 보낼 수 있도록 제한합니다.


**XSS 방지 방법**


1. 입력 값 검증 및 정화: 사용자 입력을 받기 전에 철저하게 검증하고, 예상치 못한 입력이 포함되지 않도록 정화합니다. 예를 들어, HTML 태그나 스크립트 태그가 포함되지 않도록 합니다.


2. 출력 인코딩: 사용자 입력 데이터를 HTML 콘텐츠로 출력할 때, 반드시 해당 데이터를 HTML 엔티티로 인코딩합니다. 예를 들어, <는 &lt;, >는 &gt;로 변환합니다. 이를 통해 악성 스크립트가 실행되지 않도록 합니다.


3. Content Security Policy (CSP): CSP를 사용하여 서버가 브라우저에 자바스크립트 실행을 허용할 소스와 위치를 명시적으로 지시합니다. 이를 통해 허용되지 않은 소스의 스크립트 실행을 차단할 수 있습니다.


4. HTTP 전송 보안 강화: 모든 데이터를 HTTPS로 전송하여 중간에서 데이터가 조작되지 않도록 합니다.


5. 쿠키 속성 설정: 쿠키에 대해 HttpOnly 속성을 설정하여 자바스크립트에서 접근할 수 없도록 하고, Secure 속성을 설정하여 HTTPS 연결에서만 전송되도록 합니다.


> 3. 브라우저 렌더링 원리에대해 설명해주세요.


1. HTML 파싱과 DOM 트리 생성 : 브라우저가 서버로부터 HTML 문서를 수신하면, 이를 파싱하여 DOM(Document Object Model) 트리를 생성합니다. 이 트리는 HTML 문서의 구조를 나타내며, 각 HTML 요소는 DOM 트리의 노드로 표현됩니다.


2. CSS 파싱과 CSSOM 트리 생성 : 브라우저는 HTML 문서 내에 포함된 <style> 태그나 외부 링크된 CSS 파일을 파싱하여 CSSOM(CSS Object Model) 트리를 생성합니다. CSSOM 트리는 CSS 규칙을 포함하며, 각 규칙은 선택자와 스타일 속성으로 이루어져 있습니다.


3. 렌더 트리 생성 : 브라우저는 DOM 트리와 CSSOM 트리를 결합하여 렌더 트리를 생성합니다. 렌더 트리는 화면에 표시되어야 하는 모든 노드와 해당 스타일 정보를 포함합니다. DOM 트리의 일부 요소, 예를 들어 <head> 태그나 display: none 스타일이 적용된 요소들은 렌더 트리에서 제외됩니다.


4. 레이아웃 계산 (Reflow) : 렌더 트리가 생성되면 브라우저는 각 렌더 트리 노드의 크기와 위치를 계산합니다. 이 과정을 레이아웃 또는 리플로우(Reflow) 라고 합니다. 여기서는 뷰포트의 크기와 각 요소의 스타일 규칙을 고려하여 요소들이 화면에 어떻게 배치될지 결정합니다.


5. 페인팅 (Painting) : 레이아웃 계산이 완료되면 브라우저는 각 렌더 트리 노드를 화면에 그립니다. 이 과정은 페인팅이라고 하며, 여기서 요소의 색상, 그림자, 테두리 등 스타일이 적용됩니다. 이 과정은 레스터화라고도 불리며, 픽셀 데이터를 생성하여 화면에 표시합니다.


6. 컴포지팅 (Compositing) : 페인팅 단계 이후, 브라우저는 여러 레이어로 분리된 요소들을 하나의 화면 이미지로 합치는 컴포지팅 단계를 수행합니다. 레이어를 사용하면 브라우저는 페이지의 일부분만 업데이트해야 하는 경우 전체 페이지를 다시 렌더링하지 않고, 특정 레이어만 다시 그려 성능을 최적화할 수 있습니다.
26 changes: 26 additions & 0 deletions craco.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const path = require('path');

module.exports = {
webpack: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
configure: (webpackConfig) => {
// Babel loader를 통해 ESM 모듈을 변환하는 설정 추가
webpackConfig.module.rules.push({
test: /\.js$/,
include: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-transform-runtime'],
},
},
exclude: /node_modules\/(?!strip-ansi)/, // 특정 모듈만 포함시키기
});

return webpackConfig;
},
},
};
90 changes: 90 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{
"name": "kakao-tech-campus-frontend-project",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"start:mock": "cross-env REACT_APP_RUN_MSW=true npm run start",
"start": "craco start",
"build": "craco build",
"test": "craco test",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"dependencies": {
"@chakra-ui/icons": "^2.1.1",
"@chakra-ui/react": "^2.8.2",
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
"@tanstack/react-query": "^5.24.1",
"axios": "^1.6.7",
"framer-motion": "^11.0.6",
"react": "^18.2.0",
"react-dev-utils": "11",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.12",
"react-hook-form": "^7.50.1",
"react-intersection-observer": "^9.8.1",
"react-router-dom": "^6.22.1",
"strip-ansi": "^7.1.0"
},
"devDependencies": {
"@craco/craco": "^7.1.0",
"@emotion/eslint-plugin": "^11.11.0",
"@storybook/addon-essentials": "^7.6.17",
"@storybook/addon-interactions": "^7.6.17",
"@storybook/addon-links": "^7.6.17",
"@storybook/addon-onboarding": "^1.0.11",
"@storybook/blocks": "^7.6.17",
"@storybook/preset-create-react-app": "^7.6.17",
"@storybook/react": "^7.6.17",
"@storybook/react-webpack5": "^7.6.17",
"@storybook/test": "^7.6.17",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.18.82",
"@types/react": "^18.2.57",
"@types/react-dom": "^18.2.19",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"cross-env": "^7.0.3",
"eslint": "^8.56.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^17.1.0",
"eslint-config-prettier": "^9.1.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-json-format": "^2.0.1",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-simple-import-sort": "^12.0.0",
"eslint-plugin-storybook": "^0.8.0",
"msw": "^1.3.3",
"prettier": "^3.2.5",
"prop-types": "^15.8.1",
"react-scripts": "5.0.1",
"storybook": "^7.6.17",
"tsconfig-paths-webpack-plugin": "^4.1.0",
"typescript": "^4.9.5",
"webpack": "^5.90.3"
},
"overrides": {
"react-refresh": "0.11.0"
}
}
16 changes: 16 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="ko">

<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> -->
<title>Kakao Tech</title>
</head>

<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>

</html>
Loading