ES6: условные и динамические операторы импорта

86

Условный

Возможно ли иметь условные операторы импорта, как показано ниже?

if (foo === bar) {
    import Baz from './Baz';
}

Я пробовал описанное выше, но при компиляции получаю следующую ошибку (от Babel).

'import' and 'export' may only appear at the top level

Динамический

Возможно ли иметь динамические операторы импорта, как показано ниже?

for (let foo in bar) {
    if (bar.hasOwnProperty(foo)) {
        import Baz from `./${foo}`;
    }
}

Вышеупомянутое получает ту же ошибку от Babel во время компиляции.

Возможно ли это сделать или мне чего-то не хватает?

Рассуждение

Причина, по которой я пытаюсь это сделать, заключается в том, что у меня много операций импорта для ряда «страниц», и они следуют схожему шаблону. Я хотел бы очистить свою базу кода, импортировав эти файлы с помощью динамического цикла for.

Если это невозможно, то есть ли лучший способ обрабатывать большое количество импорта в ES6?

Enijar
источник
1
нельзя ли в таком случае использовать наследование? используйте superдля вызова конкретного.
Jai
Я уже использую наследование, но эти «страницы» содержат в себе специфическую логику «страницы». У меня есть базовый класс «страницы», который все расширяется, но этого недостаточно, чтобы очистить огромное количество импортируемых мной файлов.
Enijar
1
@zerkms: Их не вытаскивают из блоков - это синтаксические ошибки.
Bergi
Возможный дубликат имени импорта переменной ES6 в node.js ?
Bergi

Ответы:

54

Сейчас у нас есть предложение по динамическому импорту с ECMA. Это на этапе 2. Это также доступно как babel-preset. .

Ниже приведен способ условного рендеринга в соответствии с вашим случаем.

if (foo === bar) {
    import('./Baz')
    .then((Baz) => {
       console.log(Baz.Baz);
    });
}

Это в основном возвращает обещание. Ожидается, что разрешение обещания будет у модуля. В предложении также есть такие вещи, как множественный динамический импорт, импорт по умолчанию, импорт файлов js и т. Д. Вы можете найти больше информации о динамическом импорте здесь .

кодек
источник
3
Этот. Динамический импорт - лучший вариант. Они работают так же, как require (), за исключением того, что они дают вам обещание, а не модуль.
superluminary
25

Вы не можете динамически разрешать свои зависимости, поскольку importsони предназначены для статического анализа. Однако вы, вероятно, можете использовать requireздесь что-то вроде:

for (let foo in bar) {
    if (bar.hasOwnProperty(foo)) {
        const Baz = require(foo).Baz;
    }
}
Джонатан Петитколас
источник
8
"поскольку импорт предназначен для статического анализа." --- это утверждение расплывчато. imports предназначены для импорта, а не для анализа.
zerkms
13
@zerkms - Я думаю , что они имели в виду, что importзаявления предназначены для подходят для статического анализа - потому что они никогда не условными, инструменты могут анализировать деревья зависимостей проще.
Джо Клей
4
Трудно понять с «foo», «baz» и «bar» - как насчет примера из реальной жизни?
TetraDev 05
1
Это уже не так. Динамический импорт теперь в ходу. Смотрите здесь: stackoverflow.com/a/46543949/687677
superluminary
7

Поскольку этот вопрос высоко оценен Google, стоит отметить, что с момента публикации более старых ответов все изменилось.

В MDN есть эта запись в разделе динамического импорта :

Ключевое слово import может быть вызвано как функция для динамического импорта модуля. При таком использовании возвращает обещание.

import('/modules/my-module.js')
  .then((module) => {
    // Do something with the module.
  });

// This form also supports the await keyword.
let module = await import('/modules/my-module.js');

Полезную статью по этой теме можно найти на Medium .

LeeGee
источник
2

С 2016 года в мире JavaScript многое изменилось, поэтому я считаю, что пора предложить самую свежую информацию по этой теме. В настоящее время динамический импорт возможен как в Node, так и в браузерах (изначально, если вам не важен IE, или с помощью @ babel / plugin-syntax-dynamic-import, если вам все равно).

Итак, рассмотрим образец модуля something.jsс двумя именами экспорта и одним экспортом по умолчанию:

export const hi = (name) => console.log(`Hi, ${name}!`)
export const bye = (name) => console.log(`Bye, ${name}!`)
export default () => console.log('Hello World!')

Мы можем использовать import()синтаксис, чтобы легко и чисто загрузить его по условию:

if (somethingIsTrue) {
  import('./something.js').then((module) => {
    // Use the module the way you want, as:
    module.hi('Erick') // Named export
    module.bye('Erick') // Named export
    module.default() // Default export
  })
}

Но так как возвращение является Promise, то async/ awaitсинтаксический сахар также возможно:

async imAsyncFunction () {
  if (somethingIsTrue) {
    const module = await import('./something.js')
    module.hi('Erick')
  }
}

Теперь подумайте о возможностях вместе с назначением разрушения объекта ! Например, мы можем легко поместить в память только один из названных экспортов для последующего использования:

const { bye } = await import('./something.js')
bye('Erick')

Или, может быть, возьмите один из названных экспортов и переименуйте его как угодно:

const { hi: hello } = await import('./something.js')
hello('Erick')

Или даже переименуйте экспортируемую функцию по умолчанию во что-нибудь более понятное:

const { default: helloWorld } = await import('./something.js')
helloWorld()

И последнее (но не менее важное) замечание: import() может выглядеть как вызов функции, но это не Function. Это особый синтаксис, в котором просто используются круглые скобки (аналогично тому, что происходит с super()). Таким образом, невозможно присвоить importпеременной или использовать элементы Functionпрототипа, например call/ apply.

Эрик Петручелли
источник
1

Require не решит вашу проблему, так как это синхронный вызов. Есть несколько вариантов, и все они включают

  1. Запрос необходимого модуля
  2. Жду обещания вернуть модуль

В ECMA Script есть поддержка отложенной загрузки модулей с помощью SystemJS. Это, конечно, поддерживается не во всех браузерах, поэтому пока вы можете использовать JSPM или прокладку SystemJS.

https://github.com/ModuleLoader/es6-module-loader

Хенрик Вендельбо
источник