Я создаю своего рода приложение для редактирования 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?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Решил решить эту проблему с помощью виртуальных модулей 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 => {});