Share/Nodejs

Nodejs MVC patter Setting

Jimmy.B 2020. 11. 16. 22:17

니꼬 쌤의 wetube를 바탕으로 정리하였습니다.

#2.1 ~ #2.25 

 

 

Tech Stack >

 

nodejs

babelrc 

es6 

 

 

Task 1.    틀잡기 

 

초반 틀을 잡으려면 app.js  나 init.js  를 구성하고 

router 와 routes (url) 부터 세팅을 하면 훨씬 틀이 빨리 잡혀간다. 

 

routes.js 

  • 내가 사용할 모든 url 정리 
  • 추후 url 하나씩 지워가며 mvc 패턴을 따라 설계 및 개발하면 에러 찾기도 쉽고 용이하다 
// Global
const HOME = "/";
const JOIN = "/join";
const LOGIN = "/login";
const LOGOUT = "/logout";
const SEARCH = "/search";

// Users

const USERS = "/users";
const USER_DETAIL = "/:id";
const EDIT_PROFILE = "/edit-profile";
const CHANGE_PASSWORD = "/change-password";

// Videos

const VIDEOS = "/videos";
const UPLOAD = "/upload";
const VIDEO_DETAIL = "/:id";
const EDIT_VIDEO = "/:id/edit";
const DELETE_VIDEO = "/:id/delete";

//js object 

const routes = {
  home: HOME,
  join: JOIN,
  login: LOGIN,
  logout: LOGOUT,
  search: SEARCH,
  users: USERS,
  userDetail: id => {
    if (id) {
      return `/users/${id}`;
    } else {
      return USER_DETAIL;
    }
  },
  editProfile: EDIT_PROFILE,
  changePassword: CHANGE_PASSWORD,
  videos: VIDEOS,
  upload: UPLOAD,
  videoDetail: id => {
    if (id) {
      return `/videos/${id}`;
    } else {
      return VIDEO_DETAIL;
    }
  },
  editVideo: EDIT_VIDEO,
  deleteVideo: DELETE_VIDEO
};

export default routes;

 

app.js 

 

  • 중앙 본사 역할 
  •  app.js 는  init.js 와 분리하여 사용할 수 있다. 
  • 입맛에 맞게 알아서 하면 될듯. 
  • 중요한 것은 app.use 및 app.set (뷰) 및 파일 입출력 관련 코드 관리 
import express from "express";

import morgan from "morgan";
import helmet from "helmet";
import cookieParser from "cookie-parser";
import bodyParser from "body-parser";

import {localsMiddleware} from "./middlewares";
import routes from "./routes";  //URL 

//라우터 
import userRouter from "./routers/userRouter" //끝이 파일이름 
import videoRouter from "./routers/videoRouter" //끝이 파일이름 
import globalRouter from "./routers/globalRouter" //끝이 파일이름 



const app = express();


app.use(helmet());
app.set("view engine", "pug");
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(morgan("dev"));
app.use(localsMiddleware);

app.use(routes.home, globalRouter);
app.use(routes.users, userRouter);
app.use(routes.videos, videoRouter);

export default app;

 

 

Task 2. 라우터 / 컨트롤러 분리 

 

  • controller 와 router 를 분리 하는 것은 정말 유용
  • 분리 해서도 js 객체화하여 코드 관리를 하면 가독성도 좋고 유지보수도 베리 굳 

 

Global Router 만 일부 살펴보면 

 

import express from "express";
import routes from "../routes";

import { home, search } from "../controllers/videoController";
import {
    getJoin,
    getLogin,
    postJoin,
    postLogin,
    logout,
  } from "../controllers/userController";


const globalRouter = express.Router();


globalRouter.get(routes.join, getJoin);
globalRouter.post(routes.join, postJoin);

globalRouter.get(routes.login, getLogin);
globalRouter.post(routes.login, postLogin);


globalRouter.get(routes.home, home);
globalRouter.get(routes.search, search);


globalRouter.get(routes.logout, logout);



export default globalRouter;
  • routes 에서 url을 객체화 하여 가져옴 
  • 컨트롤로에서 함수를 가져옴 
  • 라우터 에서는 정말 그야말로 " 라우팅 " 만 하겠다!!!!! 라는 것. 

그렇다면, 위에서 사용된 컨트롤러인 " videoController" 와 "userController" 에 가보자 

 

//videoController 

import { videos } from "../db";
import routes from "../routes";


export const home = (req, res) => {
  res.render("home", { pageTitle: "Home", videos });
};



export const search = (req, res) => {
    const {
      query: { term: searchingBy }
    } = req;
    
    console.log(req.query.term);
    
    res.render("search", { pageTitle: "Search", searchingBy, videos });
  };

  

  

  export const getUpload = (req, res) =>
  res.render("upload", { pageTitle: "Upload" });

  export const postUpload = (req, res) => {
    const {
      body: { file, title, description }
    } = req;
    // To Do: Upload and save video
    res.redirect(routes.videoDetail(324393));
  };
  
export const videoDetail = (req, res) =>
  res.render("videoDetail", { pageTitle: "Video Detail" });

export const editVideo = (req, res) =>
  res.render("editVideo", { pageTitle: "Edit Video" });

export const deleteVideo = (req, res) =>
  res.render("deleteVideo", { pageTitle: "Delete Video" });

함수별로 export 되어있음을 확인 

 

//userController 

import routes from "../routes";

export const getJoin = (req, res) => {
  res.render("join", { pageTitle: "Join" });
};
export const postJoin = (req, res) => {
  const {
    body: { name, email, password, password2 }
  } = req;
  if (password !== password2) {
    res.status(400);
    res.render("join", { pageTitle: "Join" });
  } else {
    // To Do: Register User
    // To Do: Log user in
    res.redirect(routes.home);
  }
};


export const getLogin = (req, res) =>
  res.render("login", { pageTitle: "Log In" });
export const postLogin = (req, res) => {
  res.redirect(routes.home);
};

export const logout = (req, res) => {
    // To Do: Process Log Out
    res.redirect(routes.home);
  };
  
export const userDetail = (req, res) => res.render("userDetail");
export const editProfile = (req, res) => res.render("editProfile");
export const changePassword = (req, res) => res.render("changePassword");

 

이렇게만 해도 왠만한  "구조/틀" 을 다 잡은 것이다.

 

그렇다면 이제 실제 화면에 뿌려지는 것을 보기 위해 뷰(veiw) 를 해보자 

 

 

 

 

Task3. 뷰 세분화 

 

pug 사용 

  • routes.js 를 애초에 (Task1)에서 작업했기에, 이를 활용하여 빠짐없이 뷰 페이지를 생성한다
  • view는 
    layout / mixins / partials 을 사용 
  • 이부분은 내용 추후 정리 or 스킵 

 

 

 

 

Task4. middleware 관리 (feat. locals) 

 

 

import routes from "./routes";

export const localsMiddleware = (req, res, next) => {
  res.locals.siteName = "SuperBaik ";
  res.locals.routes = routes;
  res.locals.user = {
    isAuthenticated: true,
    id: 1
  };


  next();
  
};

 

Task5. url 에 따른 id 값 확인 ( 모든 링크 최종확인 ) 

 

 

 

 

 

 

느낀점 & 아리까리 사항 

 

1. middleware 관리 와 app.use 는 express 의 표준? 이라고 보고 따르면 되는것인지.  

 

2. 콜백함수에서 res.render 나 res.send 혹은 res.locals 등 때에 따라 다르게 지원을 하는데 어떻게 이걸 알고 vscode는 지원하는지? 

 

3. middelware local이 개념이 매우 중요하다.  view에서도 routes를 쓸수있게 해준다.  

이는 app.use로 계속 실행되고있기 때문인가? 

 

4.export const home = (reqres=> res.render("home", { pageTitle: "home" });

 

 

=>

render 함수가  두번째 파라미터로 객체를 반환 

pageTitle 은 key 

"home" 은 value 

 

근데 view에서는 왜 변수로 key를 인식 

(templete 엔진이 할일 할) 

var title= {
	key : value 
}

res.render("/index", title) ; 

//이것과 같은 개념. 이해하겠지 ? 

 

 

이런식으로 객체(=pageTitle)  날려줄 때 pageTitle은 내부적으로 공유되는 전역변수와도 같은건가? 어떤 원리인지.

 

5. ES6 왜 굳이 쓰는가? 이런 표현이 더 효율적인 이유라도 ? 

 

 

const {

      query: { termsearchingBy }

    } = req;

 

이런표현

 

=> 비구조화 할당 

 

참고 

 

sanghaklee.tistory.com/54

 

[ECMAScript6 / ES6] 아름다운 JavaScript를 위한 ES6

Introduction ECMAScript5는 2009.12에 나왔다. 지금은 2017년이고 ECMAScript8이 가장 최신 버전이다. 그럼에도, 아직 많은 JavaScript 문법은 ES5로 코딩되고 있다. ES6 이상으로 넘어가기 위한 몇 가지 걸림..

sanghaklee.tistory.com

6. req.query.term 라는 것은 어떻게 추적할 수 있을까 ? 

 

=> 그종류들에 대해서 좀더 살펴보자 추후 지속적으로 

 

 

7. userRouter.get(routes.userDetail(), userDetail);

어찌알고 함수로 썼을까 , id 는 함수로 관리하네?