Nodejs MVC patter Setting
니꼬 쌤의 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 = (req, res) => 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: { term: searchingBy }
} = req;
이런표현
=> 비구조화 할당
참고
[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 는 함수로 관리하네?