LIGHTLOG
article thumbnail

1. Git 브랜칭 전략

우리팀은 Git Flow, Github Flow도 아닌, 우리팀에게 필요한 브랜칭 전략을 수립하였다. 

1) main

production 서버에 제품으로 배포되는 branch로서, develop branch의 배포 버전만 merge하여 관리한다.

 

2) hotfix

main branch에서 분기하여 긴급한 버그 및 에러를 수정하고 main branch에 다시 merge하기 위해 사용하는 branch이다.

 

3) develop

다음 출시 버전을 대비하여 공동으로 개발하는 branch로서, main에 merge 전 최종테스트를 진행하는 branch이다.

 

4) feature

develop branch에서 분기해 issue단위의 각자 기능을 구현하는 branch로서, 변경사항이 develop branch에 merge되면 삭제된다.

 

 

2. 프론트엔드 테스팅

우리팀은 두가지 테스팅 도구를 도입했다!

 

1) cypress

구현한 기능을 시나리오 단위로 사용자 관점에서 테스트, 즉 e2e테스트를 용이하게 하기 위해서 도입했다. 

하지만 테스트 코드를 구현하는데 꽤 귀찮다는 단점이 있다..

 

그래도, 추후에 리팩토링을 진행할 때 역시 용이하게 쓰일 수 있을 것 같아 도입하기로 결정했다.

 

그렇지만 e2e테스트 코드를 언제 누가 작성할지는 큰 과업으로 남아있다...

 

2) storybook

프론트엔드 팀원 간, 컴포넌트 단위의 피드백을 주고 받기 위해 도입하였다.

도입한 후 소감은, 기능 단위의 재사용성이나 독립성 뿐만 아니라, ui적으로 여러 페이지에서 잘 작동하는지 확인할 수 있다.

 

테스팅 전략에 관해선 다음과 같은 피드백을 받았다

처음 전략이 너무 이상적이다. 
현업에서는 최대한 버그가 들어온 컴포넌트, 페이지 내에서는 테스트코드를 작성하려고 한다. 
바쁜 프로젝트 상황에서도 e2e 테스트가 검증될 수 있는 방식이 무엇인지 생각해보자. 또한, 필요에 맞게 CI를 도입할 것.

 

3. 개발 그리고 개발

이번 스프린트에서 내가 담당한 기능은

- Button 컴포넌트 

- SearchBar 컴포넌트

- 다이얼 키패드 컴포넌트 구현

 

- 사장 모드의 고객리스트 페이지 

      - 검색 및 정렬 기능

- msw 핸들러 구현

...

 

프로젝트를 하다보면 파일들을 어떤 폴더에 구성할지, 또한 이름은 무엇으로 할지 고민되는 순간들이 연속된다. 

우리팀은 토론 끝에

 

1. 컴포넌트들 관리 방법

/components 폴더 안에는 우리 프로젝트 내에서 재사용(여러번 렌더링)되는 컴포넌트들을 모아두자.

이때까지, '재사용되는 컴포넌트'라 하면 나중에 새로운 프로젝트를 시작해도 대치될 수 있는 컴포넌트들을 떠올렸다.

 

하지만, Header는 우리 프로젝트의 로고를 갖기 마련이고, Button컴포넌트 등은 해당 프로젝트의 디자인을 갖기 마련이다.

위와 같은 생각이 어떻게 보면 현실적이지 않은 기준이라고 생각했고,

우리 프로젝트 내에서 잘 재사용될 수 있게 관리하는 것이 중요하다는 생각을 정립했다.

 

그렇다면 페이지 내에서 한 번 쓰이는 컴포넌트들은?
/pages/[pageName] 폴더 아래에 위치시킨다.

해당 컴포넌트들은 /pages/[pageName]/index.tsx 파일에서 불러와 사용하게 되는데

이렇게 하게 되면 컴포넌트의 폴더에서 또 페이지 별로 관심사를 나누어 관리하지 않아도 되고, 해당 프로젝트에서 쓰이는 컴포넌트라는 것이 바로 직관적으로 와닿게 된다.

 

 

4. 프론트엔드 배포

1. ssh 초기 세팅 및 배포 환경 구축

1-1) 인스턴스 생성 및 ssh 접속

aws로 인스턴스를 생성한 뒤, 생성된 .pem형식의 key로 ssh에 접속한다. 

chmod 400 <KEY_NAME>.pem
ssh -i <KEY_NAME> ubuntu@<PUBLIC_IP>

* ssh란? 원격 호스트에 접속하기 위해 사용되는 보안 프로토콜

 

1-2) Node 및 npm 설치 & 빌드

// 1. apt 업데이트
sudo apt update

// 2. https://nodejs.org/ko/download/current 에서 환경에 맞는 node를 다운받는다. 
wget <COPY_DOWNLOAD_ADDRESS>

// 3. 다운받은 파일의 압축을 해제한다.
tar -xvf <다운로드받은_파일.tar.xz>

// 4. 압축을 해제한 파일을 설치한다.
sudo cp -r * /usr/local/

// 5. node와 npm이 잘 설치되었는지 버전을 확인한다. 
node -v 
npm -v

1-3) 배포할 프로젝트를 빌드

git clone <GIT_URL>
npm install
npm run build

 

2. 본격 배포 

2-1) serve 

장점: 아주 간편하고 쉽고 빠르게 배포를 할 수 있다.

단점: npm 서버를 끄면 (ctrl + c를 하면) 배포된 서버도 꺼진다.

// 1. serve 설치
npm i -g serve

// 2. .env 파일 생성
echo "REACT_APP_BASE_URL = 'http://[IP_ADDRESS]:8080/api'" >> .env

// 3. serve 실행
sudo npx serve -s <빌드된_폴더> -l <PORT> 

-s: 정적 파일 서버로 실행된다는 의미
-l: <PORT>` 사용할 포트번호를 지정함..

 

2-2) 무중단 배포를  위한 pm2 도입

// 1. pm2 설치
sudo npm install -g pm2

// 2. pm2로 서빙 실행
pm2 start server.js

// 3. 실행중인 pm2 리스트 확인
pm2 start server.js

// 4. pm2 중지
pm2 stop <ID>
// server.js
const express = require('express');
const path = require('path');

const app = express();

app.use(express.static(path.join(__dirname, 'dist')));

// 모든 url에 대해 root file 제공
app.get('*', (_, res) => {
	res.sendFile(path.join(__dirname, '/dist/index.html'))
})

const PORT = 3000;

// 성공 시 로깅
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`); 
});

 

2-3) 배포자동화를 위한 nginx + jenkins

먼저, jenkins에 NodeJS를 깔아주자.

 그 다음, 쉘 스크립트를 작성한다.

pipeline {
    agent any
				// 환경변수 설정
        environment {
        NODEJS_HOME = tool name: 'NodeJS', type: 'jenkins.plugins.nodejs.tools.NodeJSInstallation'
        PATH = "${NODEJS_HOME}/bin:${env.PATH}"
    }
    stages {
				// git branch에서 가져옴
        stage('Github') {
            steps {
                git branch: 'develop', url: 'https://github.com/woowacourse-teams/2023-stamp-crush.git'
            }
        }
				// 빌드
        stage('Build') {
            steps {
              dir('frontend'){
              sh 'node -v'
              sh "echo 'REACT_APP_BASE_URL' = 'https://www.stampcrush.site/api' > .env"   
              sh 'npm i && npm run build'    
              }
             }  
        }
			  // 빌드된 파일 압축
        stage('compress file') {
            steps {
              dir('frontend') {
                  sh 'tar -cvf dist.tar dist'
              }
            }   
        }
				// 압축된 파일 ssh로 전송
        stage('send file to instance') {
            steps {
                dir('frontend') {
                    sshagent(credentials: ['key-stamp-crush']){
                        sh 'scp -o StrictHostKeyChecking=no dist.tar ubuntu@192.168.1.193:/home/ubuntu/frontend'
                    }                    
                }
            }
        }
				// ec2 인스턴스에 있는 쉘 스크립트 실행
        stage('deploy') {
            steps {
                dir('frontend') {
                    sshagent(credentials: ['key-stamp-crush']){
                        sh 'ssh ubuntu@192.168.1.193 ./frontend/run.sh'
                    }
                }
            }
        }
    }

}
#!/bin/bash

# 압축된 dist 디렉토리의 압축을 해제합니다.
tar -xvf /home/ubuntu/frontend/dist.tar -C /home/ubuntu/frontend

# 압축해제된 dist 디렉토리를 nginx로 이동시킵니다. 
sudo cp -r /home/ubuntu/frontend/dist /usr/share/nginx

# nginx를 다시 시작합니다.
sudo systemctl restart nginx.service

# 필요없는 파일을 지웁니다.
rm -rf ./frontend/dist && rm -rf ./frontend/dist.tar
profile

LIGHTLOG

@lightOnCoding

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!