리액트 기본 블로그 만들기 실습으로 마무리

1. 미니 블로그 기획

 

블로그에 필요한 화면을 리액트 컴포넌트로 만들고, 각 컴포넌트를 연결하여 겉모습이 그럴듯한 블로그 만들기

 

개발을 시작하기 전에, 기획과 필요한 기능, 전체 디자인에 대해 간단하게 정리

 

기능이나 디자인이 중간에 변경될 수 있지만, 간단하게라도 정리된 내용이 없다면 중간에 헤매는 경우가 자주 발생

 

 

1-1) 필요한 기능

 

글 목록 보기(리스트 형태)

 

글 보기

 

댓글 보기

 

글 작성

 

댓글 작성

 

1-2) 전체 화면 디자인

 

 

 

메인 화면은 글 목록을 보여주고, 글 작성 버튼을 누르면 글을 작성할 수 있는 화면으로 이동해서 글을 작성할 수 있도록

 

메인 화면에서 글을 클릭하면, 전체 글의 내용과 댓글을 볼 수 있는 형태가 되도록

 

글 보기 화면 하단에는 댓글을 작성할 수 있는 기능이 들어가도록

 

 

2. 프로젝트 생성

 

$npx create-react-app mini-blog로 react app 프로젝트 생성

 

mini-blog 폴더로 들어가서 $npm start로 구동 확인

 

 

 

 

3. 패키지 설치

 

$npm install --save react-router-dom styled-components

 

react-router-dom은 리액트 앱에서 페이지 전환을 위해 사용하는 필수적인 패키지

 

styled-components는 스타일링을 위한 라이브러리

 

여기서 --save 옵션은 지금 설치하는 패키지들을 package.json 파일이 관리하는 의존성 목록(dependency)에 저장한다는 의미

 

 

 

이렇게 dependency에 추가하면, 다른 사람이 어떤 패키지들이 필요한지 일일이 확인할 필요 없이, npm install을 실행하면, 된다

 

꼭 필요한 패키지 설치할때는 --save 옵션 쓰라는데... (안써도 되는것 같은데)

 

 

4. 주요 컴포넌트 구성

 

필요한 기능을 떠올리면서, 어떤 컴포넌트들이 필요할지 생각

 

컴포넌트는 재사용이 가능한 형태로 최대한 작게 쪼개서 개발하는 것이 중요

 

그래야 이 컴포넌트들을 재사용해서 다른 컴포넌트로 빠르게 개발이 가능하다

 

 

글 목록 보기 기능을 구현하기 위해, 목록을 나타내는 컴포넌트와 목록 안에 들어갈 항목을 나타내는 컴포넌트가 필요

 

PostList, PostListItem 컴포넌트가 각각 필요하다

 

글 보기 기능을 구현하기 위해서는?

 

글의 제목과 내용을 보여주는 컴포넌트가 필요

 

게다가 글 보기 화면 하단에는 댓글 보기 기능과 댓글 작성 기능을 제공

 

댓글 보기 기능은 댓글들을 목록 형태로 보여주어야하기 때문에 댓글 목록 컴포넌트, 댓글 항목 컴포넌트가 필요

 

댓글 작성을 위해서는 사용자로부터 문자열을 입력받을 수 있는 컴포넌트가 필요

 

결국 글의 내용을 보여주는 Post, 댓글 목록을 보여주는 CommentList, CommentListItem, 댓글 작성을 위한 CommentWrite 컴포넌트가 필요

 

그리고 글 작성 기능을 위해 글의 제목과 내용을 사용자로부터 입력받을 수 있는 PostWrite 컴포넌트가 필요

 

 

5. 폴더 구성

 

폴더를 구성하는 이유는 각 컴포넌트들을 적당한 폴더에 모아서 관리하여 개발 편의와 향후 유지 보수가 용이하도록

 

 

 

구성 방법에 정답은 없지만, 다른 개발자와의 협업을 위해 보편적으로 많이 사용하는 방식으로 구성하는 것이 중요

 

보통 리액트 컴포넌트가 재사용이 가능할 경우, 종류별로 모아놓거나

 

각 페이지에서만 사용하고 딱히 재사용이 될 일이 없는 경우 각 페이지별로 폴더를 만들고 그 안에 모아놓는다.

 

 

 

6. ui 컴포넌트 구현

 

버튼, 텍스트 입력 등 사용자가 직접 입력을 할 수 있게 해주는 컴포넌트

 

Button 컴포넌트는 글이나 댓글 작성을 완료했을 때 버튼을 눌러서 작성한 내용을 저장

 

TextInput 컴포넌트는 사용자로부터 문자열을 입력받을 수 있는 컴포넌트

 

 

6-1) Button 컴포넌트

 

버튼의 스타일을 변경하고 버튼에 들어갈 텍스트도 props로 받아 쉽게 사용하기 위해 리액트 컴포넌트로 개발

 

// ui/button.jsx

import React from 'react';
import styled from 'styled-components';

const StyleButton = styled.button`
padding: 8px 16px;
font-size: 16px;
border-width: 1px;
border-radius: 8px;
cursor: pointer;
`;

function Button(props) {
    const {title, onClick} = props;

    return <StyleButton onClick = {onClick}>{title || "button"}</StyleButton>;
}

export default Button;

 

styled-components를 사용해서 button 태그에 스타일을 입힌 StyledButton 컴포넌트 생성

 

Button 컴포넌트에서 props로 받은 title이 버튼에 표시되도록

 

props로 받은 onClick은 StyledButton의 onClick에 넣어서 클릭 이벤트를 상위 컴포넌트에서 받을 수 있도록

 

 

6-2) TextInput 컴포넌트

 

사용자로부터 텍스트를 입력받을 수 있게 해주는 컴포넌트

 

입력을 받을 때 input 태그를 사용하나, 여기서는 여러 줄에 걸친 텍스트를 입력받아야하므로 textarea 태그를 사용

 

import React from 'react';
import styled from 'styled-components';

const StyledTextarea = styled.textarea`
width: calc(100% - 32px);
${(props) => 
props.height &&
`
height: ${props.height}px;
`}
padding:16px;
font-size:16px;
line-height:20px;
`;

function TextInput(props) {
    const { height, value, onChange } = props;

    return <StyledTextarea height={height} value={value} onChange={onChange} />;
}

export default TextInput;

 

Button 컴포넌트와 동일하게 styled-components를 사용해서 textarea 태그에 스타일을 입힌 StyledTextarea 컴포넌트를 생성

 

TextInput 컴포넌트의 props로는 높이 설정을 위한 height, 입력된 값을 표시하기 위한 value,

 

변경된 값을 상위 컴포넌트로 전달하기 위한 onChange

 

 

7. list 컴포넌트 구현

 

7-1) PostListItem 컴포넌트 구현

 

PostList에 PostListItem이 필요하므로 작은 컴포넌트를 먼저 만들고 큰 컴포넌트를 구현한다

 

import React from 'react';
import styled from 'styled-components';

const Wrapper = styled.div`
width: calc(100% - 32px);
padding: 16px;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
border: 1px solid grey;
border-radius: 8px;
cursor: pointer;
background: white;
:hover {
    background: lightgrey;
}
`;

const TitleText = styled.p`
font-size: 20px;
font-weight: 500;
`;

function PostListItem(props) {
    const { post, onClick } = props;

    return (
        <Wrapper onClick = {onClick}>
            <TitleText> {post.title} </TitleText>
        </Wrapper>
    );
}

export default PostListItem;

 

글의 제목만 표시해주는 간단한 컴포넌트

 

TitleText를 이용해서 props로 받은 post 객체에 들어있는 title 문자열을 표시

 

 

7-2) PostList 컴포넌트 구현

 

map() 함수를 사용해서 글의 개수만큼 PostListItem 컴포넌트를 생성

 

import React from 'react';
import styled from 'styled-components';
import PostListItem from './postlistitem';

const Wrapper = styled.div`
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;

& > * {
    :not(:last-child) {
        margin-bottom: 16px;
    }
}
`;

function PostList(props) {
    const { posts, onClickItem } = props;

    return (
        <Wrapper>
            {posts.map((post, index) => {
                return (
                    <PostListItem
                    key={post.id}
                    post={post}
                    onClick={()=>{
                        onClickItem(post);
                    }}
                    />
                )
            })}
        </Wrapper>
    )
}

export default PostList;

 

PostListItem 컴포넌트를 import해서 map함수에 넣어준다

 

PostList에서 props로 받은 posts배열에 post 객체들이 들어있다.

 

이 posts배열의 map 함수를 이용해서 post 객체에 대해 PostListItem 컴포넌트를 만들어 렌더링

 

 

7-3) CommentListItem 컴포넌트

 

import React from 'react';
import styled from 'styled-components';

const Wrapper = styled.div`
width: calc(100% - 32px);
padding: 8px 16px;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
border: 1px solid grey;
border-radius: 8px;
cursor: pointer;
background: white;
:hover {
    background: lightgrey;
}
`;

const ContentText = styled.p`
font-size: 16px;
white-space: pre-wrap;
`;

function CommentListItem(props) {
    const { comment } = props;

    return (
        <Wrapper>
            <ContentText> {comment.content} </ContentText>
        </Wrapper>
    )
}

export default CommentListItem;

 

commentlistitem 컴포넌트는 props에서 받은 comment 객체 하나만 사용

 

comment 객체에는 사용자가 작성한 댓글 내용이 들어있다

 

이를 styled-components를 통해 만든 contenttext라는 컴포넌트를 사용해 화면에 표시

 

글은 클릭이 가능했지만, 댓글은 별도로 클릭하는 기능이 없어서 onClick 이벤트를 따로 처리해주지 않아도 됨

 

 

7-4) commentlist 컴포넌트 구현

 

import React from 'react';
import styled from 'styled-components';
import CommentListItem from './commentlistitem';

const Wrapper = styled.div`
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;

& > * {
    :not(:last-child) {
        margin-bottom: 16px;
    }
}
`;

function CommentList(props) {
    const { comments } = props;

    return (
        <Wrapper>
            {comments.map((comment,index) => {
                return <CommentListItem key={comment.id} comment={comment}/>
            })}
        </Wrapper>
    )
}

export default CommentList;

 

CommentList 컴포넌트의 props로 comments라는 배열이 들어온다.

 

이 배열에 comment 객체가 들어있고, 배열의 map()함수로 각 댓글 객체를 CommentListItem 컴포넌트로 넘겨 렌더링

 

 

8. 가짜 데이터 만들기

 

ui 컴포넌트와 list 컴포넌트들을 구현했으나 블로그에 보여줄 데이터가 존재하지 않는다

 

가짜 데이터를 준비

 

실제로 글과 댓글을 작성할려면, 별도의 데이터베이스를 구축해야하고 서버 API를 개발해야함

 

그리고 서버 API와 리액트 앱을 연동하는 작업도 필요

 

여기서는 가짜 데이터를 이용해서, 데이터를 서버에서 받아왔다고 가정하고 프론트엔드 구현

 

미리 만들어둔 가짜 데이터를 다운받아 src 폴더 내에 저장

 

https://raw.githubusercontent.com/soaple/mini-blog/master/src/data.json

 

 

9. page 컴포넌트 구현

 

9-1) MainPage 컴포넌트

 

MainPage는 우리가 만들 미니 블로그에 사용자가 처음 접속할 때 보게 될 페이지

 

글을 작성할 수 있는 버튼과 글 목록을 보여준다

 

import React from 'react';
import { useNavigate } from 'react-router-dom';
import styled from 'styled-components';
import PostList from '../list/postlist';
import Button from '../ui/button';
import data from '../../data.json';

const Wrapper = styled.div`
padding: 16px;
width: calc(100% - 32px);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
`;

const Container = styled.div`
width: 100%;
max-width: 720px;

& > * {
    :not(last-child) {
        margin-bottom: 16px;
    }
}
`;

function MainPage(props) {
    const {} = props;

    const navigate = useNavigate();

    return (
        <Wrapper>
            <Container>
                <Button
                title="글 작성하기"
                onClick = {() => {
                    navigate('/post-write')
                }}
                />

                <PostList
                posts = {data}
                onClickItem = {(item) => {
                    navigate(`/post/${item.id}`)
                }}
                />
            </Container>
        </Wrapper>
    )
}

export default MainPage;

 

 

위 코드를 보면, 앞에서 만든 Button 컴포넌트로 글 작성하기 페이지로 이동할 수 있게 구현

 

앞에서 만들어둔 PostList 컴포넌트로 글 목록을 표시

 

페이지 이동을 위해 react-router-dom의 useNavigate() 훅을 사용

 

MainPage 컴포넌트는 그냥 만들어둔 컴포넌트들을 모아서 배치한 수준으로 이것이 컴포넌트 기반 개발의 장점

 

 

9-2) PostWritePage 컴포넌트

 

import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import styled from 'styled-components';
import TextInput from '../ui/textinput';
import Button from '../ui/button';

const Wrapper = styled.div`
padding:16px;
width: calc(100% - 32px);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
`;

const Container = styled.div`
width: 100%;
max-width: 720px;

& > * {
    :not(:last-child) {
        margin-bottom: 16px;
    }
}
`;

function PostWritePage(props) {
    const navigate = useNavigate();

    const [title, setTitle] = useState('');
    const [content, setContent] = useState('');

    return (
        <Wrapper>
            <Container>
                <TextInput
                height = {20}
                value = {title}
                onChange = {(event) => {
                    setTitle(event.target.value);
                }}
                />

                <TextInput
                height = {480}
                value = {content}
                onChange = {(event) => {
                    setContent(event.target.value)
                }}
                />

                <Button
                title="글 작성하기"
                onClick = {() => {
                    navigate("/");
                }}
                />
            </Container>
        </Wrapper>
    )
}

export default PostWritePage;

 

2개의 state를 가진다.

 

하나는 글의 제목을 위한 state, 다른 하나는 글의 내용을 위한 state

 

두개의 state 모두 useState() 훅으로 선언

 

그리고 실제 화면에 나타나는 부분은 TextInput 컴포넌트로 글의 제목과 내용을 각각 입력받을 수 있도록 구성

 

마지막으로 화면 제일 하단에 Button 컴포넌트를 사용해서 글 작성 버튼을 넣었다

 

 

9-3) PostViewPage 컴포넌트

 

글을 볼 수 있게 해주는 컴포넌트

 

글과 댓글을 보여주고, 댓글 작성 기능을 제공

 

import React, {useState} from 'react';
import {useNavigate, useParams} from 'react-router-dom';

import styled from 'styled-components';

import CommentList from '../list/CommentList';

import TextInput from '../ui/TextInput';

import Button from '../ui/Button';

import data from '../../data.json';

const Wrapper = styled.div`
padding: 16px;
width: calc(100% - 32px);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
`;

const Container = styled.div`
width: 100%;
max-width: 720px;

& > * {
    :not(:last-child) {
        margin-bottom: 16px;
    }
}
`;

const PostContainer = styled.div`
padding: 8px 16px;
border: 1px solid grey;
border-radius: 8px;
`;

const TitleText = styled.p`
font-size:28px;
font-weight: 500;
`;

const ContentText = styled.p`
font-size:20px;
line-height: 32px;
white-space: pre-wrap;
`;

const CommentLabel = styled.p`
font-size:16px;
font-weight: 500;
`;

function PostViewPage(props){
    const navigate = useNavigate();
    const { postId } = useParams();

    const post = data.find((item) => {
        return item.id == postId;
    })

    const [comment,setComment] = useState('');

    return (
        <Wrapper>
            <Container>
                <Button
                title = "뒤로 가기"
                onClick = {() => {
                    navigate("/")
                }}
                />

                <PostContainer>
                    <TitleText>{post.title}</TitleText>
                    <ContentText>{post.content}</ContentText>
                </PostContainer>

                <CommentLabel>댓글</CommentLabel>
                <CommentList comments = {post.comments} />

                <TextInput
                height={40}
                value={comment}
                onChange={(event)=> {
                    setComment(event.target.value)
                }}
                />
                <Button
                title="댓글 작성하기"
                onClick={() => {
                    navigate("/")
                }}
                />
            </Container>
        </Wrapper>

    )
}

export default PostViewPage;

 

먼저 url 파라미터로 받은 글의 아이디를 이용해서, 전체 데이터에서 해당 글을 찾는다

 

그리고 찾은 글의 제목, 내용, 댓글을 화면에 렌더링하고 그 아래에는 textinput 컴포넌트와 button 컴포넌트로 댓글을 작성할 수 있도록 ui를 제공

 

 

10. 페이지별 경로 구성

 

모든 페이지 컴포넌트를 구현하면, 이들을 웹 브라우저에 보이도록 각 경로(route)에 맞게 매핑해주는 작업이 필요

 

어떤 사이트를 탐색할 때 주소 입력란을 보면 사이트의 각 페이지를 이동하면서 경로가 바뀌는 것을 볼 수 있다.

 

 

위 그림은 페이스북 웹 사이트를 탐색할 때 접속한 페이지에 따라 주소 입력란의 경로가 바뀌는 것을 보여줌

 

메인 도메인은 https://facebook.com 

 

그 뒤에 따라 붙는 /games, /places가 path

 

리액트에서는 react-router-dom이라는 패키지로 각 경로에 따라 다른 컴포넌트를 보여주도록 만든다

 

 

11. react-router-dom

 

리액트를 위한 라우팅 라이브러리

 

웹사이트에서 라우팅이란, 사용자가 원하는 경로로 보내는 과정

 

이런 라우팅을 쉽게 구현할 수 있도록 리액트 컴포넌트 형태로 제공

 

11-1) 기본 구성

 

react-router-dom을 이용해 라우팅을 구성하기 위해 사용하는 기본적인 컴포넌트는 BrowserRouter, routes, route 3가지

 

BrowserRouter 컴포넌트는 웹 브라우저에서 react-router를 사용하여 라우팅을 할 수 있도록 해주는 컴포넌트

 

웹브라우저에는 history라는 기능이 내장되어 있는데, 사용자가 탐색한 페이지들의 방문 기록이 저장

 

웹브라우저의 '뒤로 가기'버튼을 누르면 이 history를 이용해 이전 페이지가 어디인지 찾고, 해당 페이지로 이동

 

BrowserRouter 컴포넌트는 이 history를 이용해 경로를 탐색할 수 있게 해준다.

 

 

Routes와 Route 컴포넌트는 실제로 라우팅 경로를 구성할 수 있게 해준다.

 

Routes는 뒤에 알파벳 s가 붙어서 복수를 나타내는 것처럼, 여러개의 Route 컴포넌트를 children으로 가진다.

 

Route 컴포넌트는 Routes 컴포넌트의 하위 컴포넌트, path와 element라는 props를 가진다.

 

여기에서 path는 경로, element는 경로가 일치할 경우 렌더링을 할 리엑트 앨리먼트

 

사용자가 주소창에 새로운 경로를 입력하거나, 웹사이트내에서 경로 이동이 일어나면,

 

Routes 컴포넌트는 하위 children으로 갖고 있는 Route 컴포넌트 중에서 현재 경로와 가장 일치하는 경로를 찾아 해당되는 엘리먼트를 반환

 

그리고 사용자에게 보이는 화면이 바뀐다.

 

<BrowserRouter>
    <Routes>
        <Route index element={<MainPage />} />
        <Route path="places" element={<PlacePage />}/>
        <Route path="games" element = {<GamePage />}/>
    </Routes>
</BrowserRouter>

 

위 코드는 기본적인 라우팅을 구성하는 코드

 

경로 값이 없이 그냥 사이트 메인으로 접속하면, index라는 prop을 가진 Route로 라우팅

 

여기선 MainPage 컴포넌트가 렌더링

 

또한 /places로 접속하면, PlacePage 컴포넌트,

 

/games로 접속하면 GamePage 컴포넌트가 렌더링되어 화면에 표시

 

 

11-2) 페이지간 이동

 

useNavigate() 훅을 이용해서, 페이지 이동이 가능

 

function SampleNavigate(props) {
    const navigate = useNavigate();

    const moveToMain = () => {
        navigate("/");
    }

    return (
        ...
    )
}

 

 

12. app.js 파일 수정

 

라우팅은 보통 App.js 파일에 포함된 App 컴포넌트에 구현

 

App 컴포넌트가 가장 처음으로 렌더링되는 컴포넌트이기 때문이다.

 

import React from 'react';
import {
  BrowserRouter,
  Routes,
  Route
} from "react-router-dom";

import styled from 'styled-components';

import MainPage from './component/page/mainpage';
import PostWritePage from './component/page/postwritepage';
import PostViewPage from './component/page/postviewpage';

const MainTitleText = styled.p`
font-size: 24px;
font-weight: bold;
text-align: center;
`;

function App() {
  return (
    <BrowserRouter>
    <MainTitleText>대혁의 미니 블로그</MainTitleText>
    <Routes>
      <Route index element={<MainPage />}/>
      <Route path="post-write" element={<PostWritePage/>}/>
      <Route path="post/:postId" element={<PostViewPage/>}/>
    </Routes>
    </BrowserRouter>
  );
}

export default App;

 

react-router-dom으로 총 3가지 경로에 대해 라우팅을 제공

 

index 경로인 /으로 접속하면 MainPage 컴포넌트를 보여주고

 

/post-write 경로로 접속하면 PostWritePage 컴포넌트를 보여주고,

 

마지막으로 /post/:postId로 접속하면, PostViewPage컴포넌트를 보여준다.

 

여기서 마지막 경로에 있는 :postId는 동적으로 변하는 파라미터를 위한 값이다.

 

경로에 이렇게 콜론 :을 사용하고 아이디를 입력하면,

 

실제 컴포넌트에서 useParams() 훅을 사용해 아이디로 해당 값을 가져온다.

 

App 컴포넌트 코드는 라우팅 이외에 특별히 해주는 역할은 없다.

 

웹사이트 상단에 제목이 항상 나오게 하기 위해 MainTitleText 컴포넌트를 하나 추가하여 제목을 넣는다.

 

 

13. index.js

 

리액트는 기본적으로 index.js 파일을 렌더링한다

 

그래서 이 부분에 처음으로 렌더링할 컴포넌트를 지정한다

 

create-react-app으로 생성한 프로젝트는 App 컴포넌트가 기본적으로 들어가 있다.

 

그래서 App 컴포넌트에 라우팅 경로들을 구성

 

당연히 원한다면 다른 컴포넌트를 렌더링시킬수 있다.

 

처음 웹사이트에 접속하면 App 컴포넌트가 렌더링되고, App 컴포넌트는 BrowserRouter 컴포넌트로 둘러싸여 있다.

 

그래서 현재 경로를 탐색해서 해당되는 페이지 컴포넌트가 렌더링

 

 

14. 앱 실행

 

$npm start로 앱 실행해서 확인

 

가장 먼저 보이는 페이지는 메인페이지

 

 

글 하나를 클릭하면.. 글과 댓글을 볼 수 있는 페이지로 이동

 

 

 

 

댓글 작성도 가능하며, 뒤로가기를 누르면 메인페이지로 이동

 

 

메인페이지에서 글 작성하기를 누르면.. 글 작성하는 페이지로 이동 가능

 

당연히 데이터베이스, 서버 연동이 안되어 있어서 실제 글 작성은 안된다

 

 

15. production 빌드

 

웹 애플리케이션 개발의 최종 단계는 빌드와 배포

 

빌드는 작성한 코드와 애플리케이션이 사용하는 이미지, css파일 등의 파일을 모두 모아 패키징하는 과정

 

빌드 과정에는 코드가 식별이 불가능하도록 난독화되기도 하며,

 

필요없는 공백이나 줄바꿈 문자들을 제거해 축소시키는 과정도 포함

 

최종적으로 만들어진 파일이 build 폴더에 모인다.

 

 

$npm run build 실행

 

그러면 프로젝트 폴더에 build 폴더가 생성

 

 

 

그러면 index.html, 이미지 static안에는 css, 자바스크립트 번들 파일이 들어가있다

 

 

 

$serve -s build로 build 폴더를 기반으로 웹 어플을 서빙한다

 

만약 serve라는 명령어가 없다고 하면 $npm install -g serve로 설치한 뒤 다시 실행

 

 

serve는 정적인 static 파일들을 서빙해주는 역할을 하는 프로그램

 

 

성공하면 위와 같이 주소가 뜨고, 접속하면 정상적으로 페이지가 렌더링된다

 

 

배포는 빌드를 통해 생성된 static 파일들을 배포하려고 서버에 올리는 과정이다.

 

서버에 올려두고 serve같은 명령어를 사용해 서빙할 수 있게 해두면 인터넷이 되는 어디에서든지 해당 서버 주소로 접속하여 미니 블로그를 볼 수 있게 된다

TAGS.

Comments