본문 바로가기

개발/Node.JS

npm - CommonJS & require가 작동하는 방식

구조에 CommonJS

자바 스크립트 언어에는 ES2015 표준 이전의 코드 구성 방식이 없었습니다. Node.js는이 간격을 CommonJS 모듈 형식 으로 채 웁니다 . 이 기사에서는 Node.js 모듈 시스템의 작동 방식, 모듈 구성 방법 및 Node.js의 새로운 ES 표준 의미에 대해 학습합니다.

모듈 시스템이란 무엇입니까?

모듈은 코드 구조의 기본 빌딩 블록입니다. 모듈 시스템을 사용하면 코드를 구성하고 정보를 숨기고 구성 요소의 공용 인터페이스 만 사용하여 노출 할 수 module.exports있습니다. require통화 를 사용할 때마다 다른 모듈을로드하고 있습니다.

가장 간단한 예제는 CommonJS를 사용하는 다음과 같습니다.

// add.js
function add (a, b) {
  return a + b
}

module.exports = add

add방금 만든 모듈 을 사용하려면 모듈을 요구해야합니다.

// index.js
const add = require('./add')

console.log(add(4, 5))
//9

내부적 add.js으로 Node.js에 의해 다음과 같이 포장됩니다.

(function (exports, require, module, __filename, __dirname) {
  function add (a, b) {
    return a + b
  }

  module.exports = add
})

따라서 require 및 module 과 같은 전역 변수와 같은 변수에 액세스 할 수 있습니다 또한 변수가 전역 객체가 아닌 모듈로 범위가 지정됩니다.

어떻게 require작동합니까?

Node.js의 모듈로드 메커니즘은 첫 번째 require호출 에서 모듈을 캐싱합니다 즉, 사용할 때마다 require('awesome-module')동일한 인스턴스 awesome-module가 생성되어 모듈이 싱글 톤과 유사하고 응용 프로그램에서 동일한 상태를 유지하게됩니다.

파일 시스템 또는 설치된 모듈에서 원시 모듈 및 경로 참조를로드 할 수 있습니다. 전달받는 경우 상기 식별자 require함수 네이티브 모듈 또는 파일 참조되지 않은 경우 (시작으로 /.././다음 Node.js를 설치 모듈 모양 또는 이와 유사한 것). node_modules폴더 에서 참조 된 모듈을 찾는 파일 시스템을 탐색 합니다. 현재 모듈의 상위 디렉토리에서 시작하여 올바른 모듈을 찾거나 파일 시스템의 루트에 도달 할 때까지 상위 디렉토리로 이동합니다.

후드 필요 - module.js

노드 코어에서 모듈로드를 처리하는 모듈이 호출 되며 Node.js 저장소의 lib / module.js에서 module.js찾을 수 있습니다 .

여기에서 확인해야 할 가장 중요한 기능은 _load및 _compile기능입니다.

Module._load

이 함수는 모듈이 이미 캐시에 있는지 여부를 확인합니다. 그렇다면 내보내기 객체를 반환합니다.

모듈이 네이티브 인 경우 NativeModule.require()파일 이름과 함께를 호출 하고 결과를 반환합니다.

그렇지 않으면 파일에 대한 새 모듈을 만들어 캐시에 저장합니다. 그런 다음 내보내기 내용을 반환하기 전에 파일 내용을로드합니다.

Module._compile

컴파일 기능은 올바른 범위 또는 샌드 박스의 파일 내용을 실행뿐만 아니라 같은 도우미 변수를 노출 requiremodule또는 exports파일에.

Node.js에서 require가 작동하는 방식
요구되는 작동 원리 - James N. Snell

코드 구성 방법?

우리의 어플리케이션에서, 모듈을 생성 할 때 응집과 결합의 올바른 균형을 찾아야합니다. 바람직한 시나리오는 모듈의 높은 응집력과 느슨한 결합 을 달성 하는 것 입니다.

모듈은 응집성이 높은 기능의 단일 부분에만 집중해야합니다. 느슨한 결합은 모듈이 전역 또는 공유 상태가 아니어야 함을 의미합니다. 매개 변수를 전달해야만 통신 할 수 있으며 더 넓은 코드베이스를 만지지 않아도 쉽게 바꿀 수 있습니다.

대개 다음과 같은 방법으로 명명 된 함수 또는 상수 를 내 보냅니다 .

'use strict'

const CONNECTION_LIMIT = 0

function connect () { /* ... */ }

module.exports = {
  CONNECTION_LIMIT,
  connect
}

node_modules에 무엇이 있습니까?

node_modules폴더는 Node.js를 모듈을 찾습니다 장소입니다. npm v2 및 npm v3 은 종속성을 다르게 설치합니다. 다음을 실행하여 사용중인 npm 버전을 확인할 수 있습니다.

npm --version

npm v2

npm 2는 중첩 된 방식으로 모든 종속성을 설치합니다. 여기서 기본 패키지 종속성은 해당 node_modules폴더에 있습니다.

오후 3시

npm3은 이러한 보조 종속성을 병합하고 루트 node_modules폴더 에 설치하려고 시도 합니다. 즉, node_modules명시 적 또는 암시 적 종속성을 확인하는 패키지 를 보지 못합니다 이 방법으로 npm 3이 비 결정적이기 때문에 설치 순서가 폴더 구조를 변경시킬 수도 있습니다.


.a에서만 패키지를 설치하여 node_modules 디렉토리가 항상 동일한 지 확인할 수 있습니다 package.json이 경우 사전 순으로 종속 항목을 설치하므로 동일한 폴더 트리를 가져옵니다. 이는 모듈이 경로를 조회 키로 사용하여 캐시되기 때문에 중요합니다. 각 패키지는 고유 한 하위 node_modules폴더를 가질 수 있으므로 동일한 패키지 및 동일한 모듈의 여러 인스턴스가 생성 될 수 있습니다.

모듈을 다루는 방법?

모듈 배선에는 크게 두 가지 방법이 있습니다. 그 중 하나는 하드 코딩 된 종속성을 사용하여 require호출을 사용하여 한 모듈을 다른 모듈에 명시 적으로로드 합니다. 또 다른 방법은 종속성 주입 패턴을 사용하는 것입니다. 여기에서 구성 요소를 매개 변수로 전달하거나 전역 컨테이너 (IoC 또는 Inversion of Control 컨테이너라고 함) 를 사용하여 모듈 관리를 중앙 집중화합니다.

Node.js가 하드 코딩 된 모듈 로딩을 사용하여 모듈 수명주기를 관리하도록 허용 할 수 있습니다. 직관적 인 방식으로 패키지를 구성하므로 이해와 디버깅이 쉬워집니다.

Dependency Injection은 Node.js 환경에서는 거의 사용되지 않지만 유용한 개념입니다. DI 패턴은 모듈의 디커플링을 향상시킬 수 있습니다. 모듈에 대한 종속성을 명시 적으로 정의하는 대신 외부에서 수신합니다. 따라서 동일한 인터페이스를 가진 모듈로 쉽게 대체 할 수 있습니다.

팩토리 패턴을 사용하는 DI 모듈의 예제를 보자 :

class Car {
  constructor (options) {
    this.engine = options.engine
  }

  start () {
    this.engine.start()
  }
}

function create (options) {
  return new Car(options)
}

module.exports = create

ES2015 모듈 시스템

위에서 보았 듯이, CommonJS 모듈 시스템은 모듈의 런타임 평가를 사용하여 모듈을 실행 전에 함수로 래핑합니다. ES2015 모듈은 모듈을 평가하기 전에 importexport바인딩이 만들어지기 때문에 래핑 할 필요가 없습니다 이 비 호환성 때문에 현재 ES 모듈을 지원하는 JavaScript 런타임이 없습니다.