Как я могу условно импортировать модуль ES6?
Мне нужно сделать что-то вроде:
if (condition) {
import something from 'something';
}
// ...
if (something) {
something.doStuff();
}
Приведенный выше код не компилируется; это бросает SyntaxError: ... 'import' and 'export' may only appear at the top level
,
Я пытался с помощью System.import
как показано здесь, но я не знаю, где System
происходит от. Это предложение ES6, которое не было принято? Ссылка на "программный API" из этой статьи выводит меня на устаревшую страницу документации.
17 ответов
У нас есть предложение по динамическому импорту с ECMA. Это на этапе 3. Это также доступно как предустановка babel.
Ниже приведен способ сделать условный рендеринг согласно вашему случаю.
if (condition) {
import('something')
.then((something) => {
console.log(something.something);
});
}
Это в основном возвращает обещание. Ожидается, что разрешение обещание будет иметь модуль. Предложение также имеет другие функции, такие как множественный динамический импорт, импорт по умолчанию, импорт файла js и т. Д. Более подробную информацию о динамическом импорте вы можете найти здесь.
Если вы хотите, вы можете использовать требуют. Это способ получения условного оператора require.
let something = null;
let other = null;
if (condition) {
something = require('something');
other = require('something').other;
}
if (something && other) {
something.doStuff();
other.doOtherStuff();
}
Вы не можете импортировать условно, но вы можете сделать наоборот: экспортировать что-то условно. Это зависит от вашего варианта использования, поэтому этот обходной путь может быть не для вас.
Ты можешь сделать:
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, он нуждается в инициализации.
Обновление 2020
Теперь вы можете позвонить в
import
ключевое слово как функция (т.е.
import()
) для загрузки модуля во время выполнения.
Пример:
const mymodule = await import(modulename);
или же:
import(modulename)
.then(mymodule => /* ... */);
См. Https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Dynamic_Imports.
Похоже, ответ таков: на данный момент вы не можете.
http://exploringjs.com/es6/ch_modules.html
Я думаю, что цель состоит в том, чтобы включить статический анализ в максимально возможной степени, и условно импортированные модули ломают это. Также стоит упомянуть - я использую Babel, и я предполагаю, что System
Babel не поддерживается, потому что API загрузчика модулей не стал стандартом ES6.
Важное отличие, если вы используете режим динамического импорта 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(...);
}
Условный импорт и экспорт в JS
const value = (
await import(`${condtion ? `./file1.js` : `./file2.js`}`)
).default
export default value
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]);
Условный импорт также может быть достигнут с помощью трех require()
s:
const logger = DEBUG ? require('dev-logger') : require('logger');
Этот пример взят из глобальных документов ES Lint: https://eslint.org/docs/rules/global-require
Утаивание его в eval работало для меня, скрывая его от статического анализатора...
if (typeof __CLI__ !== 'undefined') {
eval("require('fs');")
}
У меня была похожая ситуация. Структура моего проекта была такой:
- библиотеки /
- макетApi.js
- RealApi.js
- index.js
Мне было необходимо, чтобы в продакшен -режиме в комплект не попадали моки. Еще мне было важно не писать условия в каждом месте использования и не работать с промисами.
Для меня решением было создать объединяющий файл api.js с кодом:
// solution 1
export const api = (
await import(`${process.env.NODE_ENV === 'development' ? './mockAPI.js' : './realAPI.js'}`)
).default
export default api;
При таком подходе в продакшен-режиме в бандл попадает только обработанный realAPI.js , а использование решения не требует отдельных условий или работы с промисами, например:
import api from './libs/api';
api.getUser();
Также можно использовать аналогичное решение:
// solution 2
let api = (await import('./realAPI')).default;
if (process.env.NODE_ENV === 'development') {
api = (await import('./mockAPI')).default;
}
export default api;
Оба решения позволяют не включать в комплект «моки» в рабочем режиме. Это делается путем удаления недостижимого кода во время процесса сборки, важно не перемещать условиеprocess.env.NODE_ENV === 'development' в переменную.
Можно перейти по ссылке ниже, чтобы узнать больше о динамическом импорте.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#dynamic_imports
Нет, нельзя!
Однако столкновение с этой проблемой должно заставить вас переосмыслить то, как вы организуете свой код.
До модулей ES6 у нас были модули CommonJS, в которых использовался синтаксис require(). Эти модули были "динамическими", что означало, что мы могли импортировать новые модули в зависимости от условий в нашем коде. - источник: https://bitsofco.de/what-is-tree-shaking/
Я предполагаю, что одна из причин, по которой они отказались от этой поддержки в ES6, заключается в том, что его компиляция будет очень сложной или невозможной.
Посмотрите на этот пример, чтобы понять, как работает динамический импорт.
Пример импорта динамического модуля
Иметь базовое представление об импорте и экспорте модулей.
Я знаю, что это не то, о чем задается вопрос, но вот мой подход к использованию моков при использовании vite . Я уверен, что мы можем сделать то же самое с webpack и другими.
Предположим, у нас есть две библиотеки с одинаковым интерфейсом:
link.js
а также
link-mock.js
, тогда:
В моем
vite.config.js
export default defineConfig(({ command, mode }) => {
const cfg = {/* ... */}
if (process.env.VITE_MOCK == 1) {
cfg.resolve.alias["./link"] = "./link-mock"; // magic is here!
}
return cfg;
}
код:
import { link } from "./link";
в консоли вызываем:
# to use the real link.js
npm run vite
# to use the mock link-mock.js
VITE_MOCK=1 npm run vite
или же
Скрипт package.json
{
....
"scripts": {
"dev": "vite",
"dev-mock": "VITE_MOCK=1 vite"
}
}
Как говорит Эриксоко , вместо:
import {ExampleClass} from "./ExampleClass.js";
new ExampleClass();
ты можешь написать
if(condition) {
import("./ExampleClass.js").then((module) => {
new module.ExampleClass();
});
}
Я смог добиться этого, используя функцию, вызываемую немедленно, и запрос оператора.
const something = (() => (
condition ? require('something') : null
))();
if(something) {
something.doStuff();
}