Не работает import в web workers

Создал экземпляр класса Worker, в котором импортируется файл, но при запуске появляется ошибка в консоли "import declarations may only appear at top level of a module"

Код файла вызова воркера:

const worker = new Worker('./js/workers/calculateRequestData.js', {
  type: 'module',
});

worker.postMessage({ data: '1' });

worker.addEventListener('message', (event) => {
  console.log(event.data);
});

worker.addEventListener('error', (error) => {
  console.error(error.message);
});

Код файла calculateRequestData.js

import template from '../Template/template.js';

onmessage = function (e) {
  console.log(e.data);
  postMessage(e.data);
};

В нетворках файлы приходят со статусом 304 (если это поможет)

Пробовал делать:

  1. import template from '../Template/template.js' assert { type: 'module' }
  2. self.template = require('../js/Template/template.js // Ошибка: require не найден (или не работает, что-то такое)
  3. self.importScripts('../js/Template/template.js') // Ошибка та же что и в предыдущем пункте, только про importScripts.

Все это тоже не работает


Ответы (1 шт):

Автор решения: Дмитрий Ананьин

Ошибка заключалась в использовании "стандартного import ... from '...'"

Файл воркера превращается в один файл со скриптом, где не должно быть экспортов и импортов(в привычном для модулей виде). Для того чтобы импортировать файл, или несколько файлов, в воркер нужно использовать importScripts() (можно не использовать ключевое слово self). importScripts() "разворачивает" импортируемый файл в файле воркера.

Во vue cli файлы воркера и все его импортируемые файлы должны храниться не в src директории, а в public. Это связанно с тем что они не компилируются в общий бандл, а делается запрос к конкретному файлу.

Пример правильного кода:

Файл с вызовом воркера:

const worker = new Worker('./js/workers/calculateRequestData.js');

worker.postMessage({...});

worker.addEventListener('message', (event) => 
  console.error(event.data); // обрабатываем сообщения
  worker.terminate(); // не забываем удалять воркер
});

worker.addEventListener('error', (error) => {
  console.error(error.message); // обрабатываем ошибки
  worker.terminate(); // не забываем удалять воркер
});

Файл calculateRequestData.js

self.importScripts('../Template/template.js');

onmessage = function (e) {
  template.calculate(...) // работаем с импортированными данными
};

Также столкнулся с проблемой, когда продакшн сборка не работала из-за не правильного mime-type ('application/octet-stream') файлов воркера и импортируемого скрипта. Это связанно с тем что у нас сервер по умолчанию отдавал файлы с таким mime-type, при этом браузер по умолчанию вызывает модальное окно "Сохранить как". Это лечится указанием в конфигурационном файле для mime типов добавлением строчки 'application/octet-stream' Решение было найдено здесь - https://stackoverflow.com/questions/8744376/application-octet-stream-mime-type-issue-with-codeigniter

Пример:

'js' => [
    'application/x-javascript',
    'text/plain',
    'application/octet-stream',
],
→ Ссылка