Имя импорта переменной ES6 в node.js?
Можно ли импортировать что-то в модуль с именем переменной при использовании импорта ES6?
Т.е. я хочу импортировать некоторый модуль во время выполнения в зависимости от значений, указанных в конфиге:
import something from './utils/' + variableName;
13 ответов
Не с import
заявление. import
а также export
определены таким образом, что они статически анализируемы, поэтому они не могут зависеть от информации времени выполнения.
Вы ищете загрузчик API (polyfill), но я немного неясен относительно статуса спецификации:
System.import('./utils/' + variableName).then(function(m) {
console.log(m);
});
Существует новая спецификация, которая называется динамическим импортом для модулей ES. В основном, вы просто звоните import('./path/file.js')
и тебе хорошо идти. Функция возвращает обещание, которое разрешается с модулем, если импорт был успешным.
async function import() {
try {
const module = await import('./path/module.js');
} catch (error) {
console.error('import failed');
}
}
Основные варианты использования включают импорт модулей на основе маршрутов для Polymer 3.0, React и Vue, что снижает пропускную способность загрузки, поскольку пакеты для маршрутов загружаются только тогда, когда они необходимы.
Вот предлагаемая спецификация на Github.
Прямо сейчас (январь 2017 г.) эта функция работает в Chrome 62. Другие крупные браузеры, вероятно, используют эту функцию и реализуют ее в дальнейшем, когда полностью поддерживается поддержка ES module.
Редактировать:
Я должен добавить, что спецификация требует, чтобы импорт был статически анализируемым, как для обычного, так и для динамического импорта, что означает, что вы не можете использовать имя переменной для объявления своего пути импорта. Таким образом, нет никакого решения для вашего вопроса, потому что спецификация ES предотвращает это по замыслу.
Хотя это на самом деле не динамический импорт (например, в моих обстоятельствах все файлы, которые я импортирую ниже, будут импортированы и упакованы с помощью веб-пакета, а не выбраны во время выполнения), шаблон, который я использовал, может помочь в некоторых обстоятельствах::
import Template1 from './Template1.js';
import Template2 from './Template2.js';
const templates = {
Template1,
Template2
};
export function getTemplate (name) {
return templates[name];
}
или альтернативно:
// 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;
Я не думаю, что могу вернуться к дефолту так же легко с require()
, который выдает ошибку, если я пытаюсь импортировать созданный путь шаблона, который не существует.
Хорошие примеры и сравнения между require и import можно найти здесь: http://www.2ality.com/2014/09/es6-modules-final.html
Отличная документация по реэкспорту из @iainastacio: http://exploringjs.com/es6/ch_modules.html
Мне интересно услышать отзывы об этом подходе:)
В дополнение к ответу Феликса я прямо отмечу, что в настоящее время это не разрешено грамматикой ECMAScript 6:
ImportDeclaration :
import ImportClause FromClause;
импортировать ModuleSpecifier;
FromClause :
- от ModuleSpecifier
ModuleSpecifier :
- СтроковойЛитерал
ModuleSpecifier может быть только StringLiteral, а не любым другим видом выражения, как AdditiveExpression.
Я понимаю вопрос, специально заданный для ES6 import
в Node.js, но следующее может помочь другим, ищущим более универсальное решение:
let variableName = "es5.js";
const something = require(`./utils/${variableName}`);
Обратите внимание, если вы импортируете модуль ES6 и вам нужен доступ к default
экспорт, вам нужно будет использовать один из следующих:
let variableName = "es6.js";
// Assigning
const defaultMethod = require(`./utils/${variableName}`).default;
// Accessing
const something = require(`./utils/${variableName}`);
something.default();
Вы также можете использовать деструктуризацию с этим подходом, который может добавить больше синтаксического знакомства с другими вашими импортами:
// Destructuring
const { someMethod } = require(`./utils/${variableName}`);
someMethod();
К сожалению, если вы хотите получить доступ default
а также деструктуризация, вам нужно будет выполнить это в несколько этапов:
// 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;
У меня была аналогичная проблема с использованием
Vue.js
: Когда вы используете переменную в
import(variableName)
во время сборки Webpack не знает, где искать. Таким образом, вы должны ограничить его известным путем с соответствующим расширением:
let something = import("@/" + variableName + ".js")
Этот ответ в github по той же проблеме был очень полезен для меня.
Вы можете использовать нотацию не-ES6, чтобы сделать это. вот что сработало для меня:
let myModule = null;
if (needsToLoadModule) {
myModule = require('my-module').default;
}
Мне меньше нравится этот синтаксис, но он работает:
вместо того чтобы писать
import memberName from "path" + "fileName";
// this will not work!, since "path" + "fileName" need to be string literal
используйте этот синтаксис:
let memberName = require("path" + "fileName");
Динамический импорт () (доступен в Chrome 63+) сделает вашу работу. Вот как:
let variableName = 'test.js';
let utilsPath = './utils/' + variableName;
import(utilsPath).then((module) => { module.something(); });
./utils/test.js
export default () => {
doSomething...
}
звонок из файла
const variableName = 'test';
const package = require(`./utils/${variableName}`);
package.default();
Исходя из этого вопроса здесь , который был помечен как [Node.js], но он закрыт/помечен как дубликат этого вопроса, поэтому я добавлю свой ответ здесь.
У меня было похожее требование в NodeJS, поэтому я написал import-sync:
Библиотека охватывает esm и позволит вам динамически импортировать модули ESM в модуль CommonJS (или модуль ESM) во время выполнения в NodeJS.
Вы можете установить библиотеку с помощью:
npm install import-sync
Затем используйте его следующим образом:
// import importSync from 'import-sync'; // for ESM
const importSync = require('import-sync');
const someVariable = 'someModule';
if (someCondition) {
const someModule = importSync(`../../someFolder/${someVariable}`);
console.log(someModule);
}
// Answering the original closed question:
// - https://stackoverflow.com/questions/30340005/importing-modules-using-es6-syntax-and-dynamic-path
if (someOtherCondition) {
const someOtherModule = importSync(`${process.cwd()}/someOtherModule`);
console.log(someOtherModule);
}
Любая комбинация CJS, импортирующего ESM, ESM, импортирующего CJS, и т. д. будет работать.
Надеюсь, кому-то это принесет пользу :).
Это зависит. Вы можете использовать литералы шаблонов в динамическом импорте для импорта файла на основе переменной.
Я использовал динамический импорт, чтобы добавить.vue
файлы для vue router. я исключилHome.vue
посмотреть импорт.
const pages = [
'About',
['About', 'Team'],
]
const nodes = [
{
name: 'Home',
path: '/',
component: Home,
}
]
for (const page of pages) {
if (typeof page === 'string') {
nodes.push({
name: page,
path: `/${page}`,
component: import(`./views/${page}.vue`),
})
} else {
nodes.push({
name: _.last(page),
path: `/${page.join('/')}`,
component: import(`./views/${_.last(page)}.vue`)
})
}
}
Это сработало для меня. Я использовал пряжу + vite + vue на повторе.
Я бы сделал это так
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