Node.js를 사용하려면 ES6 가져 오기 / 내보내기가 필요합니다


930

공동 작업중인 프로젝트에서 사용할 수있는 모듈 시스템에 대해 두 가지 선택이 있습니다.

  1. 사용하여 모듈을 가져 오기 require및 사용 수출 module.exportsexports.foo.
  2. ES6을 사용하여 모듈 가져 오기 import및 ES6을 사용하여 내보내기export

하나를 다른 것보다 사용하면 성능상의 이점이 있습니까? 노드 1에서 ES6 모듈을 사용할 경우 알아야 할 다른 것이 있습니까?


9
node --experimental-modules index.mjsimportBabel없이 사용할 수 있으며 Node 8.5.0 이상에서 작동합니다. 당신은 (그리고해야한다)도 할 수 네이티브 ESModule로 NPM 패키지를 게시 이전에 대한 이전 버전과의 호환성, require방법.
Dan Dascalescu

답변:


728

하나를 다른 것보다 사용하면 성능상의 이점이 있습니까?

ES6 모듈을 기본적으로 지원하는 JavaScript 엔진은 아직 없습니다. 당신은 당신이 당신이 바벨을 사용하고 있다고 자신을 말했다. Babel 은 기본적 으로 CommonJS ( / ) 로 변환 import하고 export선언 합니다. 따라서 ES6 모듈 구문을 사용하더라도 Node에서 코드를 실행하면 기본적으로 CommonJS를 사용하게됩니다.requiremodule.exports

CommonJS와 ES6 모듈에는 기술적 인 차이가 있습니다. 예를 들어 CommonJS를 사용하면 모듈을 동적으로로드 할 수 있습니다. ES6에서는이를 허용하지 않지만 개발을위한 API가 있습니다.

ES6 모듈은 표준의 일부이므로 사용합니다.


16
나는 ES6 import함께 사용하려고했지만 require다르게 작동했습니다. CommonJS는 클래스가 하나만있는 동안 클래스 자체를 내 보냅니다. ES6 내보내기는 여러 클래스가 있으므로 .ClassName내 보낸 클래스를 가져 오는 데 사용해야 합니다. 실제로 구현에 영향을 미치는 다른 차이점이 있습니까?
Thellimist

78
@ Entei : 명명 된 내보내기가 아닌 기본 내보내기를 원하는 것 같습니다. module.exports = ...;와 같습니다 export default .... exports.foo = ...동등하다 export var foo = ...;
Felix Kling

10
Babel이 importWebpack 2 / Rollup (및 ES6 트리 흔들림을 허용하는 다른 번 들러) 과 함께 사용되는 Node의 CommonJS로 궁극적으로 변환하더라도 동등한 코드 노드 크런치보다 훨씬 작은 파일로 감을 수 있습니다 ES6은 require정확한 가져 오기 / 내보내기 분석을 허용 하므로 정확하게 사용 합니다 . 이것이 노드 (아직)와 다르지 않지만 코드가 궁극적으로 단일 브라우저 번들로 작동하는 경우 확실히 가능합니다.
이 벤슨

5
동적 가져 오기가 필요하지 않은 경우
chulian

3
ES6 모듈은 최신 V8에 있으며 플래그 뒤에 다른 브라우저에도 도착합니다. 참고 : medium.com/dev-channel/…
Nexii Malthus

180

고려해야 할 몇 가지 사용법 / 기능이 있습니다.

요구 사항 :

  • 로드 된 모듈 이름이 사전 정의 / 정적되지 않은 경우 또는 특정 코드 흐름에 따라 "정확하게 요구되는"경우에만 조건부로로드하는 동적로드를 가질 수 있습니다.
  • 로딩이 동 기적입니다. 즉 require, 여러 개가 있으면 하나씩로드되고 처리됩니다.

ES6 수입품 :

  • 명명 된 가져 오기를 사용하여 필요한 부분 만 선택적으로로드 할 수 있습니다. 메모리를 절약 할 수 있습니다.
  • 가져 오기는 비동기식 일 수 있으며 (현재 ES6 모듈 로더에서는 실제로 수행 할 수 있음) 약간 더 잘 수행 할 수 있습니다.

또한 Require 모듈 시스템은 표준 기반이 아닙니다. ES6 모듈이 존재하기 때문에 이제 표준이 될 가능성은 거의 없습니다. 앞으로 성능 측면에서 유리한 다양한 구현에서 ES6 모듈에 대한 기본 지원이 제공 될 것입니다.


16
ES6 가져 오기가 비동기식이라고 생각하는 것은 무엇입니까?
Felix Kling

5
@FelixKling-다양한 관측치의 조합. JSPM (ES6 모듈 로더 ...)을 사용하면 가져 오기에서 전역 네임 스페이스를 수정했을 때 다른 가져 오기에서 효과가 관찰되지 않는 것으로 나타났습니다 (비동기 적으로 발생하기 때문입니다. 이것은 변환 된 코드에서도 볼 수 있음). 또한 이것이 동작 (1 가져 오기는 다른 것에 영향을 미치지 않음)이므로 그렇게하지 않을 이유가 없으므로 구현에 따라 달라질 수 있습니다.
Amit

35
모듈 로더라는 매우 중요한 것을 언급했습니다. ES6는 가져 오기 및 내보내기 구문을 제공하지만 모듈로드 방법을 정의하지는 않습니다. 중요한 부분은 선언을 정적으로 분석 할 수있어 코드를 실행하지 않고도 종속성을 확인할 수 있다는 것입니다. 이를 통해 모듈 로더는 모듈을 동기식 또는 비동기식으로로드 할 수 있습니다. 그러나 ES6 모듈 자체는 동기식 또는 비동기식이 아닙니다.
Felix Kling

5
@FelixKling ES6 모듈 로더가 OP에 태그되어 있으므로 답변과 관련이 있다고 가정합니다. 또한 관측에 근거하여 비동기는 현재의 행동이며 향후 (모든 구현에서) 가능성이므로 고려할 관련 포인트라고 언급했습니다. 당신은 그것이 잘못 생각하십니까?
Amit

10
모듈 시스템 / 구문을 모듈 로더와 혼동하지 않는 것이 중요하다고 생각합니다. 예를 들어 노드를 개발하는 경우 require어쨌든 ES6 모듈을 컴파일 하고 있으므로 노드의 모듈 시스템과 로더를 사용하고 있습니다.
Felix Kling

41

주요 장점은 구문입니다.

  • 보다 선언적이며 컴팩트 한 구문
  • ES6 모듈은 기본적으로 UMD (Universal Module Definition)를 더 이상 사용하지 않습니다. 기본적으로 CommonJS와 AMD (서버와 브라우저) 사이의 스키마를 제거합니다.

ES6 모듈의 성능 이점은 거의 없습니다. 브라우저에서 ES6 기능을 완벽하게 지원하는 경우에도 모듈을 번들로 제공하기 위해 추가 라이브러리가 필요합니다.


4
브라우저에 ES6 모듈이 완벽하게 지원되는 경우에도 왜 번 들러가 필요한지 명확히 할 수 있습니까?
E. Sundin

1
더 이해하기 위해 편집 한 사과. 가져 오기 / 내보내기 모듈 기능은 기본적으로 모든 브라우저에서 구현되지 않았습니다. 트랜스 필러가 여전히 필요합니다.
snozza

16
나에게 약간의 모순이있는 것 같습니다. 완전한 지원 이 있다면 번 들러의 목적은 무엇입니까? ES6 사양에 빠진 것이 있습니까? 완전히 지원되는 환경 에서 번 들러가 실제로 할 수없는 것은 무엇입니까 ?
E. Sundin

1
@snozza가 말했듯이 ... "가져 오기 / 내보내기 모듈 기능은 모든 브라우저에서 순진하게 구현되지 않습니다. 트랜스 파일러가 여전히 필요합니다"
robertmain

2
더 이상 추가 라이브러리가 필요하지 않습니다. v8.5.0 (1 년 이상 전에 출시)부터 Babel없이 node --experimemntal-modules index.mjs사용할 수 있습니다 import. 당신은 (그리고해야한다) 또한 수 이전 버전과의 호환성, 기본 ESModule로 NPM 패키지를 게시 이전을위한 require방법. 많은 브라우저가 기본적으로 동적 가져 오기를 지원 합니다.
Dan Dascalescu

38

하나를 다른 것보다 사용하면 성능상의 이점이 있습니까?

현재 브라우저 엔진 import/export이 ES6 표준을 구현하지 않기 때문에 현재 답변은 아니요 입니다.

일부 비교 차트 http://kangax.github.io/compat-table/es6/ 는 이것을 고려하지 않으므로 Chrome의 거의 모든 녹색을 볼 때 조심하십시오. importES6의 키워드는 고려되지 않았습니다.

즉, V8을 포함한 현재 브라우저 엔진은 JavaScript 지시문을 통해 기본 JavaScript 파일 에서 새 JavaScript 파일 을 가져올 수 없습니다 .

( V8이 ES6 사양에 따라 구현할 때까지 년이지나거나 몇 년이 걸릴 수 있습니다.)

문서 는 우리가 필요 로하는 것이며이 문서 는 우리가 준수해야 할 것입니다.

그리고 ES6 표준에 따르면, .h파일 헤더가있는 프로그래밍 언어 C 에서처럼 모듈을 읽기 전에 모듈 종속성이 있어야한다고 합니다.

이것은 훌륭하고 잘 테스트 된 구조이며 ES6 표준을 만든 전문가가이를 염두에두고 있다고 확신합니다.

이것은 특별한 경우에 Webpack 또는 다른 패키지 번 들러가 번들을 최적화하고 필요하지 않은 번들의 종속성을 줄 이도록하는 것입니다. 그러나 우리가 완벽한 의존성을 가진 경우에는 결코 일어나지 않을 것입니다.

import/export기본 지원이 시작될 때까지 약간의 시간이 필요 하며 require키워드는 오랫동안 아무 데나 가지 않습니다.

무엇입니까 require?

이것은 node.js모듈을로드하는 방법입니다. ( https://github.com/nodejs/node )

노드는 시스템 레벨 방법을 사용하여 파일을 읽습니다. 당신은 기본적으로 그것을 사용할 때 그것에 의존합니다 require. JavaScript 파일 / 모듈을로드하기 위해 (종료 시스템, Linux, Mac, Windows에 따라) require와 같은 일부 시스템 호출로 uv_fs_open끝납니다.

이것이 사실인지 확인하려면 Babel.js를 사용하십시오. 그러면 import키워드가로 변환됩니다 require.

여기에 이미지 설명을 입력하십시오


2
실제로 성능 향상시킬 있는 영역은 번들 크기입니다. importWebpack 2 / Rollup 빌드 프로세스에서 사용하면 사용 하지 않는 모듈 / 코드를 '트리 떨림'하여 결과 파일 크기를 잠재적으로 줄일 수 있습니다. 작은 파일 크기 = 다운로드 속도 = 클라이언트에서 초기화 / 실행 속도가 빠릅니다.
이 벤슨

2
추론은 지구상의 현재 브라우저가 import 키워드를 기본적으로 허용하지 않았다는 것 입니다. 또는 이는 JavaScript 파일에서 다른 JavaScript 파일을 가져올 수 없음을 의미합니다. 이것이이 두 가지의 성능 이점을 비교할 수없는 이유입니다. 물론 Webpack1 / 2 또는 Browserify와 같은 도구는 압축을 처리 할 수 ​​있습니다. 그것들은 목에서 목까지입니다 : gist.github.com/substack/68f8d502be42d5cd4942
prosti November

4
당신은 '나무 흔들림'을 내려다보고 있습니다. 요점 링크에서 나무 흔들림이 논의되는 곳은 없습니다. 때문에 ES6 모듈을 사용하여, 그것을 가능하게 import하고 export특정 코드 경로를 가져 정적 선언하고, 반면에 require동적 일 수 있으므로 사용하지 않는 코드에 번들. 성능 이점은 indirect-- 웹팩 2 및 / 또는 롤업 수 잠재적 빠른 다운로드한다 작은 다발 크기 초래하므로 (브라우저의) 최종 사용자 빠르다는 나타난다. 모든 코드가 ES6 모듈로 작성되어 가져 오기를 정적으로 분석 할 수있는 경우에만 작동합니다.
리 벤슨

2
@LeeBenson의 답변을 업데이트했습니다. 아직 비교할 수없는 브라우저 엔진의 기본 지원을 고려한다고 생각합니다. Webpack을 사용하여 편리한 3 가지 흔들림 옵션은 CommonJS 모듈을 설정하기 전에도 달성 할 수 있습니다. 대부분의 실제 응용 프로그램에서는 어떤 모듈을 사용해야하는지 알고 있기 때문입니다.
prosti

1
귀하의 답변은 완전히 유효하지만 두 가지 특성을 비교하고 있다고 생각합니다. 모두 import/export 가로 변환되어 require부여되었습니다. 그러나이 단계 이전에 발생하는 일은 "성능"향상으로 간주 될 수 있습니다. 예 : lodashES6 및 you로 작성된 경우 import { omit } from lodash최종 번들에는 다른 유틸리티가 아닌 '생략'만 포함되지만 단순 require('lodash')은 모든 항목을 가져옵니다. 이렇게하면 번들 크기가 늘어나고 다운로드 시간이 길어 지므로 성능이 저하됩니다. 이것은 물론 브라우저 컨텍스트에서만 유효합니다.
Lee Benson

31

ES6 모듈을 사용하면 '트리 쉐이킹'에 유용 할 수 있습니다. 즉, Webpack 2, 롤업 (또는 다른 번 들러)을 사용하여 가져 오거나 가져 오지 않은 코드 경로를 식별하므로 결과 번들로 만들지 않습니다. 이렇게하면 필요하지 않은 코드를 제거하여 파일 크기를 크게 줄일 수 있지만 Webpack 등은 필요한지 여부를 알 수 없으므로 CommonJS와 함께 기본적으로 번들로 제공됩니다.

이것은 코드 경로의 정적 분석을 사용하여 수행됩니다.

예를 들어,

import { somePart } 'of/a/package';

... 번 들러에 package.anotherPart필요하지 않은 힌트를 제공 합니다 (가져 오지 않으면 올바르게 사용할 수 없습니까?). 번들링을 방해하지 않습니다.

Webpack 2에서이를 사용 가능하게하려면 트랜스 파일러가 CommonJS 모듈을 분리하지 않아야합니다. es2015babel과 함께 플러그인을 사용하는 경우 다음 .babelrc과 같이 비활성화 할 수 있습니다 .

{
  "presets": [
    ["es2015", { modules: false }],
  ]
}

롤업 및 기타 기능이 다르게 작동 할 수 있습니다. 관심이있는 경우 문서를보십시오.


2
또한 나무를 흔들어 주기
prosti

25

비동기 또는 게으른 로딩과 관련하여 import ()훨씬 강력합니다. 구성 요소가 비동기 방식으로 필요할 때 import확인한 다음 const변수 using 과 같이 비동기 방식으로 사용 await합니다.

const module = await import('./module.js');

아니면 사용하려면 require()다음,

const converter = require('./converter');

것입니다 import()자연의 비동기 사실이다. 에 neehar venugopal에서 언급 한 바와 같이 ReactConf , 당신은 클라이언트 측 아키텍처의 구성 요소를 반응 동적 부하에 사용할 수 있습니다.

또한 라우팅과 관련하여 더 좋습니다. 그것은 사용자가 특정 웹 사이트에 특정 구성 요소에 연결할 때 필요한 부분을 다운로드하기 위해 네트워크 로그를 만드는 특별한 것입니다. 예를 들어 대시 보드 앞의 로그인 페이지는 대시 보드의 모든 구성 요소를 다운로드하지 않습니다. 현재 필요한 것은 로그인 컴포넌트입니다.

동일은 간다 export: ES6는 exportCommonJS 경우와 정확히 동일합니다 module.exports.

참고 -node.js 프로젝트를 개발하는 경우을 사용하는 require()것처럼 노드에서 예외 오류가 발생하므로 엄격하게 사용해야 invalid token 'import'합니다 import. 따라서 노드는 import 문을 지원하지 않습니다.

업데이트 -Dan Dascalescu가 제안한 대로 : v8.5.0 (2017 년 9 월 릴리스)부터 Babel없이 node --experimental-modules index.mjs사용할 수 있습니다 import. 당신은 (그리고해야한다) 또한 수 이전 버전과의 호환성, 기본 ESModule로 NPM 패키지를 게시 이전을위한 require방법.

비동기 가져 오기를 사용할 위치에 대한 자세한 내용은 https://www.youtube.com/watch?v=bb6RCrDaxhw를 참조하십시오.


1
그렇다면 동기화가 필요한가요?
baklazan

1
사실 말할 수 있습니다!
Zaveri를 만나보십시오.

15

알아야 할 가장 중요한 것은 ES6 모듈은 공식 표준이지만 CommonJS (Node.js) 모듈은 그렇지 않다는 것입니다.

2019 년에는 ES6 모듈이 브라우저의 84 % 에서 지원됩니다. Node.js는이를 --experimental-modules 플래그 뒤에 배치하지만 esm 이라는 편리한 노드 패키지도있어 통합이 원활합니다.

이러한 모듈 시스템간에 발생할 수있는 또 다른 문제는 코드 위치입니다. Node.js는 소스가 node_modules디렉토리에 유지되는 반면 대부분의 ES6 모듈은 플랫 디렉토리 구조로 배포 된다고 가정합니다 . 이것들은 조정하기 쉽지 않지만 package.json설치 전후 스크립트로 파일을 해킹하여 수행 할 수 있습니다 . 다음은 예입니다 동형 모듈기사 어떻게 작동하는지 설명은.


8

가져 오기를 사용하여 필요한 메소드를 가져올 수 있기 때문에 개인적으로 가져 오기를 사용합니다.

import {foo, bar} from "dep";

파일 이름 : dep.js

export foo function(){};
export const bar = 22

크레딧은 Paul Shan에게갑니다. 더 많은 정보 .


1
좋은 선택입니다! 또한 npm 패키지를 이전 require방식 과의 하위 호환성으로 기본 ESModule로 게시 하고 있습니까?
Dan Dascalescu

6
당신은 require와 똑같이 할 수 있습니다!
스위스

4
const {a,b} = require('module.js'); 수출 a도 가능합니다b
BananaAcid

module.exports = { a: ()={}, b: 22 }- @BananaAcid respones의 두 번째 부분
세스 McClaine

7

현재 ES6 가져 오기에서 내보내기는 항상 CommonJS로 컴파일 되므로 하나를 사용하면 이점없습니다 . ES6의 사용이 권장되지만 브라우저에서 기본 지원을 릴리스 할 때 유리해야합니다. 그 이유는 CommonJS를 사용하면 하나의 파일에서 부분을 가져올 수 있지만 모든 파일이 필요합니다.

ES6 → import, export default, export

커먼 JS → require, module.exports, exports.foo

아래는 그것들의 일반적인 사용법입니다.

ES6 내보내기 기본값

// hello.js
function hello() {
  return 'hello'
}
export default hello

// app.js
import hello from './hello'
hello() // returns hello

ES6 다중 내보내기 및 다중 가져 오기

// hello.js
function hello1() {
  return 'hello1'
}
function hello2() {
  return 'hello2'
}
export { hello1, hello2 }

// app.js
import { hello1, hello2 } from './hello'
hello1()  // returns hello1
hello2()  // returns hello2

CommonJS module.exports

// hello.js
function hello() {
  return 'hello'
}
module.exports = hello

// app.js
const hello = require('./hello')
hello()   // returns hello

CommonJS 모듈. 여러 내보내기

// hello.js
function hello1() {
  return 'hello1'
}
function hello2() {
  return 'hello2'
}
module.exports = {
  hello1,
  hello2
}

// app.js
const hello = require('./hello')
hello.hello1()   // returns hello1
hello.hello2()   // returns hello2

0

왜 (아마도 최적화-게으른로드?) 그런 식으로 작동하는지 확실하지 않지만 import가져온 모듈을 사용하지 않으면 코드를 구문 분석하지 못할 수 있습니다.
어떤 경우에는 예상대로 작동하지 않을 수 있습니다.

샘플 종속성으로 Foo 클래스를 싫어하십시오.

foo.ts

export default class Foo {}
console.log('Foo loaded');

예를 들면 다음과 같습니다.

index.ts

import Foo from './foo'
// prints nothing

index.ts

const Foo = require('./foo').default;
// prints "Foo loaded"

index.ts

(async () => {
    const FooPack = await import('./foo');
    // prints "Foo loaded"
})();

반면에 :

index.ts

import Foo from './foo'
typeof Foo; // any use case
// prints "Foo loaded"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.