ES6 모듈을 조건부로 가져 오려면 어떻게해야합니까?


194

나는 다음과 같은 일을해야합니다 :

if (condition) {
    import something from 'something';
}
// ...
if (something) {
    something.doStuff();
}

위의 코드는 컴파일되지 않습니다. 던졌습니다 SyntaxError: ... 'import' and 'export' may only appear at the top level.

여기System.import표시된대로 사용하려고했지만 어디서 왔는지 모르겠습니다 . ES6 제안은 결국 받아 들여지지 않았습니까? 이 기사의 "프로그래밍 API"링크는 더 이상 사용되지 않는 문서 페이지로 덤프 합니다 .System


정상적으로 가져 오십시오. 모듈에 관계없이 필요합니다.
Andy

나는 당신이 조건에 관계없이 수입하지 않는 이유를 실제로 보지 못합니다. 일종의 오버 헤드가있는 것과는 다릅니다. 일부 시나리오에서는 파일이 필요하므로 완전히 건너 뛸 수있는 경우가 아닙니다. 이 경우 무조건 가져 오기만하면됩니다.
감사합니다

8
내 유스 케이스 : 선택적 종속성을 쉽게 갖기를 원합니다. 뎁이 필요하지 않으면, 사용자는 뎁을 제거한다 package.json; 내 gulpfile다음 검사는 종속성 일부 빌드 단계를 수행하기 전에 존재하는 경우.
ericsoco

1
다른 사용 사례 : 테스트 목적. es6을 es5로 사용 webpack하고 babel변환합니다. github.com/jhnns/rewire-webpack/issues/12webpack-rewire 와 같은 프로젝트 는 도움이되지 않습니다 . 테스트를 두 배로 설정하거나 문제가있는 종속성을 제거하는 한 가지 방법은 조건부 가져 오기 일 수 있습니다.
Amio.io

3
+1. 종속성이 작동하거나 작동하지 않을 수있는 여러 환경에서 모듈을 사용할 수있는 것은 특히 모듈이 브라우저에서만 작동하는 종속성을 참조 할 수있는 경우 (예 : webpack스타일 시트를 관련 스타일을 삽입하는 모듈로 변환하는 데 사용되는 경우) DOM을 가져올 때) 그러나 모듈은 브라우저 외부에서 실행해야합니다 (예 : 단위 테스트).
Jules

답변:


144

이제 ECMA와 함께 동적 수입 제안이 있습니다. 3 단계 입니다. babel-preset 으로도 제공됩니다 .

다음은 귀하의 경우에 따라 조건부 렌더링을 수행하는 방법입니다.

if (condition) {
    import('something')
    .then((something) => {
       console.log(something.something);
    });
}

이것은 기본적으로 약속을 반환합니다. 약속의 해결은 모듈을 가질 것으로 예상됩니다. 제안서에는 여러 동적 가져 오기, 기본 가져 오기, js 파일 가져 오기 등과 같은 다른 기능도 있습니다 . 동적 가져 오기 에 대한 자세한 정보는 여기를 참조하십시오 .


13
마지막으로 실제 ES6 답변! @thecodejack에게 감사합니다. 이 기사에 따르면 실제로이 글을 쓰는 시점에서 3 단계에 있습니다.
ericsoco

5
또는 방금 수출이라는 이름을 지정한 경우 다음과 같이 구조를 해제 할 수 있습니다.if (condition) { import('something') .then(({ somethingExported }) => { console.log(somethingExported); }); }
ivn

4
Firefox에서 실행 중에도 npm run build여전히 오류가 발생합니다.SyntaxError: ... 'import' and 'export' may only appear at the top level
ste

1
@stackjlei :이 기능은 아직 JavaScript 표준의 일부가 아니며 3 단계 제안 일뿐입니다! 그러나 많은 최신 브라우저에서 이미 구현되어 있습니다 ( caniuse.com/#feat=es6-module-dynamic-import 참조) .
Konrad Höffner

1
이 조건부 동적 가져 오기 기능에는 "Y에서 X 가져 오기"가있는 특정 요소 만 가져 오는 미세한 기능이 없습니다. 사실 (전처리 번들링과 달리) 동적 로딩에서 미세 입자 능력이 훨씬 더 중요 할 수 있습니다.
Craig Hicks

102

원하는 경우 require를 사용할 수 있습니다. 이것은 조건부 require 문을 갖는 방법입니다.

let something = null;
let other = null;

if (condition) {
    something = require('something');
    other = require('something').other;
}
if (something && other) {
    something.doStuff();
    other.doOtherStuff();
}

1
블록 범위가 지정된 const를 사용하여 무언가와 다른 변수를 선언한다고 생각합니다. 두 번째 조건이 정의되지 않은 것을 던질 경우
Mohammed Essehemy

'var'을 사용하지 않고 블록 범위를 피하는 대신 블록 외부에 두 변수를 선언하고 선언하는 것이 좋습니다.
Vorcan

이 경우 게양이 어떤 영향을 미칩니 까? 나는 게양이 메모리에 도움이된다면 이것에 가까운 패턴을 따를 때 예기치 않게 라이브러리를 가져 왔음을 의미하는 몇 가지 문제에 부딪쳤다.
Thomas

11
require()표준 JavaScript의 일부가 아니라는 점을 지적해야 합니다. Node.js의 내장 함수이므로 해당 환경에서만 유용합니다. OP는 Node.js 작업에 대한 표시를 제공하지 않습니다.
Velojet

55

조건부로 가져올 수는 없지만 반대로 할 수 있습니다. 조건부로 무언가를 내 보냅니다. 사용 사례에 따라 다르므로이 해결 방법이 적합하지 않을 수 있습니다.

넌 할 수있어:

api.js

import mockAPI from './mockAPI'
import realAPI from './realAPI'

const exportedAPI = shouldUseMock ? mockAPI : realAPI
export default exportedAPI

apiConsumer.js

import API from './api'
...

나는 현재 다중 빌드 또는 프론트 엔드를 가질 수 없기 때문에 mixpanel 등과 같은 분석 라이브러리를 조롱하는 데 사용합니다. 가장 우아하지는 않지만 작동합니다. mixpanel의 경우 초기화가 필요하기 때문에 환경에 따라 여기에 몇 가지 'if'가 있습니다.


40
이 솔루션은 원하지 않는 모듈이로드되도록하므로 최적의 솔루션은 아닙니다.
ismailarilik

5
답변에서 언급했듯이 이것은 해결 방법입니다. 당시에는 해결책이 없었습니다. ES6 가져 오기는 동적이 아니며 의도적으로 설계된 것입니다. 현재 허용되는 답변에 설명 된 ES6 동적 가져 오기 기능 제안이 가능합니다. JS는 진화하고 있습니다 :)
Kev

9

대답은 현재로서는 할 수없는 것 같습니다.

http://exploringjs.com/es6/ch_modules.html#sec_module-loader-api

정적 분석을 가능한 한 많이하는 것이 목적이며 조건부로 가져온 모듈이이를 깨뜨립니다. 또한 언급 할만큼 가치 - 내가 사용하고 바벨을 , 나는 그 추측하고있어 System모듈 로더 API는 ES6 표준이 없었기 때문에 바벨을 지원하지 않습니다.


@FelixKling이 답변을 직접 작성하면 행복하게 받아 들일 것입니다!
ericsoco

4

require()런타임에 일부 모듈을 가져 오는 방법 import이며 문자열 리터럴 경로와 함께 사용하는 경우와 같이 정적 분석에 동일하게 적합 합니다. 번 들러는 번들에 대한 종속성을 선택해야합니다.

const defaultOne = require('path/to/component').default;
const NamedOne = require('path/to/component').theName;

완전한 정적 분석을 지원하는 동적 모듈 확인을 위해 인덱서 (index.js)의 첫 번째 인덱스 모듈과 호스트 모듈의 인덱서 가져 오기.

// index.js
export { default as ModuleOne } from 'path/to/module/one';
export { default as ModuleTwo } from 'path/to/module/two';
export { SomeNamedModule } from 'path/to/named/module';

// host.js
import * as indexer from 'index';
const moduleName = 'ModuleOne';
const Module = require(indexer[moduleName]);

7
require()표준 JavaScript의 일부가 아니라는 점을 지적해야 합니다. Node.js의 내장 함수이므로 해당 환경에서만 유용합니다. OP는 Node.js 작업에 대한 표시를 제공하지 않습니다.
Velojet

2

동적 가져 오기 웹팩 모드를 사용하는 경우 중요한 차이점 eager:

if (normalCondition) {
  // this will be included to bundle, whether you use it or not
  import(...);
}

if (process.env.SOMETHING === 'true') {
  // this will not be included to bundle, if SOMETHING is not 'true'
  import(...);
}

그러나 import약속을 돌려줍니다.
newguy

0

평가판에서 그것을 가리면 정적 분석기에서 숨겨져 나를 위해 일했습니다 ...

if (typeof __CLI__ !== 'undefined') {
  eval("require('fs');")
}

3
왜이 답변이 다운 보트되었는지 설명해 줄 수 있습니까? 실제 단점이 있거나 악의적 인 키워드 'eval'에 자동으로 부정적인 반응을 보였습니까?
유리 고르

3
hideous eval 키워드를 사용하기위한 자동 다운 보트. 물러서
Tormod Haugene

1
eval@TormodHaugene을 사용하면 실제로 무엇이 잘못되었는지 설명 할 수 있습니까 ?
Adam Barnes

MDN eval은 사용하지 말아야 할 몇 가지 이유를 요약합니다 . 일반적으로 : 사용할 필요가 eval있는 경우 잘못 사용하고있을 수 있으므로 대안을 고려하기 위해 한 발짝 물러서야합니다. 사용 eval이 올바른 시나리오가있을 수 있지만 이러한 상황 중 하나가 발생하지 않은 것 같습니다.
Tormod Haugene

5
require()표준 JavaScript의 일부가 아니라는 점을 지적해야 합니다. Node.js의 내장 함수이므로 해당 환경에서만 유용합니다. OP는 Node.js 작업에 대한 표시를 제공하지 않습니다.
Velojet

0

즉시 호출 된 함수를 사용 하여이 작업을 수행 할 수 있었고 명령문을 요구했습니다.

const something = (() => (
  condition ? require('something') : null
))();

if(something) {
  something.doStuff();
}

5
require()표준 JavaScript의 일부가 아니라는 점을 지적해야 합니다. Node.js의 내장 함수이므로 해당 환경에서만 유용합니다. OP는 Node.js 작업에 대한 표시를 제공하지 않습니다.
Velojet

0

조건부 수입은 3 항과 require()s 로도 달성 할 수 있습니다 .

const logger = DEBUG ? require('dev-logger') : require('logger');

이 예제는 ES Lint 글로벌 필수 문서에서 가져온 것입니다 : https://eslint.org/docs/rules/global-require


5
require()표준 JavaScript의 일부가 아니라는 점을 지적해야 합니다. Node.js의 내장 함수이므로 해당 환경에서만 유용합니다. OP는 Node.js 작업에 대한 표시를 제공하지 않습니다.
Velojet


0

아니, 안돼!

그러나이 문제에 부딪 치면 코드 구성 방법을 다시 생각해야합니다.

ES6 모듈 이전에는 require () 구문을 사용하는 CommonJS 모듈이있었습니다. 이러한 모듈은 "동적"이므로 코드의 조건에 따라 새 모듈을 가져올 수 있습니다. -출처 : https://bitsofco.de/what-is-tree-shaking/

ES6에서 지원을 중단 한 이유 중 하나는 컴파일이 매우 어렵거나 불가능하다는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.