Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deploy #7

Merged
merged 22 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules
build
.git
.gitignore
.github
README.md
*.pem
71 changes: 71 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: Deploy
on:
push:
branches: [deploy]
workflow_dispatch:

jobs:
deploy:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
node-version: lts/Hydrogen

- name: Cache node modules
uses: actions/cache@v4
id: cache
with:
path: node_modules
key: npm-packages-${{ hashFiles('**/package-lock.json') }}

- name: Install Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: npm install

- name: Build
run: CI=false npm run build

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build and push Docker images
uses: docker/[email protected]
with:
context: .
file: ./Dockerfile.prod
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/syluv:latest
build-args: |
REACT_APP_KAKAO_JS_KEY=${{ secrets.REACT_APP_KAKAO_JS_KEY }}
REACT_APP_KAKAO_REST_API_KEY=${{ secrets.REACT_APP_KAKAO_REST_API_KEY }}
REACT_APP_KAKAO_REDIRECT_URI=${{ secrets.REACT_APP_KAKAO_REDIRECT_URI }}
REACT_APP_BASE_URL=${{ secrets.REACT_APP_BASE_URL }}

- name: Pull and restart Docker Container
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USER }}
key: ${{ secrets.SSH_KEY }}
port: 22
timeout: 60s
script: |
echo "Pulling latest Docker image"
sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/syluv:latest
echo "Stopping existing Docker container"
sudo docker stop syluvFrontend || true
sudo docker rm syluvFrontend || true
echo "Starting new Docker container"
sudo docker run -d --rm --name syluvFrontend -p 80:80 ${{ secrets.DOCKERHUB_USERNAME }}/syluv:latest
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ yarn-debug.log*
yarn-error.log*

.env
/cert/*
/cert/*
*.pem
74 changes: 74 additions & 0 deletions Dockerfile.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Build stage
FROM node:lts AS build

WORKDIR /app

COPY package.json .

RUN npm i

COPY . .

# Build arguments for React environment variables
ARG REACT_APP_API_URL
ARG REACT_APP_OTHER_ENV

# Set environment variables for React build
ENV REACT_APP_API_URL $REACT_APP_API_URL
ENV REACT_APP_OTHER_ENV $REACT_APP_OTHER_ENV

RUN npm run build

# Production stage
FROM nginx:stable-alpine

# nginx의 기본 설정을 삭제하고 앱에서 설정한 파일을 복사
RUN rm -rf /etc/nginx/conf.d
COPY conf /etc/nginx

# 위 스테이지에서 생성한 빌드 결과를 nginx의 샘플 앱이 사용하던 폴더로 이동
COPY --from=build /app/build /usr/share/nginx/html

EXPOSE 80

# nginx 실행
CMD [ "nginx", "-g", "daemon off;" ]
# Build stage
FROM node:lts AS build

WORKDIR /app

COPY package.json .

RUN npm i

COPY . .

# Build arguments for React environment variables
ARG REACT_APP_KAKAO_JS_KEY
ARG REACT_APP_KAKAO_REST_API_KEY
ARG REACT_APP_KAKAO_REDIRECT_URI
ARG REACT_APP_BASE_URL

# Set environment variables for React build
ENV REACT_APP_KAKAO_JS_KEY $REACT_APP_KAKAO_JS_KEY
ENV REACT_APP_KAKAO_REST_API_KEY $REACT_APP_KAKAO_REST_API_KEY
ENV REACT_APP_KAKAO_REDIRECT_URI $REACT_APP_KAKAO_REDIRECT_URI
ENV REACT_APP_BASE_URL $REACT_APP_BASE_URL

RUN npm run build

# Production stage
FROM nginx:stable-alpine

# nginx의 기본 설정을 삭제하고 앱에서 설정한 파일을 복사
RUN rm -rf /etc/nginx/conf.d
COPY conf /etc/nginx

# 위 스테이지에서 생성한 빌드 결과를 nginx의 샘플 앱이 사용하던 폴더로 이동
COPY --from=build /app/build /usr/share/nginx/html

EXPOSE 80

# nginx 실행
CMD [ "nginx", "-g", "daemon off;" ]
9 changes: 9 additions & 0 deletions conf/conf.d/default.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
server {
listen 80;

location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
29 changes: 26 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,8 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11"
}
}
2 changes: 1 addition & 1 deletion src/pages/MenuTestPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const stores = [
];

const MenuTestPage = () => {
const { addItem, removeItem, updateItemCount, carts } = useCartStore();
const { addItem, removeItem, carts } = useCartStore();

const handleAddItem = (storeName, item) => {
addItem(storeName, item);
Expand Down
113 changes: 60 additions & 53 deletions src/utils/OauthCallback.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useEffect, useState, useCallback } from "react";
import axios from "axios";
import useTokenStore from "hooks/useTokenStore";
import { useNavigate } from "react-router-dom";
Expand All @@ -10,62 +10,69 @@ const OauthCallback = () => {
const { setRefreshToken, setAccessToken } = useTokenStore();
const navigate = useNavigate();

useEffect(() => {
const code = new URL(window.location.href).searchParams.get("code");
const getKakaoToken = async () => {
try {
const response = await axios.post(
"https://kauth.kakao.com/oauth/token",
new URLSearchParams({
grant_type: "authorization_code",
client_id: process.env.REACT_APP_KAKAO_REST_API_KEY,
redirect_uri: process.env.REACT_APP_KAKAO_REDIRECT_URI,
code: code,
}).toString(),
{
headers: {
"Content-Type":
"application/x-www-form-urlencoded;charset=utf-8",
},
}
);
return response.data.id_token;
} catch (error) {
throw new Error("Failed to get Kakao token");
}
};
const getKakaoToken = useCallback(async (code) => {
try {
const response = await axios.post(
"https://kauth.kakao.com/oauth/token",
new URLSearchParams({
grant_type: "authorization_code",
client_id: process.env.REACT_APP_KAKAO_REST_API_KEY,
redirect_uri: process.env.REACT_APP_KAKAO_REDIRECT_URI,
code: code,
}).toString(),
{
headers: {
"Content-Type":
"application/x-www-form-urlencoded;charset=utf-8",
},
}
);
return response.data.id_token;
} catch (error) {
throw new Error("Failed to get Kakao token");
}
}, []);

const getSyluvToken = async (idToken) => {
try {
const response = await axios.post(
"https://syluv.link/v1/users/login/kakao",
{
idToken: idToken,
}
);
return response.data;
} catch (error) {
throw new Error("Failed to get Syluv token");
}
};
const getSyluvToken = useCallback(async (idToken) => {
try {
const response = await axios.post(
"https://syluv.link/v1/users/login/kakao",
{
idToken: idToken,
}
);
return response.data;
} catch (error) {
throw new Error("Failed to get Syluv token");
}
}, []);

const fetchTokens = async () => {
try {
const idToken = await getKakaoToken();
const syluvData = await getSyluvToken(idToken);
setAccessToken(syluvData.accessToken);
setRefreshToken(syluvData.refreshToken);
navigate("/", { replace: true });
} catch (error) {
setIsError(true);
setError(error);
} finally {
setIsLoading(false);
}
};
const fetchTokens = useCallback(async () => {
try {
const code = new URL(window.location.href).searchParams.get("code");
const idToken = await getKakaoToken(code);
const syluvData = await getSyluvToken(idToken);
setAccessToken(syluvData.accessToken);
setRefreshToken(syluvData.refreshToken);
navigate("/", { replace: true });
} catch (error) {
setIsError(true);
setError(error);
navigate("/login", { replace: true });
} finally {
setIsLoading(false);
}
}, [
getKakaoToken,
getSyluvToken,
setAccessToken,
setRefreshToken,
navigate,
]);

useEffect(() => {
fetchTokens();
}, []);
}, [fetchTokens]);

if (isLoading) return <div>Loading...</div>;
if (isError) return <div>Error: {error.message}</div>;
Expand Down