Использование динамического импорта для обработки зависимостей, подобных AMD/requirejs.

Я отчаянно ищу способ объединить статический импорт (связку) с динамическим импортом (amd). Как Bundler, я в настоящее время использую webpack + babel-env для полифиллов (кстати: я так устал от всех конфигураций, всех ограничений и всех магических вещей, которые происходят, я бы с радостью избавился от webpack).

Использование webpack для создания модулей AMD не удовлетворяло, потому что requirejs усложняет отладку, а webpack просто не нравится идея модульной сборки/множества точек входа. Чтобы уточнить: у меня есть много точек входа, которые будут использовать некоторые общие библиотеки. Для веб-пакета это всегда концепция одного пакета, который контролирует все. Я читал о динамическом импорте и решил, что это перспективный способ.

Итак, я остановился на этой идее:

const library = await import("library.js");

export default function() {
    return library.foo("bar");
}

или для нескольких зависимостей какой-то

const depenencies = await Promise.all([
    import("library1.js"),
    import("library2.js")
]);
const library1 = dependencies[0];
const library2 = dependencies[1];

export default function() {
    return library1.foo("bar") + library2.bar("baz);
}

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

const [library1, library2] = await load('library1.js', 'library2.js');

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

Я хочу добиться чего-то очень похожего на AMD, где я могу определить модуль, который имеет зависимость от другого модуля, который должен загружаться браузером асинхронно.

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

Просто представьте, что я предоставляю некоторые предварительные компоненты (или что-то еще) и хочу поделиться общими/универсальными компонентами в нескольких модулях. Каждому модулю нужно будет импортировать preact-core, поэтому, конечно, я хотел бы предоставить это preact-ядро как отдельный модуль (vendor/preact.js).

Но я все равно хотел бы закодировать что-то вроде:

const Preact = await import("vendor/preact");

export default class StatefulComponent extends Preact.Component {
    render() {
        return "hello world";
    }
}

Используя ES6, мне нужно было бы сделать что-то вроде:

export default async function init() {
    return new Promise(resolve => {
        const Preact = await import("vendor/preact.js");
        class StatefulComponent extends Preact.Component {
            render();
        }
        resolve(StatefulComponent);
    });
}

Это просто глупо и некрасиво...

Верно ли, что API import() никак не подходит для управления зависимостями? Является ли мой единственный вариант AMD/requirejs и удаление веб-пакета?

Если решение супер-простое, и я просто слишком глуп, чтобы увидеть его, это потому, что я мучил свой мозг AMD/UMD/CommonJS/ES6/и скоро и так далее в последние дни, и я очень зол на javascript в целом на данный момент.


person Philipp Wrann    schedule 09.03.2021    source источник


Ответы (1)


Не нужно ТАК запутаться, но если у вас есть экспорт, который зависит от import, тогда он должен быть async (на основе обещаний).

Я бы сделал что-то вроде этого:

//mylibrary.js
export default (async function(){
    let dep1 = await import('1');
    let dep2 = await import('2');
    //so on and so on...

    return {
        myClassThatDependsOnDep1,
        myFunctionThatDependsOnDep2,
    }
})();

Который вы могли бы использовать аналогичным образом:

(async function(){
   let myLibrary = await import('mylibrary.js')
                   .then(m => m.default);

   //You use `myLibrary` here
   //                      v
   
})();

С TLA здесь можно отказаться от async IIFE.

person MinusFour    schedule 09.03.2021