Nano Hash - криптовалюты, майнинг, программирование

Структурирование проекта TypeScript с работниками

Как мне структурировать проект, который включает сценарий основного потока (DOM) и рабочие потоки? Например:

main.ts

// This file must have DOM types, but not worker types.

const worker = new Worker('worker.js');

worker.onmessage = (event) => {
  // Ideally, I should be able to reference types from the worker:
  const data = event.data as import('./worker').HelloMessage;
  console.log(data.hello);
};

рабочий.тс

// This file must have worker types, but not DOM types.
// The global object must be one of the worker globals (how do I pick which?)

const helloMessage = {
  hello: 'world',
};

export type HelloMessage = typeof helloMessage;

postMessage(helloMessage);

Всякий раз, когда я пробовал это в прошлом, я чувствовал, что боролся с TypeScript либо:

  • Использование одного tsconfig.json, который имеет как рабочие типы, так и типы DOM. Но, конечно, это не точно по типу.
  • Использование нескольких tsconfig.json. Но тогда граница проекта затрудняет ссылку на типы между ними.

Кроме того, как мне объявить глобальный в работнике? Раньше я использовал declare var self: DedicatedWorkerGlobalScope, но есть ли способ установить глобальное значение (а не просто установить self)?


Ответы:


1

Большое спасибо Mattias Buelens, который указал мне правильное направление.

Вот рабочий пример.

Структура проекта такова:

  • dist
  • src
    • generic-tsconfig.json
    • main
      • (typescript files)
      • tsconfig.json
    • dedicated-worker
      • (typescript files)
      • tsconfig.json
    • service-worker
      • (typescript files)
      • tsconfig.json

src/generic-tsconfig.json

Он содержит конфигурацию, общую для каждого проекта:

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "moduleResolution": "node",
    "rootDir": ".",
    "outDir": "../dist",
    "composite": true,
    "declarationMap": true,
    "sourceMap": true
  }
}

Я намеренно не называл это tsconfig.json, так как это не проект. Адаптируйте вышеизложенное к вашим потребностям. Вот важные части:

  • outDir — здесь будут находиться транспилированный скрипт, объявления и исходные карты.
  • rootDir — установив это в каталог src, каждый из подпроектов (main, dedicated-worker, service-worker) будет отображаться как подкаталоги в outDir, в противном случае они будут пытаться использовать один и тот же каталог и перезаписывать друг друга.
  • composite — это необходимо для TypeScript, чтобы сохранять ссылки между проектами.

Не включайте references в этот файл. Они будут проигнорированы по какой-то недокументированной причине (здесь я застрял).

src/main/tsconfig.json

Это конфигурация для проекта «основной поток», например, JavaScript, который будет иметь доступ к документу.

{
  "extends": "../generic-tsconfig.json",
  "compilerOptions": {
    "lib": ["esnext", "dom"],
  },
  "references": [
    {"path": "../dedicated-worker"},
    {"path": "../service-worker"}
  ]
}
  • extends — указывает на нашу общую конфигурацию выше.
  • compilerOptions.lib — библиотеки, используемые в этом проекте. В данном случае JS и DOM.
  • references — Поскольку это основной проект (тот, который мы строим), он должен ссылаться на все остальные подпроекты, чтобы убедиться, что они также построены.

src/dedicated-worker/tsconfig.json

Это конфигурация для выделенного работника (такая, которую вы создаете с помощью new Worker()).

{
  "extends": "../generic-tsconfig.json",
  "compilerOptions": {
    "lib": ["esnext", "webworker"],
  }
}

Вам не нужно ссылаться здесь на другие подпроекты, если только вы не импортируете из них что-то (например, типы).

Использование выделенных рабочих типов

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

postMessage('foo');

Это работает, поскольку типы «веб-работников» TypeScript создают глобальные переменные для всех выделенных рабочих глобальных переменных. Однако:

self.postMessage('foo');

… это не удается, поскольку TypeScript дает self несуществующий тип, который является своего рода абстрактным рабочим глобальным.

Чтобы исправить это, включите это в свой источник:

declare var self: DedicatedWorkerGlobalScope;
export {};

Это устанавливает правильный тип self.

Бит declare var не работает, если файл не является модулем, а фиктивный экспорт заставляет TypeScript рассматривать его как модуль. Это означает, что вы объявляете self в области модуля, которой в настоящее время не существует. В противном случае вы пытаетесь объявить его в глобальном масштабе, где он действительно уже существует.

src/service-worker/tsconfig.json

То же, что и выше.

{
  "extends": "../generic-tsconfig.json",
  "compilerOptions": {
    "lib": ["esnext", "webworker"],
  }
}

Использование типов сервис-воркеров

Как и выше, типы «веб-работников» TypeScript создают глобальные переменные для всех выделенных рабочих глобальных переменных. Но это не выделенный работник, поэтому некоторые типы неверны:

postMessage('yo');

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

К сожалению, вы ничего не можете сделать, чтобы исправить настоящий глобальный код, но вы все равно можете исправить self:

declare var self: ServiceWorkerGlobalScope;
export {};

Теперь вам нужно обеспечить доступ к каждому глобальному объекту, специально предназначенному для сервис-воркеров, через self.

addEventListener('fetch', (event) => {
  // This is a type error, as the global addEventListener
  // doesn't know anything about the 'fetch' event.
  // Therefore it doesn't know about event.request.
  console.log(event.request);
});

self.addEventListener('fetch', (event) => {
  // This works fine.
  console.log(event.request);
});

Те же проблемы и обходные пути существуют для других типов рабочих процессов, таких как рабочие процессы и общие рабочие процессы.

Строительство

tsc --build src/main

Вот и все!

30.05.2019
  • Спасибо за подробное объяснение, @JaffaTheCake! Добавьте это в закладки. 30.05.2019
  • Отличный ответ +1. К вашему сведению, я создал минимальную настройку с рабочим примером для TS с Web Worker, вот мое решение: github .com/gibbok/typescript-web-workers Я использую приведение к DedicatedWorkerGlobalScope, чтобы помочь TS получить типы для себя. Я надеюсь, может быть полезным. 26.08.2020
  • @GibboK, этот проект, на который вы ссылаетесь, не решает проблему конфликтов между типами worker и dom, потому что он полностью исключает типы dom, я думаю, что ваш пример может быть слишком минимальным, чтобы быть полезным в реальной ситуации. 11.01.2021
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..