13. Practice Movie App - Publishing
1. GitHub 사이트 로그인 후
repository를 추가 후 커밋 및 푸쉬를 진행한다.
2. package.json 파일 내
scrips에 "deploy": "gh-pages -d build"와 "predeploy": "npm run build"를 추가한다.
3. package.json 파일 내
"hompage":"https://깃허브 유저네임/github.io/푸쉬한 레퍼지토리명"를 추가한다.
4. Visual Studio Code 툴 내 터미널에서
"npm run deploy" 명령어를 실행한다.
<자세한 내용>
Visual Studio Code 툴 내 터미널에서 "npx create-react-app 폴더명"을 실행하면 폴더가 생성되고
해당 폴더 내 package.json 함께 생성되는 것이다.
깃허브에서 repository를 추가 후 커밋 및 푸쉬를 진행한다.
아래 이미지는 Visual Studio Code 툴에서 커밋하는 과정이다.
Visual Studio Code 툴 내 터미널에서 "npm i gh-pages"를 실행한다.
gh-pages는 github pages에 업로드 할 수 있게 해주는 패키지이다.
github pages는 github에서 제공하는 무료 서비스인데 html, css, javascript를 올리면
웹사이트로 만들어서 전세계에 무료로 배포해주는데 도메인도 가지게 된다.
package.json 파일을 보면 build라는 scripts가 있어
이 scripts를 실행하면 우리 웹사이트의 production ready code를 생성하게 된다.
production ready code란 코드가 압축되고 모든게 최적화 된다는 의미이다.
Visual Studio Code 툴 내 터미널에서 "npm run build"를 실행한다.
압축, 최적화 등이 이루어지기 때문에 시간이 조금 걸린다.
완료가 되면 build 폴더가 생겨난다.
github pages에 push를 하기전에 package.json 파일을 수정한다.
package.json 파일 내
"hompage": "https://bonsimony.github.io/React-Movie-App"를 추가했는데
"hompage":"https://깃허브 유저네임/github.io/푸쉬한 레퍼지토리명" 이 형식으로 작성한다.
Visual Studio Code 툴 내 터미널에서 git remote -v를 실행하면 확인이 가능하다.
- git remote -v
현재 Git 저장소에 연결된 원격 저장소(remote repository) 목록을 확인할 때 사용됩니다.
여기서 -v는 verbose(자세히 보기) 옵션으로, 각 원격 저장소의 URL까지 함께 보여줍니다.
- git remote set-url origin 새로운URL
기존에 등록된 원격 저장소(origin) 의 URL을 변경할 때 사용합니다.
(ex) git remote set-url origin https://github.com/bonsimony/React-Movie-App.git
package.json 파일 내 scripts를 하나 만들어준다.
"deploy": "gh-pages -d build"를 추가한다.
build를 하고 난 다음에 deploy가 자동으로 될 수 있도록 하기 위해서
package.json 파일 내 scripts에 "predeploy": "npm run build"를 추가한다.
해당 프로젝트 내 생성되었던 build 폴더를 삭제한다.
비주얼스튜디어 내 터미널에서 "npm run deploy"를 실행하면
Node.js가 predeploy를 먼저 실행하고 "npm run build"가 실행되고
"npm run build"는 react-scrips build를 실행시키면서 최적화를 만들어내고
그게 끝이면 "gh-pages -d build"가 실행된다.
"gh-pages -d build"가 하는 일은 build 폴더를
"hompage": "https://bonsimony.github.io/React-Movie-App"
https://bonsimony.github.io/React-Movie-App 해당 웹 사이트에 업로드하는 것이다.
해당 프로젝트에서 package.json 파일 내에서 Ctrl 누른 상태로
https://bonsimony.github.io/react-for-beginners 클릭하면
해당 페이지로 이동하는데 웹사이트가 업데이트된걸 보려면 5분 정도 걸린다.
<전체 소스>
App.js
import {
BrowserRouter as Router,
Route,
Routes
} from "react-router-dom";
import Home from "./routes/Home";
import Detail from "./routes/Detail";
function App() {
// 누군가 만들어 놓은 컴포넌트를 잘 사용하면 된다.
// Swith(Routes)가 하는 역할은 Route를 찾는 것인데 Route는 URL을 의미한다.
// 사용자가 "/" 경로에 있으면 Home Route를 랜더링한다.
return <Router>
<Routes>
<Route path = "/movie/:id" element={<Detail />} />
<Route path = "/" element={<Home />} />
</Routes>
</Router>;
}
export default App;
Home.js
import { useEffect, useState } from 'react';
import Movie from "../components/Movie";
function Home(){
const [loading, setLoading] = useState(true);
const [movies, setMovies] = useState([]);
const getMovies = async() => {
const json = await(await fetch(`https://yts.mx/api/v2/list_movies.json?minimum_ration=8.8&sort_by=year`)).json();
setMovies(json.data.movies);
setLoading(false);
};
useEffect(()=>{
//fetch 대신에 요즘 async-await를 사용한다.
/*
fetch(`https://yts.mx/api/v2/list_movies.json?minimum_ration=8.5&sort_by=year`)
.then(response => {
response.json()
.then((json) => {
setMovies(json.data.movies)
setLoading(false);
});
});
*/
getMovies();
}, []);
return (
<div>
{
loading ? (<h1>Loading...</h1>)
: (
<div>
{movies.map((movie) => (
<Movie
key = {movie.id}
id = {movie.id}
coverImg = {movie.medium_cover_image}
title = {movie.title}
summary = {movie.summary}
genres = {movie.genres}
/>
))}
</div>
)
}
</div>
);
};
export default Home;
Movie.js
import PropTypes from "prop-types"; //prop-types를 사용하기 위해서는 터미널에서 npm i prop-types를 실행해야 한다!
import {Link} from "react-router-dom";
function Movie({id, coverImg, title, summary, genres}){
return(
<div>
<div>
<img src = {coverImg} alt={title}/>
<h2><Link to={`/movie/${id}`}>{title}</Link></h2>
<p>{summary}</p>
<ul>
{genres.map((g) =>
(<li>{g}</li>)
)}
</ul>
</div>
</div>
);
};
Movie.prototype = {
id : PropTypes.number.isRequired,
coverImg : PropTypes.string.isRequired,
title : PropTypes.string.isRequired,
summary : PropTypes.string.isRequired,
genres : PropTypes.arrayOf(PropTypes.string).isRequired
}
export default Movie;
Detail.js
import { useEffect } from "react";
import { useParams } from "react-router-dom";
function Detail(){
const {id} = useParams();
const getMovies = async () => {
const json = await(await fetch(`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`)).json();
};
useEffect(()=>{
getMovies();
},[]);
return <h1>Detail</h1>
};
export default Detail;
pacage.json
{
"name": "practice-movie-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^13.5.0",
"gh-pages": "^6.3.0",
"prop-types": "^15.8.1",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-router-dom": "^7.5.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"deploy": "gh-pages -d build",
"predeploy": "npm run build"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"homepage": "https://bonsimony.github.io/React-Movie-App"
}