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.