Bir ES6 modülünü koşullu olarak nasıl alabilirim?


194

Gibi bir şey yapmam gerekiyor:

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

Yukarıdaki kod derlenmez; atar SyntaxError: ... 'import' and 'export' may only appear at the top level.

BuradaSystem.import gösterildiği gibi kullanmayı denedim ama nereden geldiğini bilmiyorum . Kabul edilmeyen bir ES6 teklifi mi? Bu makaledeki "programlı API" bağlantısı beni kullanımdan kaldırılmış dokümanlar sayfasına götürüyor .System


Sadece normal şekilde içe aktarın. Modülünüzün ne olursa olsun buna ihtiyacı vardır.
Andy

Durumdan bağımsız olarak sadece ithalat yapmamanız için herhangi bir neden göremiyorum. Bir çeşit tepegöz yok gibi değil. Bazı senaryoda dosyaya ihtiyacınız vardır, bu yüzden tamamen atlanabileceği bir durum yoktur. Bu durumda, koşulsuz olarak içe aktarın.
Teşekkür ederim

8
Kullanım durumum: İsteğe bağlı bir bağımlılığa sahip olmayı kolaylaştırmak istiyorum. Dep gerekli değilse, kullanıcı onu kaldırır package.json; Benim gulpfileunsurları kontrol eder bağımlılık bazı yapı adımları gerçekleştirmeden önce varsa.
ericsoco

1
Başka bir kullanım örneği: test amaçlı. Ben kullanıyorum webpackve babeltranspile ES6 için ES5 için. Benzeri webpack-rewireve benzeri projeler burada yardımcı değildir - github.com/jhnns/rewire-webpack/issues/12 . Testi iki katına çıkarmanın VEYA sorunlu bağımlılıkları kaldırmanın bir yolu koşullu içe aktarma olabilir.
Amio.io

3
+1. Bir modülün bağımlılıkların çalışabileceği veya çalışmayabileceği çoklu ortamlarda kullanılabilmesi, özellikle de modüller yalnızca tarayıcıda çalışacak bağımlılıklara atıfta bulunabiliyorsa (örneğin webpack, stil sayfalarını ilgili stilleri DOM'lar içe aktarıldıklarında), ancak modülün tarayıcının dışında da çalışması gerekir (örn. Birim testi için).
Jules

Yanıtlar:


144

ECMA ile dinamik ithalat teklifimiz var. Bu 3. aşamadadır. Babil önayarı olarak da mevcuttur .

Aşağıda, durumunuza göre koşullu oluşturma yapmanın yolu verilmiştir.

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

Bu temelde bir söz veriyor. Sözün çözülmesi modülün olması bekleniyor. Teklif ayrıca, birden çok dinamik içe aktarma, varsayılan içe aktarma, js dosyası içe aktarma vb. Gibi başka özelliklere de sahiptir. Dinamik içe aktarma hakkında daha fazla bilgiyi burada bulabilirsiniz .


13
Son olarak, gerçek bir ES6 cevabı! Teşekkürler @thecodejack. Aslında bu makaleye göre bu yazının 3. evresinde.
ericsoco

5
ya da sadece ihracat ismini if (condition) { import('something') .then(({ somethingExported }) => { console.log(somethingExported); }); }
verdiyseniz, aşağıdakileri yapılandırabilirsiniz

4
Firefox ve çalışırken npm run buildhala hatayı alıyorum:SyntaxError: ... 'import' and 'export' may only appear at the top level
ste

1
@stackjlei: Bu özellik henüz JavaScript standardının bir parçası değil, yalnızca 3. aşama bir teklif! Bununla birlikte, daha yeni tarayıcılarda zaten uygulanmaktadır, bkz. Caniuse.com/#feat=es6-module-dynamic-import .
Konrad Höffner

1
Bu koşullu dinamik içe aktarma işlevi, yalnızca "X'den Y'yi içe aktar" öğesinin sahip olduğu belirli öğeleri içe aktarma yeteneğine sahip değildir. Aslında, ince taneli yetenek dinamik yüklemede daha da önemli olabilir (önişlemiş paketlemenin aksine)
Craig Hicks

102

İsterseniz, Require kullanabilirsiniz. Bu, koşullu bir talep ifadesine sahip olmanın bir yoludur.

let something = null;
let other = null;

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

1
Sanırım bir şey ve diğer değişkenler blok kapsamı olan const kullanılarak çözülür, bu yüzden ikinci koşul bir şey tanımlanmayacaksa, tanımlanır
Mohammed Essehemy

'Var' kullanmak ve blok kapsamından tamamen kaçınmak yerine iki değişkenin blok dışında bildirilmesine izin vermek daha iyi olurdu.
Vorcan

Kaldırma bu durumda bir şeyi etkiler mi? Kaldırma, bellek hizmet veriyorsa buna yakın bir desen izlerken beklenmedik bir şekilde bir kütüphane ithal ettiğim anlamına gelen bazı sorunlarla karşılaştım.
Thomas

11
require()Standart JavaScript'in bir parçası olmadığı belirtilmelidir - Node.js'de yerleşik bir işlevdir, bu yüzden sadece bu ortamda yararlıdır. OP, Node.js ile çalıştığına dair hiçbir belirti vermez.
Velojet

55

Koşullu olarak içe aktaramazsınız, ancak tam tersini yapabilirsiniz: bir şeyi koşullu olarak dışa aktarın. Kullanım durumunuza bağlıdır, bu nedenle bu geçici çözüm sizin için olmayabilir.

Yapabilirsin:

api.js

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

const exportedAPI = shouldUseMock ? mockAPI : realAPI
export default exportedAPI

apiConsumer.js

import API from './api'
...

Bunu mixpanel gibi analitik kütüphaneleri alay etmek için kullanıyorum. En zarif değil, ama çalışıyor. Ortama bağlı olarak burada ve orada birkaç 'if' var, çünkü mixpanel durumunda, başlatılması gerekiyor.


40
Bu çözüm istenmeyen modüllerin yüklenmesine neden oluyor, bu yüzden optimal bir çözüm değil bence.
ismailarilik

5
Yanıtta belirtildiği gibi, bu bir çözümdür. O zaman, basit bir çözüm yoktu. ES6 ithalatı dinamik değildir, bu tasarım gereğidir. Şu anda kabul edilen cevapta açıklanan ES6 dinamik içe aktarma işlevi teklifi bunu yapabilir. JS evrim geçiriyor :)
Kev

9

Görünüşe göre cevap şu an için yapamıyorsunuz.

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

Niyetin olabildiğince statik analizi mümkün kılmak olduğunu düşünüyorum ve şartlı olarak içe aktarılan modüller bunu kırıyor. Ayrıca bahsetmeye değer - Babel kullanıyorum Systemve modül yükleyici API bir ES6 standardı olmadığından Babel tarafından desteklenmediğini tahmin ediyorum .


@FelixKling bunu kendi cevabı yapar ve ben de memnuniyetle kabul edeceğim!
ericsoco

4

require()bir modülü çalışma zamanında içe aktarmanın bir yoludur ve importdizgi değişmez yollarında kullanıldığında olduğu gibi statik analiz için de eşittir . Bu, paketleyici tarafından paket için bağımlılıkları seçmesi için gereklidir.

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

Tam statik analiz desteğiyle dinamik modül çözünürlüğü için, önce bir dizinleyicide (index.js) dizin modüllerini ve ana makine modülünde dizinleyiciyi içe aktarın.

// 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()Standart JavaScript'in bir parçası olmadığı belirtilmelidir - Node.js'de yerleşik bir işlevdir, bu yüzden sadece bu ortamda yararlıdır. OP, Node.js ile çalıştığına dair hiçbir belirti vermez.
Velojet

2

Dinamik içe aktarma Webpack modunu kullanıyorsanız önemli fark 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(...);
}

Ama importbir söz veriyor.
newguy

0

benim için çalışan bir değerlendirmede gizlemek, statik analizörden gizlemek ...

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

3
Herkes bu cevabın neden reddedildiğini açıklayabilir mi? Herhangi bir gerçek dezavantajı var mı veya sadece 'eval' kötü anahtar kelimesine otomatik olumsuz tepki miydi?
Yuri Gor

3
İğrenç eval anahtar sözcüğünü kullanmak için otomatik indirme. Uzak dur.
Tormod Haugene

1
evalBurada kullanımda neyin yanlış olduğunu açıklayabilir misin @TormodHaugene?
Adam Barnes

MDN evalkullanılmaması gereken birkaç nedeni özetlemektedir . Genel olarak: kullanma gereğini evalbulursanız, muhtemelen yanlış yapıyorsunuz ve alternatiflerinizi düşünmek için bir adım geri atmalısınız. Muhtemelen evalkullanımın doğru olduğu bazı senaryolar vardır , ancak büyük olasılıkla bu durumlardan biriyle karşılaşmadınız.
Tormod Haugene

5
require()Standart JavaScript'in bir parçası olmadığı belirtilmelidir - Node.js'de yerleşik bir işlevdir, bu yüzden sadece bu ortamda yararlıdır. OP, Node.js ile çalıştığına dair hiçbir belirti vermez.
Velojet

0

Hemen çağrılan bir işlev kullanarak bunu başardım ve ifade gerektirir.

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

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

5
require()Standart JavaScript'in bir parçası olmadığı belirtilmelidir - Node.js'de yerleşik bir işlevdir, bu yüzden sadece bu ortamda yararlıdır. OP, Node.js ile çalıştığına dair hiçbir belirti vermez.
Velojet

0

Koşullu ithalat bir üçlü ve require()s:

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

Bu örnek ES Lint küresel gereksinim belgelerinden alınmıştır: https://eslint.org/docs/rules/global-require


5
require()Standart JavaScript'in bir parçası olmadığı belirtilmelidir - Node.js'de yerleşik bir işlevdir, bu yüzden sadece bu ortamda yararlıdır. OP, Node.js ile çalıştığına dair hiçbir belirti vermez.
Velojet


0

Hayır, yapamazsınız!

Ancak, bu sorunla karşılaşmanız, kodunuzu nasıl düzenlediğiniz konusunda yeniden düşünmenizi sağlayacaktır.

ES6 modüllerinden önce, requir () sözdizimini kullanan CommonJS modüllerine sahiptik. Bu modüller "dinamik" dir, yani kodumuzdaki koşullara göre yeni modülleri içe aktarabiliriz. - kaynak: https://bitsofco.de/what-is-tree-shaking/

Sanırım ES6'ya desteğin düşmesinin nedenlerinden biri, bunu derlemenin çok zor veya imkansız olması.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.