Node.js'de ES6 değişken içe aktarma adı?


108

ES6 içe aktarımını kullanırken değişken adı sağlayan modüle bir şey aktarmak mümkün müdür?

Yani bir yapılandırmada sağlanan değerlere bağlı olarak bir çalışma zamanında bazı modülleri içe aktarmak istiyorum:

import something from './utils/' + variableName;

1
@Bigood evet, derleyici fırlar ve Webstorm da bir hata gösterir
Vytautas Butkus

Yanıtlar:


67

Açıklamayla değil import. importveexport statik olarak analiz edilebilecek şekilde tanımlanırlar, bu nedenle çalışma zamanı bilgilerine bağlı olamazlar.

Yükleyici API'sini (polyfill) arıyorsunuz , ancak spesifikasyonun durumu hakkında biraz emin değilim:

System.import('./utils/' + variableName).then(function(m) {
  console.log(m);
});

3
Sisteme "ihtiyaç duymam" gerekir mi? Küresel bir kapsamda değil .. Ps babel js kullanıyorum
Vytautas Butkus

Henüz AFAIK hiçbir yerde uygulanmadı. Çoklu dolguyu bağlantıdan kullanmanız gerekir.
Felix Kling

1
Biraz önce kontrol ettim, işe yarıyor (dosyayı yüklemeyi deniyor) ama sonra diğer modüllerin yollarını karıştırıyor ... Çok kötü, yerel olarak desteklenmiyor ..
Vytautas Butkus

3
Hala böyle bir mesele var mı? ES6 modüllerini dinamik olarak yüklemem gerekiyor ama başarılı
olamadım

26

Felix'in cevabına ek olarak , buna şu anda ECMAScript 6 dilbilgisi tarafından izin verilmediğini açıkça belirteceğim :

İthalat Beyanı :

  • içe ImportClause FromClause;

  • ModuleSpecifier'ı içe aktarın;

FromClause :

  • dan ModuleSpecifier

ModuleSpecifier :

  • StringLiteral

Bir ModuleSpecifier yalnızca olabilir StringLiteral , bir gibi ifade olmayan başka türlü AdditiveExpression .


2
Bunun e-postaları içerecek şekilde genişletilmemesi üzücü const string literal. Statik olarak analiz edilebilirler, değil mi? Bir bağımlılığın yerini yeniden kullanmayı bir olasılık haline getirir. (örneğin bir şablonu içe aktarın ve şablonun hem şablonunu hem de konumunu hazır bulundurun).
nicodemus13

26

Bu aslında dinamik bir içe aktarma olmasa da (örneğin, benim durumumda, aşağıda içe aktardığım tüm dosyalar çalışma zamanında seçilmeden, web paketi tarafından içe aktarılacak ve gruplanacak), bazı durumlarda yardımcı olabilecek kullandığım bir kalıp :

import Template1 from './Template1.js';
import Template2 from './Template2.js';

const templates = {
  Template1,
  Template2
};

export function getTemplate (name) {
  return templates[name];
}

Veya alternatif olarak:

// index.js
export { default as Template1 } from './Template1';
export { default as Template2 } from './Template2';


// OtherComponent.js
import * as templates from './index.js'
...
// handy to be able to fall back to a default!
return templates[name] || templates.Template1;

Varsayılana geri dönebileceğimi sanmıyorum require(), bu da var olmayan bir yapılandırılmış şablon yolunu içe aktarmaya çalışırsam bir hata verir.

Required ve import arasında iyi örnekler ve karşılaştırmalar burada bulunabilir: http://www.2ality.com/2014/09/es6-modules-final.html

@İainastacio'dan yeniden dışa aktarmayla ilgili mükemmel belgeler: http://exploringjs.com/es6/ch_modules.html#sec_all-exporting-styles

Bu yaklaşımla ilgili geri bildirim almakla ilgileniyorum :)


Oyla. "Veya alternatif olarak" yaklaşımını kullandım. Özel yerelleştirme çözümüm için harika çalıştı.
groundh0g


1
Bunu düşünmeliydim. Bir şeyleri nasıl içe aktarıyor olursanız olun (ve hiçbir şey içe aktarmasanız bile) harika çözüm. Adını ya da daha sonra ismini almak istediğiniz öğelerin bir listesi var mı? Onları bir dizi değişmezi yerine bir nesne değişmezine koyun ve nesne sözdiziminin yerel sabit / değişken adlarına göre onları adlandırmasına izin verin. Bunlara tekrar bir liste olarak ihtiyacınız olursa, yapmanız yeterlidir Object.values(templates).
Andrew Koster

15

ES modülleri için dinamik içe aktarma adı verilen yeni bir spesifikasyon var . Temel olarak, sadece ara import('./path/file.js')ve gitmekte fayda var. Fonksiyon, içe aktarma başarılı olursa modül ile çözülen bir söz verir.

async function importModule() {
   try {
      const module = await import('./path/module.js');
   } catch (error) {
      console.error('import failed');
   }
}

Kullanım durumları

Kullanım durumları arasında React, Vue vb. İçin rota tabanlı bileşen içe aktarma ve modülleri geç yükleme yeteneği bulunur çalışma zamanı sırasında gerekli olduklarında .

Daha fazla bilgi

İşte Google Developers hakkında bir açıklama .

Tarayıcı uyumluluğu (Nisan 2020)

MDN'ye göre, mevcut tüm büyük tarayıcılar (IE hariç) tarafından desteklenmektedir ve caniuse.com , küresel pazar payında% 87 destek göstermektedir. Yine IE veya krom olmayan Edge'de destek yok.


düzenlemenden emin misin? teklif, değişken yol içeren bir örneği gösterir: github.com/tc39/proposal-dynamic-import#example
phil294

@Blauhirn öyleydim, ama bağlantınız açıkça bunun bir olasılık olduğunu gösteriyor. Örneğin web paketinin bu ithalatı nasıl çözeceği hakkında hiçbir fikrim olmasa da
Nicolai Schmid

yanılıyorsam düzelt ama webpack bunları işlemez, değil mi? Tarayıcıda "olduğu gibi" çalıştırılmasının dinamik içe aktarmanın amacı olduğunu düşündüm.
phil294

Evet, tarayıcıda olduğu gibi çalıştırabilirsiniz. Ancak webpack, uygulamanızı, örneğin rotalar gibi uygulamanızın farklı bölümleri için birden çok gruba ayırmak için içe aktarmaları otomatik olarak kullanır. Onları her zaman kullanıyorum ve gerçekten yardımcı oluyorlar. Ve "işleme" gittikçe; webpack, babel'i içe aktarmayı geçecek ve bu da özelliği eski tarayıcılar için çoklu dolduracaktır.
Nicolai Schmid

Açıklamak gerekirse: Dinamik ithalat () olacak değişkenlerle çalışmak ve statik analiz olması gerekli değildir (elbette, 'dinamik' bütün mesele bu mu?). Cevabımı gör.
Velojet

6

Node.js'de özellikle ES6 için sorulan soruyu anlıyorum import, ancak aşağıdakiler başkalarının daha genel bir çözüm aramasına yardımcı olabilir:

let variableName = "es5.js";
const something = require(`./utils/${variableName}`);

Bir ES6 modülünü içe aktarıyorsanız ve dışa aktarmaya erişmeniz defaultgerekiyorsa, aşağıdakilerden birini kullanmanız gerekeceğini unutmayın:

let variableName = "es6.js";

// Assigning
const defaultMethod = require(`./utils/${variableName}`).default;

// Accessing
const something = require(`./utils/${variableName}`);
something.default();

Bu yaklaşımla, diğer içe aktarmalarınıza daha fazla sözdizimi aşinalığı ekleyebilecek yok etme özelliğini de kullanabilirsiniz:

// Destructuring 
const { someMethod } = require(`./utils/${variableName}`);    
someMethod();

Ne yazık ki, defaultyıkmanın yanı sıra erişmek istiyorsanız , bunu birkaç adımda gerçekleştirmeniz gerekecek:

// ES6 Syntax
Import defaultMethod, { someMethod } from "const-path.js";

// Destructuring + default assignment
const something = require(`./utils/${variableName}`);

const defaultMethod = something.default;    
const { someMethod, someOtherMethod } = something;

4

bunu yapmak için ES6 olmayan gösterimi kullanabilirsiniz. bu benim için çalıştı:

let myModule = null;
if (needsToLoadModule) {
  myModule = require('my-module').default;
}

3

Bu sözdizimini daha az sevdim ama işe yarıyor:
yazmak yerine

import memberName from "path" + "fileName"; 
// this will not work!, since "path" + "fileName" need to be string literal

şu sözdizimini kullanın:

let memberName = require("path" + "fileName");

1
@UlysseBN Kötü bir şekilde farklı mı? Ya da gerçekten önemli olmayan bir yol?
Sam

@Jacob gerçekten tamamen farklılar, bu yüzden evet, ne yaptığınıza bağlı olarak önemli olabilir. İlk sözdizimi statik olarak değerlendirilirken, ikincisi dinamik olarak değerlendirilir. Örneğin, web paketi kullanıyorsanız, ikincisi ile ağaç sallamayı doğru bir şekilde gerçekleştirmek olmayacaktır. Başka birçok farklılık var, dokümanı okumanızı ve hangisinin sizin için daha uygun olduğunu görmenizi öneririm!
Ulysse BN

@Jacob - Gerçekten önemli değil (çoğu durumda). require()eski sürüm olan dosyaları yüklemek için bir Node.JS yöntemidir. importifadesi, artık resmi dil sözdiziminin bir parçası olan daha yeni sürümdür. Ancak çoğu durumda tarayıcı öncekini kullanacaktır (bilimin arkasında). Require ifadesi ayrıca dosyalarınızı nakde çevirir, bu nedenle bir dosya 2. kez yüklenirse bellekten yüklenir (daha iyi performans). WebPack kullanıyorsanız, içe aktarma yolunun kendine göre avantajları vardır. daha sonra webpack ölü referansları kaldırabilir (bu komut dosyaları istemciye indirilmeyecektir).
Gil Epshtain

1

Dinamik içe aktarma () (Chrome 63+ sürümünde mevcuttur) işinizi yapar. Bunu nasıl yapacağınız aşağıda açıklanmıştır:

let variableName = 'test.js';
let utilsPath = './utils/' + variableName;
import(utilsPath).then((module) => { module.something(); });

0

Böyle yapardım

function load(filePath) {
     return () => System.import(`${filePath}.js`); 
     // Note: Change .js to your file extension
}

let A = load('./utils/' + variableName)

// Now you can use A in your module

0

./utils/test.js

export default () => {
  doSomething...
}

dosyadan ara

const variableName = 'test';
const package = require(`./utils/${variableName}`);
package.default();
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.