생성자 함수 createApplication(1)

김대웅·2021년 6월 21일
0

express 분석

목록 보기
1/14

node.js의 express.js 한줄 한줄 분석하고 있습니다.

express/lib/express.js

exports = module.exports = createApplication;

/**
 * exports와 module.exports의 차이
 *
 * 노드의 경우 파일을 실행시키기 전에 퍄일내의 스크립트들을 즉시 실행 함수로 감쌈
 *
 * (function (exports, require, module, __filename, __dirname) {
 *     // 스크립트 위치
 * });
 *
 * 따라서 exports와 module의 경우 즉시 실행함수를 통해 들어오는 인자에 불과함
 *
 */

/**
 * exports = module.exports = createApplication; 으로 모듈을 익스포트 하는 이유
 *
 * exports와 module.exports가 가리키는 개체의 프로퍼티를 바꾸는것이 아니라 개체 자체를 바꾸어야하는경우
 *
 * exports와 module.exports 둘다 바꾸지 않은경우 서로 다른것을 가리킬 위험이 있음
 */

/**
 * exports와 module.exports의 참조 관계
 *
 * exports -> module.exports -> {}
 *
 * var module = new Moduel(...);
 * var exports = module.exports;
 *
 * https://stackoverflow.com/questions/7137397/module-exports-vs-exports-in-node-js 참고
 *
 */

/**
 * require()호출을 통해 받는 값 -> module.exports
 *
 * exports는 편의 변수로 모듈 작성자가 코드를 덜 작성하도록 돕는다.
 * exports는 require()함수에서 반환되지 않는다.
 *
 * https://edykim.com/ko/post/module.exports-and-exports-in-node.js/#요약 참고
 */
 
 /**
 * moduel.exports와 exports require 간의 관계
 * 
 * https://medium.com/@chullino/require-exports-module-exports-공식문서로-이해하기-1d024ec5aca3 참고
 */

exports 와 module.exports에 대해

  • export의 경우 module.export를 참조하고 module.export가 빈 개체를 참조하고 있다.(export -> module.export -> {})
  • 개체의 경우 참조형 데이터이므로 개체의 프로퍼티를 변경하는것은 위의 참조관계를 무너뜨리지 않는다.
  • 프로퍼티 변경이 아닌 개체 자체를 바꾸는 경우 exports와 moduel.export의 참조관계를 무너뜨릴수 있다.
  • require의 경우 module.export가 참조하고 있는 값을 가져오므로, express에서처럼 exports = module.export = createApplication; 형태로 참조 관계를 다시 맞추어줄 필요는 없다.(exports가 module.export와는 다른 개체를 참조한다 하더라도 require함수에의해 가져오는 개체는 exports가 아닌 module.export이므로)
  • 그럼에도 불구하고 express에서 exports = module.export = createApplication;구조를 사용한 이유는 express가 익스포트하는 개체는 createApplication함수가 유일하지 않기 때문이다.
/**
 * Expose the prototypes.
 */

exports.application = proto;
exports.request = req;
exports.response = res;

/**
 * Expose constructors.
 */

exports.Route = Route;
exports.Router = Router;

/**
 * Expose middleware
 */

exports.json = bodyParser.json
exports.query = require('./middleware/query');
exports.raw = bodyParser.raw
exports.static = require('serve-static');
exports.text = bodyParser.text
exports.urlencoded = bodyParser.urlencoded
  • express의 경우 createApplication함수에 몇몇 프로퍼티를 추가하여 익스포트한다.
  • 이때 exports를 사용하여 프로퍼티를 추가하므로 exports = module.export = createApplication;형태로 코드를 구성하였다.(exports와 module.export가 다른 개체를 바라보고 있는경우 exports를 통해 추가한 개체는 require를 통해 가져올 수 없기 때문)
  • 만약 프로퍼티를 moduel.export.Route = Route;의 형태로 저장한다면 exports = module.export = createApplication;으로 코드를 작성하지 않았을 것이다.

exports default와 module.export에 대해

  • es6의 exports default의 경우 개체를 익스포트하므로 module.export와 같을것이라 생각하였다.
  • 하지만 babel에 의해 변환된 코드를 보면 그렇지 않다.
  • exports에 default프로퍼티를 추가하여 해당 프로퍼티에 값을 넣어준다.
  • require의 경우 module.export를 가져오는데 exports default에 의해 변경된 값이 개체가 아니라 프로퍼티라면 문제가 아닐까 하는 생각을 할 수 있다.
  • babel이 import문법을 require과 1대1로 치환하지 않기 때문에 해당 문제는 발생하지 않는다.
var _express = _interopRequireDefault(require("express"));
  • _interopRequireDefault함수는 ex6문법에 의해 익스포트된 개체("default" 프로퍼티에 실제 값이 들어있는 개체)가 아니경우(module.export = createApplication과 같은 경우) ex6문법에 의해 익스포트된 개체로 변경(return { "default" : obj };)해서 사용한다.
  • 이후 개체를 사용할 때 default프로퍼티에 접근하여 사용(=pp.set(VIEWS, _path["default"].join(__dirname, VIEWS));)한다.

require과 import에 대해

  • require과 import는 단지 표현방식의 차이만 있는것이 아니다.
  • require의 경우 파일의 형태로 분리되어 있는 모듈을 포함시키는 함수이다.
  • require함수는 인자로 받아온 파일을 읽고, 실행하고, 모듈을 리턴한다.
  • require의 경우 node.js의 빌트인 모듈(http, fs, path등)과 커뮤니티 기반 모듈(node_modules에 저장되는) 그리고 로컬 모듈만을 읽을 수 있다.
  • import의 경우 ES module만 가져올 수 있다.
  • import는 파일 타입의 모듈을 가져올 수 없다. (deno에서의 모듈시스템을 의미하는것 같다.)
  • node.js의 경우 common js의 모듈 시스템을 사용(require, module.export)한다.
  • node.js자체적으로 es6모듈 시스템을 이해할 수 없다.
  • babel이 node.js가 이해할수 있도록 코드를 바꾸어주므로 위의 상황과 같은 것들이 발생한다.

https://flexiple.com/javascript-require-vs-import/ 참고

https://github.com/JsTsPractices/express/commit/d96c55cb2a670c88ac715370a7d74c9b7a511fd6

profile
42seoul cadet

0개의 댓글