Skip to content

Instantly share code, notes, and snippets.

@StatPan
Last active May 4, 2025 15:04
Show Gist options
  • Select an option

  • Save StatPan/9c6764c3b385e4f0b7ac3c07bdb54052 to your computer and use it in GitHub Desktop.

Select an option

Save StatPan/9c6764c3b385e4f0b7ac3c07bdb54052 to your computer and use it in GitHub Desktop.
#!/bin/bash
# setup-react-pnpm.sh
# pnpm을 사용한 React + TypeScript + ESLint + Prettier 설정 스크립트
#설치 명령어
#curl -o setup-react-pnpm.sh https://gist.githubusercontent.com/StatPan/9c6764c3b385e4f0b7ac3c07bdb54052/raw/0a65099bc776f1d81f9270df407f20c54cab7336/vite-react-starter.sh && chmod +x setup-react-pnpm.sh && ./setup-react-pnpm.sh 프로젝트명 [옵션]
# 사용법: ./setup-react-pnpm.sh 프로젝트명 [옵션]
# 예: ./setup-react-pnpm.sh my-app
# 옵션:
# --tailwind Tailwind CSS 설치 및 설정
# --router React Router 설치
# --husky Husky 및 lint-staged 설정 (Git Hook)
# --eslint8 ESLint 8.x 버전 사용 (기본값: 9.x)
set -e
# 기본 옵션 설정
INSTALL_TAILWIND=false
INSTALL_ROUTER=false
INSTALL_HUSKY=false
USE_ESLINT8=false
INSTALL_TEST=false
INSTALL_STORYBOOK=false
# 프로젝트 이름 확인
if [ -z "$1" ]; then
echo "프로젝트 이름을 입력해주세요."
echo "사용법: ./setup-react-pnpm.sh 프로젝트명 [옵션]"
echo "옵션:"
echo " --tailwind Tailwind CSS 설치 및 설정"
echo " --router React Router 설치"
echo " --husky Husky 및 lint-staged 설정 (Git Hook)"
echo " --eslint8 ESLint 8.x 버전 사용 (기본값: 9.x)"
echo " --test Jest 및 React Testing Library 설정"
echo " --storybook Storybook 설정"
exit 1
fi
PROJECT_NAME="$1"
shift
# 추가 옵션 파싱
for arg in "$@"; do
case $arg in
--test)
INSTALL_TEST=true
;;
--storybook)
INSTALL_STORYBOOK=true
;;
--tailwind)
INSTALL_TAILWIND=true
;;
--router)
INSTALL_ROUTER=true
;;
--husky)
INSTALL_HUSKY=true
;;
--eslint8)
USE_ESLINT8=true
;;
*)
echo "알 수 없는 옵션: $arg"
exit 1
;;
esac
done
echo "🚀 pnpm으로 리액트 프로젝트 생성 시작: $PROJECT_NAME"
echo " - ESLint + Prettier 설정"
if [ "$USE_ESLINT8" = true ]; then
echo " - ESLint 8.x 버전 사용"
else
echo " - ESLint 9.x 버전 사용"
fi
if [ "$INSTALL_TAILWIND" = true ]; then
echo " - Tailwind CSS 설정"
fi
if [ "$INSTALL_ROUTER" = true ]; then
echo " - React Router 설치"
fi
if [ "$INSTALL_HUSKY" = true ]; then
echo " - Husky + lint-staged 설정"
fi
# 옵션 출력 부분에 테스트 옵션 추가
if [ "$INSTALL_TEST" = true ]; then
echo " - Jest + React Testing Library 설정"
fi
if [ "$INSTALL_STORYBOOK" = true ]; then
echo " - Storybook 설정"
fi
# pnpm이 설치되어 있는지 확인
if ! command -v pnpm &> /dev/null; then
echo "pnpm이 설치되어 있지 않습니다. pnpm을 먼저 설치해주세요."
echo "npm install -g pnpm"
exit 1
fi
# Vite + React + TypeScript 프로젝트 생성
echo "📦 Vite + React + TypeScript 프로젝트 생성 중..."
pnpm create vite "$PROJECT_NAME" --template react-ts
# 프로젝트 디렉토리로 이동
cd "$PROJECT_NAME"
# 기본 의존성 설치
echo "📦 기본 의존성 설치 중..."
pnpm install
# 의존성 설치 후 추가 패키지 설치
if [ "$INSTALL_TAILWIND" = true ]; then
echo "📦 Tailwind CSS 설치 중..."
pnpm add -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
# Tailwind CSS 설정 파일 수정
cat > tailwind.config.js << EOF
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
EOF
# CSS 파일에 Tailwind 지시어 추가
cat > src/index.css << EOF
@tailwind base;
@tailwind components;
@tailwind utilities;
EOF
echo "✅ Tailwind CSS 설정 완료"
fi
if [ "$INSTALL_ROUTER" = true ]; then
echo "📦 React Router 설치 중..."
pnpm add react-router-dom
echo "✅ React Router 설치 완료"
fi
# 테스트 도구 설치
if [ "$INSTALL_TEST" = true ]; then
echo "📦 테스트 도구 설치 중..."
pnpm add -D jest @types/jest ts-jest @testing-library/react @testing-library/jest-dom @testing-library/user-event jest-environment-jsdom
# Jest 설정 파일 생성
cat > jest.config.js << EOF
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
moduleNameMapper: {
'\\.(css|less|scss|sass)$': 'identity-obj-proxy',
'^@/(.*)$': '<rootDir>/src/$1'
},
setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts'],
};
EOF
# setupTests 파일 생성
mkdir -p src
cat > src/setupTests.ts << EOF
import '@testing-library/jest-dom';
EOF
# 예제 테스트 파일 생성
mkdir -p src/components/__tests__
cat > src/components/__tests__/example.test.tsx << EOF
import { render, screen } from '@testing-library/react';
test('기본 테스트 예제', () => {
render(<div>테스트 성공</div>);
expect(screen.getByText('테스트 성공')).toBeInTheDocument();
});
EOF
# package.json에 테스트 스크립트 추가
TEST_SCRIPTS='"test": "jest",\n "test:watch": "jest --watch",\n "test:coverage": "jest --coverage",'
sed -i.bak "s/\"scripts\": {/\"scripts\": {\n $TEST_SCRIPTS/" package.json && rm package.json.bak
echo "✅ 테스트 설정 완료"
fi
# Storybook 설치
if [ "$INSTALL_STORYBOOK" = true ]; then
echo "📦 Storybook 설치 중..."
pnpm dlx storybook@latest init --builder @storybook/builder-vite -y
# package.json에 Storybook 테스트 스크립트 추가
STORYBOOK_TEST_SCRIPT='"test-storybook": "test-storybook",'
sed -i.bak "s/\"scripts\": {/\"scripts\": {\n $STORYBOOK_TEST_SCRIPT/" package.json && rm package.json.bak
echo "✅ Storybook 설정 완료"
fi
if [ "$INSTALL_HUSKY" = true ]; then
echo "📦 Husky 및 lint-staged 설치 중..."
pnpm add -D husky lint-staged
# package.json에 husky 및 lint-staged 설정 추가
HUSKY_SCRIPT='"prepare": "husky install",'
LINT_STAGED='"lint-staged": {\n "*.{ts,tsx}": [\n "eslint --fix",\n "prettier --write"\n ],\n "*.{css,scss}": [\n "prettier --write"\n ]\n },'
# sed를 사용하여 package.json 파일에 스크립트 추가
sed -i.bak "s/\"scripts\": {/\"scripts\": {\n $HUSKY_SCRIPT/" package.json && rm package.json.bak
sed -i.bak "s/\"devDependencies\": {/\"devDependencies\": {\n },\n $LINT_STAGED\n \"devDependencies\": {/" package.json && rm package.json.bak
# Git 초기화 및 Husky 설정
git init
pnpm prepare
npx husky add .husky/pre-commit "npx lint-staged"
# .gitignore 생성
cat > .gitignore << EOF
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
!.vscode/settings.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
EOF
echo "✅ Husky 및 lint-staged 설정 완료"
fi
# ESLint와 Prettier 설치 - 버전에 따라 분기
echo "📦 ESLint 및 Prettier 설치 중..."
if [ "$USE_ESLINT8" = true ]; then
# ESLint 8.x 버전 설치
pnpm add -D eslint@^8.0.0 eslint-plugin-react@^7.33.2 eslint-plugin-react-hooks@^4.6.0 \
eslint-plugin-react-refresh@^0.4.5 @typescript-eslint/eslint-plugin@^6.0.0 \
@typescript-eslint/parser@^6.0.0 prettier@^3.0.0 eslint-config-prettier@^9.0.0 \
eslint-plugin-prettier@^5.0.0
else
# ESLint 9.x 버전 설치
pnpm add -D eslint@^9.0.0 @eslint/js globals typescript-eslint \
eslint-plugin-react@^7.33.2 eslint-plugin-react-hooks@^5.0.0 \
eslint-plugin-react-refresh@^0.4.5 prettier@^3.0.0 eslint-config-prettier@^9.0.0 \
eslint-plugin-prettier@^5.0.0
fi
# VS Code 설정 디렉토리 및 파일 생성
echo "📝 VS Code 설정 생성 중..."
mkdir -p .vscode
cat > .vscode/settings.json << EOF
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
"prettier.requireConfig": true
}
EOF
# VS Code 추천 확장 프로그램 설정
cat > .vscode/extensions.json << EOF
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"dsznajder.es7-react-js-snippets"
]
}
EOF
# Prettier 설정 파일 생성
echo "📝 Prettier 설정 파일 생성 중..."
cat > .prettierrc << EOF
{
"semi": true,
"tabWidth": 2,
"printWidth": 100,
"singleQuote": true,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "avoid"
}
EOF
# Prettier 무시 파일 생성
cat > .prettierignore << EOF
node_modules
dist
.vscode
EOF
# package.json에 스크립트 추가
echo "📝 npm 스크립트 추가 중..."
NPM_SCRIPTS='"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",\n "lint:fix": "eslint . --ext ts,tsx --fix",\n "format": "prettier --write \\"src/**/*.{ts,tsx,css,scss}\\"",\n "format:check": "prettier --check \\"src/**/*.{ts,tsx,css,scss}\\"",'
# sed를 사용하여 package.json 파일에 스크립트 추가
sed -i.bak "s/\"scripts\": {/\"scripts\": {\n $NPM_SCRIPTS/" package.json && rm package.json.bak
# ESLint 설정 파일 생성 (ESLint 버전에 따라 분기)
echo "📝 ESLint 설정 파일 생성 중..."
if [ "$USE_ESLINT8" = true ]; then
# ESLint 8.x 방식 (.eslintrc.cjs)
cat > .eslintrc.cjs << EOF
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'prettier' // ESLint와 Prettier 충돌 방지를 위해 마지막에 추가
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh', 'prettier'],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
'react/react-in-jsx-scope': 'off',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'prettier/prettier': 'error' // Prettier 규칙 위반 시 에러로 표시
},
settings: {
react: {
version: 'detect'
}
}
};
EOF
echo "✅ ESLint 8.x 설정 완료 (.eslintrc.cjs)"
else
# ESLint 9.x 방식 (eslint.config.js)
cat > eslint.config.js << EOF
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'
import prettierPlugin from 'eslint-plugin-prettier'
import prettierConfig from 'eslint-config-prettier'
export default tseslint.config(
prettierConfig,
{ 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,
'prettier': prettierPlugin,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
'prettier/prettier': 'error',
},
},
)
EOF
echo "✅ ESLint 9.x 설정 완료 (eslint.config.js)"
fi
# ESLint와 Prettier 설치 부분 이후...
# SWC 플러그인 설치
echo "📦 SWC 플러그인 설치 중..."
pnpm add -D vite-plugin-swc
# vite.config.ts 파일 수정
cat > vite.config.ts << EOF
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import swc from 'vite-plugin-swc';
export default defineConfig({
plugins: [
react(),
swc({
jsc: {
parser: {
syntax: 'typescript',
tsx: true,
},
transform: {
react: {
runtime: 'automatic',
development: true,
refresh: true,
},
},
},
}),
],
});
EOF
echo "✅ SWC 설정 완료"
if [ "$INSTALL_TEST" = true ]; then
echo "✅ Jest + React Testing Library가 설정되었습니다"
echo " - 테스트 실행: pnpm test"
echo " - 테스트 감시 모드: pnpm test:watch"
echo " - 테스트 커버리지 보기: pnpm test:coverage"
fi
if [ "$INSTALL_STORYBOOK" = true ]; then
echo "✅ Storybook이 설정되었습니다"
echo " - Storybook 실행: pnpm storybook"
echo " - Storybook 테스트: pnpm test-storybook"
fi
# VS Code 설정 디렉토리 및 파일 생성 (기존 코드)...
echo "🎉 설정 완료: $PROJECT_NAME"
echo ""
echo "📋 다음 단계:"
echo " 1. cd $PROJECT_NAME"
echo " 2. pnpm run dev"
echo ""
echo "💡 ESLint와 Prettier 충돌 방지 설정이 완료되었습니다:"
if [ "$USE_ESLINT8" = true ]; then
echo " - ESLint 8.x 방식으로 설정되었습니다 (.eslintrc.cjs)"
else
echo " - ESLint 9.x 방식으로 설정되었습니다 (eslint.config.js)"
fi
echo " - Prettier와 통합되어 코드 스타일을 통일합니다"
echo "💻 즐거운 코딩되세요! 😊"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment