[오류해결] CJS 특징으로 인한 모듈 오류

최주희·2024년 4월 13일
0

트러블슈팅

목록 보기
1/2
post-thumbnail
post-custom-banner

[문제 발생]

현재, 내가 제작하고 있는 것은 도서 구매 사이트이다.

문제는 카테고리 전체 목록을 조회하고자 했지만, 도서 전체 목록이 조회가 되고 있었다.

[작성한 코드]

내가 짠 코드는 아래와 같다.

1. Express 앱을 설정하고 라우팅을 구성

[app.js]

const express = require('express');
const app = express();

app.listen(process.env.PORT);

const bookRouter = require('./routes/books');
const categoryRouter = require('./routes/categorys');

app.use('/books', bookRouter);
app.use('/categorys', categoryRouter);

2. 라우터 모듈

bookscategorys에 넣어줄 모듈
재사용되는 부분이라 따로 모듈로 만들었다.

const express = require('express');
const router = express.Router();
router.use(express.json());

module.exports = router;

3. 도서 관련 라우팅 및 컨트롤러 구현

[route/books.js]

도서 관련 라우팅을 설정하고, 해당 요청에 대한 처리를 컨트롤러로 전달

const router = require('../modules/common');
const { getAllBooks } = require('../controller/BookController');

// 전체 도서 조회 
router.get('/', getAllBooks);

module.exports = router;

[BookController.js]

도서 관련 요청을 처리하는 컨트롤러,
getAllBooks 함수는 모든 도서를 조회하고, 해당 정보를 반환

const pool = require('../db');
const { StatusCodes } = require('http-status-codes');

const getAllBooks = async (req, res) => {
    try {
      const sql = `SELECT * FROM books`;
      const books = await pool.execute(sql);
      res.status(StatusCodes.OK).json(books[0]);
    } catch (error) {
      res
        .status(StatusCodes.INTERNAL_SERVER_ERROR)
        .json({ msg: '전체 도서 조회 중에 오류가 발생했습니다.' });
    }
};

module.exports = {
  getAllBooks,
};

4. 카테고리 관련 라우팅 및 컨트롤러 구현

[routes/categorys.js]

const router = require('../modules/common');

const allCategory = require('../controllers/CategoryController');

// 카테고리 전체 목록조회
router.get('/', allCategory);

module.exports = router;

[controllers/CategoryController.js]

allCategory 함수는 모든 카테고리를 조회하고, 해당 정보를 반환

const pool = require('../db');
const { StatusCodes } = require('http-status-codes');

const allCategory = async (req, res) => {
  const sql = `SELECT * FROM categorys`;
  //카테고리 전체 목록 리스트
  try {
    const result = await pool.execute(sql);
    const category = result[0];
    res.status(StatusCodes.OK).json(category);
  } catch (error) {
    res.status(500).json({ msg: '카테고리 전체 목록 조회 중에 문제가 발생했습니다.' });
  }
};

module.exports = allCategory;

[해결 과정]

1. 라우터 모듈의 문제

이유를 찾던 중 다른 라우터 모두 하나의 라우터 객체를 가리키고 있는 것 아니냐는 조언을 얻었다

그래서 추가로 똑같이 다른 라우터를 추가해서 모듈을 가지고 와서 확인해보았다.

맞았다. 내가 만든 "라우터 모듈"이 문제라는 것을..

2. 왜 이런 문제가 발생한 것일까?

require 함수를 사용하여 모듈을 로딩하는 방식은 CommonJs 방식이다.

CommonJs

정적 바인딩, 동기 import를 큰 특징으로 가지는 모듈 시스템

정적 바인딩

require를 통해 가져온 값을 복사본을 제공한다.
즉, module.exports를 수행한 곳에서 값의 변경이 있어도 최초 require 이후에는 변경된 값을 사용할 수 없다.

그렇기 때문에 처음 books.js에서 수행한 후에, 이후 라우터 들은 그 값을 그대로 가지고 온 것이다.

Q. CJS는 어디에 유용할까?

동기 import라는 특징 덕에 이는 서버사이드에서 용이하다.
CommonJs는 원래 이름도 ServerJs라고한다.

[결론]

CommonJS의 특징 중 하나는 정적 바인딩이며, 이는 require를 통해 가져온 값의 복사본을 제공하고 최초 로딩 이후에는 변경된 값을 반영하지 않아 모듈 캐싱으로 인해 동일한 객체를 참조하는 문제가 발생한 것이다.

즉, 하나의 라우터 모듈이 여러 파일에서 공유되어 사용될 때에는 같은 라우터 객체가 공유되는 문제가 발생

[해결 방법]

  • 각각의 라우터 모듈에서 독립적인 라우터 객체를 생성하도록 수정
    => 각 모듈이 자체적으로 독립적인 라우팅을 수행할 수 있습니다.

1. 독립적으로 라우터 객체 생성

[routes/books.js]

const express = require('express');
const router = express.Router();
router.use(express.json());
const allCategory = require('../controllers/CategoryController');

// 카테고리 전체 목록조회
router.get('/', allCategory);

[routes/categorys.js]

const express = require('express');
const router = express.Router();
router.use(express.json());
const { getAllBooks, getDetailBook } = require('../controllers/BookController');

// 전체 도서 조회 
router.get('/', getAllBooks);

module.exports = router;

참고자료

profile
큰 목표보단 꾸준한 습관 만들기
post-custom-banner

0개의 댓글