Импорт во встроенный «строковый» модуль с помощью Vite

Я создаю своего рода приложение для редактирования JS-кода в браузере, поэтому у меня есть поле ввода для кода. После каждого события изменения я хочу eval код в этом поле ввода. Поскольку код имеет формат ES, я не могу использовать eval() и вынужден использовать import():

// This is the code from input
let inputCode = `
    console.info('Hello World!');
`;

// Transforming it into inline ES module
let inlineModule = `data:text/javascript,` + inputCode;

// Importing our inline module
import(inlineModule).then(module => {});

Приведенный выше код работает отлично. Дело в том, что я хочу предоставить доступ к моему собственному пакету под названием bitran-parser в этом встроенном модуле. Поэтому я ожидаю, что этот код тоже будет работать:

let inputCode = `
    import { Product } from 'bitran-parser';
    console.info(Product);
`;

// ...

Но я получаю сообщение об ошибке, сообщающее, что путь к bitran-parser неверен. Изменение его на что-то вроде /@fs/D:/projects/bitran/packages/parser/dist/index.js не помогает, я получаю следующую ошибку: «Не удалось разрешить спецификатор модуля «...». Неверный относительный URL-адрес или базовая схема не является иерархической.

Итак, мой вопрос: чем мне следует заменить bitran-parser имя пакета, чтобы код работал правильно как в режимах dev, так и build Vite?

Может быть, каким-то образом предварительно загрузить мой пакет непосредственно в приложение Vue и указать его прямое имя вместо стратегии ручного разделения Vite?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
80
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Решил решить эту проблему с помощью виртуальных модулей Vite. Сначала мы создаем плагин виртуального модуля. Этот плагин также объединяет наш виртуальный модуль в отдельный блок при создании приложения Vite:

import { type Plugin } from "vite";

export default function() {
    const moduleName = 'local-bitran-parser';
    let serveMode = false;

    return <Plugin> {
        name: moduleName,
        configResolved(config) {
            serveMode = config.command === 'serve';
        },
        resolveId(id) {
            if (id === moduleName)
                return moduleName;
        },
        load(id) {
            if (id === moduleName)
                return 'export * from "bitran-parser"'; // This is the contents of our virtual module
        },
        buildStart() {
            if (!serveMode)
                this.emitFile({
                    type: 'chunk',
                    fileName: 'parser.js', // Saving our virutal module into file when building the App
                    id: moduleName,
                    preserveSignature: 'exports-only'
                })
        }
    }
}

Теперь мы можем использовать виртуальный модуль во встроенных модулях внутри приложения. Для этого нам нужно сканировать каждый импорт и заменять имя нашего пакета на путь к виртуальному модулю (в режиме dev) или путь к сохраненному чанку (в режиме build):

// ... somewhere inside App

let inputCode = `
    import { Product } from 'bitran-parser';
    console.info(Product);
`;

// Replace import targets when importing from "bitran-parser"
// In `dev` mode: "bitran-parser" --> "https://.../@id/local-bitran-parser" (our virtual module id)
// In `build` mode: "bitran-parser" --> "https://.../parser.js"
function replaceImports(configStr: string)
{
    return configStr.replace(/(import\s+(?:{[^{}]+}|.*?)\s*(?:from)?)\s*['"](.*?)['"]|import\(.*?\)/g, (match, begin, target) =>
    {
        if (target === 'bitran-parser')
            target = location.origin + (import.meta.env.MODE === 'development' ? '/@id/local-bitran-parser' : '/parser.js');

        return begin + ' ' + `"${target}"`;
    })
}

// Executing the code
import('data:text/javascript;base64,' + btoa(replaceImports(inputCode)).then(module => {});

Другие вопросы по теме