Bagaimana saya bisa mengimpor modul ES6 secara kondisional?

194

Saya perlu melakukan sesuatu seperti:

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

Kode di atas tidak dikompilasi; itu melempar SyntaxError: ... 'import' and 'export' may only appear at the top level.

Saya mencoba menggunakan System.importseperti yang ditunjukkan di sini , tetapi saya tidak tahu dari mana Systemasalnya. Apakah ini proposal ES6 yang akhirnya tidak diterima? Tautan ke "API terprogram" dari artikel itu mencampakkan saya ke laman dokumen yang tidak digunakan lagi .

ericsoco
sumber
Cukup impor secara normal. Modul Anda membutuhkannya.
Andy
Saya tidak benar-benar melihat alasan mengapa Anda tidak akan hanya mengimpor terlepas dari kondisinya. Ini tidak seperti ada semacam overhead. Dalam beberapa skenario Anda memerlukan file, sehingga tidak seperti ada kasus di mana ia dapat sepenuhnya dilewati. Dalam hal ini, impor saja tanpa syarat.
Terima kasih
8
Kasus penggunaan saya: Saya ingin membuatnya mudah memiliki ketergantungan opsional. Jika dep tidak diperlukan, pengguna menghapusnya dari package.json; saya gulpfilekemudian memeriksa apakah ketergantungan itu ada sebelum melakukan beberapa langkah membangun.
ericsoco
1
Kasus penggunaan lain: untuk tujuan pengujian. Saya menggunakan webpackdan babeluntuk transpile es6 ke es5. Proyek seperti webpack-rewiredan sejenisnya tidak membantu di sini - github.com/jhnns/rewire-webpack/issues/12 . Salah satu cara untuk menetapkan uji ganda ATAU untuk menghapus dependensi yang bermasalah bisa berupa impor bersyarat.
Amio.io
3
+1. Mampu menggunakan modul di beberapa lingkungan di mana dependensi mungkin atau mungkin tidak berfungsi sangat penting, terutama ketika modul dapat merujuk pada dependensi yang hanya akan bekerja di browser (misalnya di mana webpackdigunakan untuk mengubah stylesheet ke dalam modul yang memasukkan gaya yang relevan ke dalam DOM ketika mereka diimpor) tetapi modul juga perlu dijalankan di luar browser (misalnya untuk pengujian unit).
Jules

Jawaban:

146

Kami memiliki proposal impor dinamis sekarang dengan ECMA. Ini dalam tahap 3. Ini juga tersedia sebagai babel-preset .

Mengikuti adalah cara untuk melakukan rendering bersyarat sesuai kasus Anda.

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

Ini pada dasarnya mengembalikan janji. Resolusi janji diharapkan memiliki modul. Proposal juga memiliki fitur lain seperti beberapa impor dinamis, impor default, impor file js dll. Anda dapat menemukan informasi lebih lanjut tentang impor dinamis di sini .

kode sandi
sumber
13
Akhirnya, jawaban ES6 yang nyata! Terima kasih @ thecodejack. Sebenarnya pada tahap 3 saat penulisan ini, menurut artikel itu sekarang.
ericsoco
5
atau jika Anda baru saja menyebutkan ekspor, Anda dapat merusak:if (condition) { import('something') .then(({ somethingExported }) => { console.log(somethingExported); }); }
ivn
4
di Firefox dan saat berjalan npm run buildsaya masih mendapatkan kesalahan:SyntaxError: ... 'import' and 'export' may only appear at the top level
ste
1
@stackjlei: Fitur ini belum menjadi bagian dari standar JavaScript, ini hanya proposal tahap 3! Namun itu sudah diterapkan di banyak browser baru, lihat caniuse.com/#feat=es6-module-dynamic-import .
Konrad Höffner
1
Fungsi impor dinamis bersyarat tidak memiliki kemampuan berbutir halus untuk mengimpor hanya elemen tertentu yang "impor X dari Y". Faktanya, kemampuan berbutir halus dapat menjadi lebih penting dalam pemuatan dinamis (sebagai lawan bundel praproses)
Craig Hicks
102

Jika mau, Anda bisa menggunakan persyaratan. Ini adalah cara untuk memiliki pernyataan persyaratan bersyarat.

let something = null;
let other = null;

if (condition) {
    something = require('something');
    other = require('something').other;
}
if (something && other) {
    something.doStuff();
    other.doOtherStuff();
}
BaptWaels
sumber
1
Saya pikir sesuatu dan variabel lain dideklarasikan menggunakan const yang merupakan blok scoped, jadi kondisi kedua jika akan melempar sesuatu tidak didefinisikan
Mohammed Essehemy
Akan lebih baik menggunakan membiarkan dan mendeklarasikan dua variabel di luar blok daripada menggunakan 'var' dan menghindari ruang lingkup blok sama sekali.
Vorcan
Apakah mengangkat mempengaruhi sesuatu dalam kasus ini? Saya mengalami beberapa masalah ketika mengangkat berarti saya mengimpor perpustakaan secara tidak terduga ketika mengikuti pola yang dekat dengan ini jika memori berfungsi.
Thomas
11
Perlu ditunjukkan bahwa require()itu bukan bagian dari JavaScript standar - ini adalah fungsi bawaan di Node.js, jadi hanya berguna di lingkungan itu. OP tidak memberikan indikasi bekerja dengan Node.js.
Velojet
56

Anda tidak dapat mengimpor secara kondisional, tetapi Anda dapat melakukan yang sebaliknya: mengekspor sesuatu secara kondisional. Itu tergantung pada kasus penggunaan Anda, jadi penyelesaian ini mungkin bukan untuk Anda.

Anda dapat melakukan:

api.js

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

const exportedAPI = shouldUseMock ? mockAPI : realAPI
export default exportedAPI

apiConsumer.js

import API from './api'
...

Saya menggunakannya untuk mengejek lib analytics seperti mixpanel, dll ... karena saya tidak dapat memiliki beberapa build atau frontend kami saat ini. Bukan yang paling elegan, tetapi bekerja. Saya hanya punya beberapa 'jika' di sana-sini tergantung pada lingkungan karena dalam kasus mixpanel, perlu inisialisasi.

Kev
sumber
40
Solusi ini menyebabkan modul yang tidak diinginkan dimuat, jadi bukan solusi yang optimal, saya pikir.
ismailarilik
5
Seperti yang dinyatakan dalam jawaban, ini adalah solusi. Pada saat itu, sama sekali tidak ada solusi. Impor ES6 tidak dinamis, ini karena desain. Proposal fungsi impor dinamis ES6, yang dijelaskan dalam jawaban yang saat ini diterima, dapat melakukannya. JS berevolusi :)
Kev
9

Sepertinya jawabannya adalah, sampai sekarang, Anda tidak bisa.

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

Saya pikir maksudnya adalah untuk memungkinkan analisis statis sebanyak mungkin, dan modul yang diimpor dengan syarat mematahkannya. Juga layak disebutkan - Saya menggunakan Babel , dan saya rasa itu Systemtidak didukung oleh Babel karena API pemuat modul tidak menjadi standar ES6.

ericsoco
sumber
@ Feliksling membuat ini jawabannya sendiri dan saya akan dengan senang hati menerimanya!
ericsoco
4

require()adalah cara untuk mengimpor beberapa modul pada waktu berjalan dan sama-sama memenuhi syarat untuk analisis statis seperti importjika digunakan dengan jalur literal string. Ini diperlukan oleh bundler untuk memilih dependensi untuk bundel.

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

Untuk resolusi modul dinamis dengan dukungan analisis statis lengkap, modul indeks pertama dalam pengindeks (index.js) dan pengindeks impor dalam modul host.

// 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]);
Shoaib Nawaz
sumber
7
Perlu ditunjukkan bahwa require()itu bukan bagian dari JavaScript standar - ini adalah fungsi bawaan di Node.js, jadi hanya berguna di lingkungan itu. OP tidak memberikan indikasi bekerja dengan Node.js.
Velojet
2

Perbedaan penting jika Anda menggunakan mode impor dinamis Webpack 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(...);
}
Solo
sumber
Tapi importmengembalikan janji.
newguy
0

mengaburkannya dalam eval bekerja untuk saya, menyembunyikannya dari analisa statis ...

if (typeof __CLI__ !== 'undefined') {
  eval("require('fs');")
}
Chris Marstall
sumber
3
Adakah yang bisa menjelaskan mengapa jawaban ini diturunkan? Apakah ada kelemahan nyata atau itu hanya reaksi negatif otomatis terhadap kata kunci jahat 'eval'?
Yuri Gor
3
Downvote otomatis untuk menggunakan kata kunci eval mengerikan. Menjauhlah
Tormod Haugene
1
Bisakah Anda menjelaskan apa yang sebenarnya salah dengan penggunaan di evalsini, @TormodHaugene?
Adam Barnes
MDN meringkas beberapa alasan mengapa evaltidak digunakan . Secara umum: jika Anda merasa perlu menggunakan eval, Anda mungkin melakukan kesalahan dan harus mengambil langkah mundur untuk mempertimbangkan alternatif Anda. Mungkin ada beberapa skenario di mana penggunaannya evalbenar, tetapi Anda kemungkinan besar belum menemukan salah satu dari situasi itu.
Tormod Haugene
5
Perlu ditunjukkan bahwa require()itu bukan bagian dari JavaScript standar - ini adalah fungsi bawaan di Node.js, jadi hanya berguna di lingkungan itu. OP tidak memberikan indikasi bekerja dengan Node.js.
Velojet
0

Saya dapat mencapai ini menggunakan fungsi yang dipanggil langsung dan memerlukan pernyataan.

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

if(something) {
  something.doStuff();
}
bradley2w1dl
sumber
5
Perlu ditunjukkan bahwa require()itu bukan bagian dari JavaScript standar - ini adalah fungsi bawaan di Node.js, jadi hanya berguna di lingkungan itu. OP tidak memberikan indikasi bekerja dengan Node.js.
Velojet
0

Impor bersyarat juga dapat dicapai dengan terner dan require()s:

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

Contoh ini diambil dari ES Lint global-membutuhkan dokumen: https://eslint.org/docs/rules/global-require

Elliot Ledger
sumber
5
Perlu ditunjukkan bahwa require()itu bukan bagian dari JavaScript standar - ini adalah fungsi bawaan di Node.js, jadi hanya berguna di lingkungan itu. OP tidak memberikan indikasi bekerja dengan Node.js.
Velojet
0

Tidak bisa!

Namun, setelah menabrak masalah itu harus membuat Anda memikirkan kembali bagaimana Anda mengatur kode Anda.

Sebelum modul ES6, kami memiliki modul CommonJS yang menggunakan sintaks memerlukan (). Modul-modul ini "dinamis", artinya kita dapat mengimpor modul baru berdasarkan kondisi dalam kode kita. - sumber: https://bitsofco.de/what-is-tree-shaking/

Saya kira salah satu alasan mereka menjatuhkan dukungan pada ES6 dan seterusnya adalah fakta bahwa kompilasi akan sangat sulit atau tidak mungkin.

Aldee
sumber