함께 성장하는 프로독학러

Memo_app 02. 작업환경 설정 및 디렉토리 구조 이해 본문

Programming/tutorials

Memo_app 02. 작업환경 설정 및 디렉토리 구조 이해

프로독학러 2018. 6. 22. 12:17

안녕하세요, 프로독학러 입니다.


저번 포스팅에서는 Memo app 을 제작하기 위한 기본 개념들에 대해서 알아보았는데요, 이번 포스팅에서는 설치부터 본격적으로 진행해 보도록 하겠습니다.


*본 튜토리얼은 Velopert 님의 'React.js Codelab 2016' 을 기반으로 되었습니다.

(여러 모듈들의 버전업에 따라 작성방법이 조금씩 달라진 코드를 버전에 맞게 수정하고, 제가 튜토리얼을 따라함에 있어 이해가 쉽지 않았던 부분에 설명을 추가하는 방식으로 진행합니다.)

* Velopert 님의 원본 튜토리얼을 보고싶으신 분들은 아래의 링크를 참고해 주세요.

<React.js codelab 2016 - Velopert>


1. React.js 설치


우리가 만들게 될 Memo app 은 React.js 를 기반으로 한 SPA(Single Page Application) 입니다.

따라서 가장먼저 해야할 것은 React 프로젝트를 만드는 것입니다.

React.js 를 설치하고 프로젝트 파일을 생성하는 과정은 이전에 제가 React.js 포스팅을 할 때 올렸던 자료를 참고하셔서 진행하시면 되겠습니다.

<리액트 환경 설정하기 - React.js, Node.js, babel, webpack4>

* Node.js 를 이미 설치하신 분이라면 위의 링크 중 2. React project 설정 부터 따라하시면 되겠습니다.

* 프로젝트의 이름(디렉토리명)은 Memo_app_tuts 로 하겠습니다. (원하시는 이름으로 네이밍하면 되겠습니다)

* ./dist/index.html 과 ./src/index.js 의 내용은 아래 코드로 변경해 주세요


(./dist/index.html)

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
  <head>
    <title>Memo_app_tuts</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="/bundle.js"></script>
  </body>
</html>
cs


(./src/index.js)

1
2
3
4
5
6
7
8
9
10
11
12
import React from 'react';
import ReactDOM from 'react-dom';
 
const title = 'Memo_App';
 
ReactDOM.render(
  <div>{title}</div>,
  document.getElementById('root')
);
 
module.hot.accept();
 
cs


위의 링크를 통해 React.js 와 webpack, babel 까지 설정을 완료했습니다.


2. 프로젝트 dependencies 설치


React 프로젝트를 구성한 뒤엔 Memo 어플리케이션에서 사용할 dependencies 를 설치해야합니다.


설치할 모듈들은 다음과 같습니다.


2-1) Global dependency 설치


npm install -g babel-cli nodemon cross-env


babel-cli : 콘솔 환경에서 babel 을 사용할 수 있게 해주는 모듈

nodemon : development 환경에서 파일이 수정될 때마다 서버를 재시작해주는 모듈

cross-env : 윈도우 / 리눅스 / OSX 에서 환경변수 값을 설정해주는 모듈


2-2) Local Dependency 설치


npm install --save express body-parser


express : Node.js 웹 프레임 워크

body-parser : JSON 형태의 데이터를 HTTP 요청에서 파싱할 때 사용(req.body 로 접근할 수 있도록)


2-3) Dev Dependency 설치


npm install -dev--save babel-preset-es2015


babel-preset-es2015 : npm 스크립트를 통해서 개발 서버를 열 때 es2015를 사용할 수 있도록 해 주는 모듈


2-4) Express 코드 작성


Express 를 이용하여 서버파일을 생성해 줍니다.


(./server/main.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import express from 'express';
import path from 'path';
 
const app = express();
const port = 3000;
 
app.use('/', express.static(path.join(__dirname, './../dist')));
 
app.get('/hello', (req, res) => {
    return res.send('Hello Memo_App');
});
 
app.listen(port, () => {
    console.log('Express is listening on port', port);
});
cs


2-5) NPM 스크립트 수정


(./package.json)

1
2
3
4
5
6
7
8
9
10
...,
"scripts": {
    "start""webpack-dev-server --config ./webpack.config.js --mode development",
    "test""echo \"Error: no test specified\" && exit 1",
    "clean""rm -rf build public/bundle.js",
    "build""babel server --out-dir build --presets=es2015 && webpack",
    "win_start""cross-env NODE_ENV=production node ./build/main.js",
    "win_development""cross-env NODE_ENV=development nodemon --exec babel-node --presets=es2015 ./server/main.js --watch server"
  },
...
cs


package.json 파일의 script 부분을 위와 같이 수정합니다.

script 부분에 필드를 추가하면 명령프롬프트(cmd)에서 'npm run (스크립트에 추가한 필드명)' 으로 파일을 실행할 수 있습니다.

개발서버를 실행해려면 프로젝트파일 경로에서 'npm run win_development' 명령어를 통해 실핼할 수 있습니다.


2-6) Webpack 개발서버용 설정파일 만들기


루트 경로에 webpack.dev.config.js 파일을 생성하고 아래의 코드를 붙여넣습니다.


(./webpack.dev.config.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import webpack from 'webpack';
 
module.exports = {
    mode: 'development',
    /* webpack-dev-server를 콘솔이 아닌 자바스크립트로 실행 할 땐,
    HotReloadingModule 를 사용하기 위해선 dev-server 클라이언트와
    핫 모듈을 따로 entry 에 넣어주어야 합니다. */
 
    entry: [
        './src/index.js',
        'webpack-dev-server/client?http://0.0.0.0:4000'// 개발서버의 포트가 이 부분에 입력되어야 제대로 작동합니다
        'webpack/hot/only-dev-server'
    ],
 
    output: {
        path: '/'// public 이 아니고 /, 이렇게 하면 파일을 메모리에 저장하고 사용합니다
        filename: 'bundle.js'
    },
 
    // 개발서버 설정입니다
    devServer: {
        hot: true,
        filename: 'bundle.js',
        publicPath: '/',
        historyApiFallback: true,
        contentBase: './public',
        /* 모든 요청을 프록시로 돌려서 express의 응답을 받아오며,
        bundle 파일의 경우엔 우선권을 가져서 devserver 의 스크립트를 사용하게 됩니다 */
        proxy: {
            "**""http://localhost:3000" // express 서버주소
        },
        stats: {
          // 콘솔 로그를 최소화 합니다
          assets: false,
          colors: true,
          version: false,
          hash: false,
          timings: false,
          chunks: false,
          chunkModules: false
        }
    },
 
 
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ],
 
    module: {
      rules: [
        {
          test: /\.(js|jsx)$/,
          exclude: /node_modules/,
          use: ['babel-loader']
        }
      ]
    },
    performance: {
      hints: process.env.NODE_ENV === 'production' ? "warning" : false
    }
 
 
};
 
cs


코드의 네 번째 줄에서 mode 를 설정해주고, 58번째 줄에서 모드가 production 일 경우에는 경고창을 띄우고 아닐 경우에는 경고창을 띄우지 않도록 했습니다.


2-7) server 메인 파일 수정


development 환경일 때 개발 서버를 켜는 코드를 추가하도록 하겠습니다.


(./server/main.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import express from 'express';
import path from 'path';
import WebpackDevServer from 'webpack-dev-server';
import webpack from 'webpack';
 
const app = express();
 
const port = 3000;
const devPort = 4000;
 
app.use('/', express.static(path.join(__dirname, './../dist')));
 
app.get('/hello', (req, res) => {
    return res.send('Hello Memo_App!!');
});
 
app.listen(port, () => {
    console.log('Express is listening on port', port);
});
 
if(process.env.NODE_ENV == 'development') {
    console.log('Server is running on development mode');
    const config = require('../webpack.dev.config');
    const compiler = webpack(config);
    const devServer = new WebpackDevServer(compiler, config.devServer);
    devServer.listen(
        devPort, () => {
            console.log('webpack-dev-server is listening on port', devPort);
        }
    );
}
cs


3. MongoDB 설치


MongoDB 데이터베이스의 설치는 아래의 링크를 참조해주세요. (MongoDB에 익숙치 않으시다면 해당 카테고리의 포스팅을 모두 읽어 보시는것을 추천드립니다)

<MongoDB 설치법>

* Node.js 환경에서 MongoDB 를 사용하는 모듈인 mongoose 의 사용법에 대해 익숙치 않으신 분들은 아래의 링크를 참조해주세요.

<mongoose 사용법>


4. 미들웨어 및 기타 모듈설치


server 의 main.js 파일에서 사용할 미들웨어 및 기타 모듈을 설치하도록 하겠습니다.

설치할 미들웨어 및 모듈은 다음과 같습니다.


morgan : HTTP 요청을 로그하는 미들웨어

mongoose : mongoDB 데이터 모델링툴 (MongoDB 의 데이터를 Javascript 객체로 사용할 수 있도록 해주는 모듈)

express-session : express 에서 세션을 다룰 때 사용하는 미들웨어


npm install --save morgan mongoose express-session


server/main.js 에서 추가한 모듈들을 사용하는 코드를 추가해 줍니다.


(./server/main.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import express from 'express';
import path from 'path';
import WebpackDevServer from 'webpack-dev-server';
import webpack from 'webpack';
import morgan from 'morgan'// HTTP REQUEST LOGGER
import bodyParser from 'body-parser'// PARSE HTML BODY
import mongoose from 'mongoose';
import session from 'express-session';
 
const app = express();
 
/* mongodb connection */
const db = mongoose.connection;
db.on('error'console.error);
db.once('open', () => { console.log('Connected to mongodb server'); });
// mongoose.connect('mongodb://username:password@host:port/database=');
mongoose.connect('mongodb://localhost/Memo_app_tuts');
 
app.use(session({
    secret: 'CodeLab1$1$234',
    resave: false,
    saveUninitialized: true
}));
app.use(morgan('dev'));
app.use(bodyParser.json());
 
const port = 3000;
const devPort = 4000;
 
app.use('/', express.static(path.join(__dirname, './../dist')));
 
app.get('/hello', (req, res) => {
    return res.send('Hello Memo_App!!');
});
 
app.listen(port, () => {
    console.log('Express is listening on port', port);
});
 
if(process.env.NODE_ENV == 'development') {
    console.log('Server is running on development mode');
    const config = require('../webpack.dev.config');
    const compiler = webpack(config);
    const devServer = new WebpackDevServer(compiler, config.devServer);
    devServer.listen(
        devPort, () => {
            console.log('webpack-dev-server is listening on port', devPort);
        }
    );
}
cs


5. 디렉토리 구조 이해하기


여기까지 잘 따라오셨다면 이제 본격적으로 어플리케이션을 만들 준비가 된 상태입니다.

본격적으로 코드를 작성하기 이전에 프로젝트의 디렉토리 구조가 어떻게 되는지 이해하고 가도록 하겠습니다.


- dist (리액트 컴포넌트를 렌더링할 대상)

- index.html

- server (BACK-END)

- models

: mongoose 모델이 위치하는 디렉토리

- routes

: API 들이 위치하는 디렉토리

- main.js : 서버를 위한 js 파일

- src (FRONT-END)

- actions

: actionType, action 생성자 함수, thunk 가 위치할 디렉토리

- components

: 기능을 가진 컴포넌트 (작은단위의 컴포넌트) 들이 위치할 디렉토리

- containers

: 컴포넌트를 포함하는 상위 개념의 컴포넌트 (라우트에 렌더링할 컴포넌트) 들이 위치할 디렉토리

reducers

: 액션객체를 전달받아 Redux state 를 업데이트하는 함수가 위치할 디렉토리

- index.js : 리액트 설정 파일 (렌더링 위치, 라우트 등을 지정)

- style.css : 스타일시트


dist 디렉토리에는 렌더링을 진행할 대상인 HTML 파일이 위치하고, server 디렉토리에는 BACK-END 관련 파일이, src 디렉토리에는 FRONT-END 파일이 위치합니다.

위의 디렉토리를 여러분의 프로젝트 파일에도 똑같이 생성해 주세요. 파일을 튜토리얼을 진행하며 생성할 예정이니 폴더만 생성해 주시면 됩니다.


./server/main.js 파일에 API 라우터들을 불러오는 코드와 ./dist/index.html 을 렌더링하기 위한 코드를 추가해줍시다.


(./server/main.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import express from 'express';
import path from 'path';
import WebpackDevServer from 'webpack-dev-server';
import webpack from 'webpack';
import morgan from 'morgan'// HTTP REQUEST LOGGER
import bodyParser from 'body-parser'// PARSE HTML BODY
import mongoose from 'mongoose';
import session from 'express-session';
 
//file import
import api from './routes';
 
const app = express();
 
/* mongodb connection */
const db = mongoose.connection;
db.on('error'console.error);
db.once('open', () => { console.log('Connected to mongodb server'); });
// mongoose.connect('mongodb://username:password@host:port/database=');
mongoose.connect('mongodb://localhost/Memo_app_tuts');
 
app.use(session({
    secret: 'CodeLab1$1$234',
    resave: false,
    saveUninitialized: true
}));
app.use(morgan('dev'));
app.use(bodyParser.json());
// routes '/api' 로 들어오는 요청울 routes 폴더의 라우트들로 위임
app.use('/api', api);
 
const port = 3000;
const devPort = 4000;
 
app.use('/', express.static(path.join(__dirname, './../dist')));
app.get('*', (req, res) => {
    res.sendFile(path.resolve(__dirname, './../dist/index.html'));
});
 
app.get('/hello', (req, res) => {
    return res.send('Hello Memo_App!!');
});
 
app.listen(port, () => {
    console.log('Express is listening on port', port);
});
 
if(process.env.NODE_ENV == 'development') {
    console.log('Server is running on development mode');
    const config = require('../webpack.dev.config');
    const compiler = webpack(config);
    const devServer = new WebpackDevServer(compiler, config.devServer);
    devServer.listen(
        devPort, () => {
            console.log('webpack-dev-server is listening on port', devPort);
        }
    );
}
cs


위의 코드의 11, 30 번째 줄이 라우트를 위한 설정이고, 36 번째 줄은 렌더링 설정입니다.


여기까지...


Memo 어플리케이션을 작성하는데 있어 필요한 환경설정을 마쳤습니다.

다음 포스팅부터는 인증 부분부터 구현하도록 하겠습니다.


감사합니다.


**참고 자료 (항상 감사드립니다)

https://velopert.com/1921


*이 포스팅이 도움이 되셨다면 다녀가셨다는 표시로 공감 부탁드릴게요! (로그인 하지 않으셔도 공감은 가능합니다 ㅎㅎ)

Comments