• 카테고리

    질문 & 답변
  • 세부 분야

    풀스택

  • 해결 여부

    미해결

Main.pug 파일에 과 정적파일에 관한 질문입니다.

18.11.14 11:25 작성 조회수 236

0

※파일 전체의 코드는 질문 하단에 있습니다.

안녕하세요. 항상 최고의 node.js 강좌 잘 듣고 있습니다.

질문은 두개 입니다.

  1. main.pug 파일을 보면 다음과 같은 부분이 있습니다.

    [].forEach.call(document.querySelectorAll('.twit-follow'), function (tag) {

    tag.addEventListener('click', function () {

[] 부분이 이해가 안갑니다. 빈 리스트를 forEach 하는게 어떻게 가능한지요. "변수".forEach라면 모르겠는데...

이 부분에는 어떤 값이 어떻게, 언제 오기에 저 문법이 가능한지 알고 싶습니다.

  1. 정적파일은 기왕이면 다른 미들웨어들 위에 두라고 하신 부분이 이해가 잘 되지 않습니다.
  2. 예를 들어,

app.use(morgan('dev'));

app.use(express.static(path.join(__dirname, 'public')));

app.use('/img', express.static(path.join(__dirname, 'uploads')));

app.use(express.json());

app.use(express.urlencoded({ extended: false }));

app.use(cookieParser(process.env.COOKIE_SECRET));

위와 같은 코드에서 morgan 뒤쪽에 static middleware 를 위치 시켜서, 다른 미들웨어들이 불필요하게 사용되지 않게 해서 자원을 아끼라고 말씀하셨습니다.

그러나, 미들웨어들은 일단 실행되면 (next() 가 있다는 가정하에, 에러가 없다면) 순서대로 마지막 미들웨어까지 계속 나가야 하는것 아닌가요? 결국 위에 위치시키나, 아래 위치시키나 다른 미들웨어들을 실행하는건 마찬가지 같은데요.

a) express.static은 next()가 없는 건가요?

b)만약 express static이, 다음 미들웨어를 실행하지 않고 저기서 끝난다면, app.js 파일을 사용할 때마다 모든 요청이 전부 express.static 에서 끝나 버릴텐데, 그럼 json, eurlencoded, cookieParser 등등도 사용할 수 없게 되는 거 아닐까요?

혹시 express.static은 특정 요청에만 응답하고, 일반적인 요청에는 응답을 안하는 기능이 있는 건가요? 그렇다고 하면, 결국 이 명령어를 상위에 위치시킬 필요는 없는것 같은데요.

main.pug 파일 -----------

extends layout

block content

.timeline

if user

div

form#twit-form(action='/post' method='post' enctype='multipart/form-data')

.input-group

textarea#twit(name='content' maxlength=140)

.img-preview

img#img-preview(src='' style='display: none;' width='250' alt='미리보기')

input#img-url(type='hidden' name='url')

div

label#img-label(for='img') 사진 업로드

input#img(type='file' accept='image/*')

button#twit-btn.btn(type='submit') 짹짹

.twits

form#hashtag-form(action='/post/hashtag')

input(type='text' name='hashtag' placeholder='태그 검색')

button.btn 검색

for twit in twits

.twit

input.twit-user-id(type='hidden' value=twit.user.id)

input.twit-id(type='hidden' value=twit.id)

.twit-author= twit.user.nick

-const follow = user && user.Followings.map(f => f.id).includes(twit.user.id);

if user && user.id !== twit.user.id && !follow

button.twit-follow 팔로우하기

.twit-content= twit.content

if twit.img

.twit-img

img(src=twit.img alt='섬네일')

script.

if (document.getElementById('img')) {

document.getElementById('img').addEventListener('change', function (e) {

var formData = new FormData();

console.log(this, this.files);

formData.append('img', this.files[0]);

var xhr = new XMLHttpRequest();

xhr.onload = function () {

if (xhr.status === 200) {

var url = JSON.parse(xhr.responseText).url;

document.getElementById('img-url').value = url;

document.getElementById('img-preview').src = url;

document.getElementById('img-preview').style.display = 'inline';

} else {

console.error(xhr.responseText);

}

};

xhr.open('POST', '/post/img');

xhr.send(formData);

});

}

[].forEach.call(document.querySelectorAll('.twit-follow'), function (tag) {

tag.addEventListener('click', function () {

var isLoggedIn = document.querySelector('#my-id');

if (isLoggedIn) {

var userId = tag.parentNode.querySelector('.twit-user-id').value;

var myId = isLoggedIn.value;

if (userId !== myId) {

if (confirm('팔로잉하시겠습니까?')) {

var xhr = new XMLHttpRequest();

xhr.onload = function () {

if (xhr.status === 200) {

location.reload();

} else {

console.error(xhr.responseText);

}

};

xhr.open('POST', '/user/' + userId + '/follow');

xhr.send();

}

}

}

});

});

app.js 파일입니다.

const express = require('express');

const cookieParser = require('cookie-parser');

const morgan = require('morgan');

const path = require('path');

const session = require('express-session');

const flash = require('connect-flash');

const passport = require('passport');

require('dotenv').config();

const pageRouter = require('./routes/page');

const authRouter = require('./routes/auth');

const postRouter = require('./routes/post');

const userRouter = require('./routes/user');

const { sequelize } = require('./models');

const passportConfig = require('./passport');

const app = express();

sequelize.sync();

passportConfig(passport);

app.set('views', path.join(__dirname, 'views'));

app.set('view engine', 'pug');

app.set('port', process.env.PORT || 8001);

app.use(morgan('dev'));

app.use(express.static(path.join(__dirname, 'public')));

app.use('/img', express.static(path.join(__dirname, 'uploads')));

app.use(express.json());

app.use(express.urlencoded({ extended: false }));

app.use(cookieParser(process.env.COOKIE_SECRET));

app.use(session({

resave: false,

saveUninitialized: false,

secret: process.env.COOKIE_SECRET,

cookie: {

httpOnly: true,

secure: false,

},

}));

app.use(flash());

app.use(passport.initialize());

app.use(passport.session());

app.use('/', pageRouter);

app.use('/auth', authRouter);

app.use('/post', postRouter);

app.use('/user', userRouter);

app.use((req, res, next) => {

const err = new Error('Not Found');

err.status = 404;

next(err);

});

app.use((err, req, res) => {

res.locals.message = err.message;

res.locals.error = req.app.get('env') === 'development' ? err : {};

res.status(err.status || 500);

res.render('error');

});

app.listen(app.get('port'), () => {

console.log(app.get('port'), '번 포트에서 대기중');

});

답변 2

·

답변을 작성해보세요.

0

ryu sin님의 프로필

ryu sin

질문자

2018.11.14

답변 감사합니다. 정말 최고입니다 ! : )

0

[].forEach.call 문법은요. 빈 배열을 forEach를 도는게 아니라 배열에서 forEach 메서드를 빌려(call 메서드가 그 역할을 해줍니다) 유사배열(forEach 메서드가 없음)에 적용하는 것입니다.

아 그런데 생각해보니 document.querySelectorAll()은 유사배열이지만 forEach를 제공하네요. 제 실수입니다.

express.static에 관해서는요. 이것은 정적 파일을 찾으면 res.sendFile을 하고, 못 찾으면 next()를 합니다.

미들웨어는 위에서부터 순차적으로 실행되기 때문에(next()로 다음으로 넘겨주고요)

파일을 찾아서 res.sendFile을 한 경우에는 다음 미들웨어가 실행되지 않습니다. 그렇기 때문에 최대한 위로 올려야 쓸데없는 미들웨어들이 실행이 되지 않고요. 못 찾은 경우에는 next()를 내부적으로 해서 다음 미들웨어로 넘어갑니다.