[Next.js] Custom Server - Express

Hyeok·2023년 1월 15일
2

next+express

Next.js를 Express 서버와 함께 실행시키는 방법입니다.

설치

CRN - Next.js 프로젝트를 생성

npx create-next-app@latest

# √ What is your project named? ... client
# √ Would you like to use TypeScript with this project? ... No
# √ Would you like to use ESLint with this project? ... Yes
기존 폴더 구조 src 사용

Express 설치

npm install --save express dotenv

# 서버 자동 재시작을 위한 패키지
npm install --save-dev nodemon

Express 서버 생성

Express 서버파일을 작성합니다.

  • 생성한 Next.js 프로젝트 폴더에 server 폴더 생성
  • server.js 파일에 Express 서버를 실행하기 위한 코드 작성
// server.js
const express = require('express');
const dotenv = require('dotenv');
dotenv.config({ path: '.env' }); // 환경변수 사용

const app = express();
const port = process.env.PORT; //.env 파일에서 설정해준다

app.set('port', port);
app.use(express.json());
app.use(express.urlencoded({ extended: false }));

app.use('/', (req, res, next) => {
  res.send('hello!');
});

app.listen(app.get('port'), () => {
  console.log(`Express server listen port:${port}`);
  console.log(`http://localhost:${port}`);
});

Next.js 서버 설정

server/server.js 파일에 next.js 서버 설정을 추가합니다.

# .env
SERVER_PORT=[YOUR_PORT]
// server.js
const express = require('express');
const dotenv = require('dotenv');
dotenv.config({ path: '.env' }); // 환경변수 사용
const path = require('path');

/** Create Express */
const app = express();

/** Next.js 모듈 가져오기 */
const next = require('next');
const { parse } = require('url');

/** Next.js 설정 */
const port = process.env.SERVER_PORT;
/**
 * 개발환경이아니라면 dev 옵션을 false 로 설정하고
 * 서버 시작전에 next build 를 실행해준다.
 */
const nextApp = next({ dev: true, port });
const handle = nextApp.getRequestHandler();

nextApp
  .prepare()
  .then(() => {
    /** Express Settings */
    app.use(express.json());
    app.use(express.urlencoded({ extended: true }));
    /** static 경로 설정 */
    app.use(express.static(path.join(__dirname, '../', 'public')));

    /** Express Router Settings */
    app.use('/api', (req, res, next) => {
      res.send('hello!');
    });

    /** Next.js Routing */
    app.get('/', (req, res) => {
      const parsedUrl = parse(req.url, true);
      const { pathname, query } = parsedUrl;
      nextApp.render(req, res, pathname, query);
    });
    app.get('*', (req, res) => {
      return handle(req, res);
    });

    app.listen(port, () => {
      console.log(`Express server listen port:${port}`);
      console.log(`http://localhost:${port}`);
    });
  })
  .catch((ex) => {
    console.error(ex.stack);
    process.exit(1);
  });

module.exports = app;

실행 설정

package.json 파일의 시작명령어 script를 Express를 사용하도록 수정합니다.

// package.json
...,
"scripts": {
    "dev": "node server/server.js",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
...

nodemon 사용

// package.json
...,
"scripts": {
    "dev": "nodemon server/server.js",
  },
...

nodemon.json 사용

  • nodemon.json 파일을생성
// nodemon.json
{
  "watch": ["server/server.js", "server/src"],
  "exec": "node server/server.js",
  "ext": "js json"
}
  • script 수정
// package.json
...,
"scripts": {
    "dev": "nodemon",
  },
...

시작

모든 설정이 완료되었습니다!
이제 시작명령어를 입력하고 Express를 Custom 서버로 사용하는 Next.js를 시작해보세요.

npm run dev

참조

profile
FE 탐구생활 🙂

1개의 댓글

comment-user-thumbnail
2024년 12월 14일

좋은 글 잘 읽었습니다.
다만 Express.js 5.x이 출시되면서 일부 변경사항이 있어 말씀드립니다.
Express.js 5.x부터 경로에 와일드카드(*) 사용이 제한되었기 때문에, 위 코드가 Express.js 5.x 환경에서 실행될 경우 TypeError가 발생할 수 있습니다.

해결 방법은 "app.get('*', (req, res) => {" 부분을 "app.use((req, res) => {" 로 수정해 미들웨어로 바꾸면 정상적으로 동작합니다.

이 문제의 원인은 Express.js의 버전 업그레이드와 함께 사용되는 패키지들의 변화 때문입니다.
특히, router 2.0.0 패키지가 도입되면서 path-to-regexp 8.0.0이 적용되었는데, 이로 인해 와일드카드(*)의 의미가 변경되었습니다.
Express.js 4.x까지는 path-to-regexp 0.1.12 버전을 사용해 단독 와일드카드가 허용되었으나, Express.js 5.x에서는 더 이상 사용할 수 없습니다.

제가 위 코드를 직접 실행해보진 않았지만, 참고 자료로 활용했으며 이 글이 Next.js custom-server와 Express.js를 검색하면 가장 먼저 보이는 글이라 정보를 공유합니다.

참고

답글 달기

관련 채용 정보