Структурирование проекта 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.info(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)?

Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
61
0
14 007
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

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

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

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

  • dist
  • src
    • generic-tsconfig.json
    • main
      • (файлы машинописного текста)
      • tsconfig.json
    • dedicated-worker
      • (файлы машинописного текста)
      • tsconfig.json
    • service-worker
      • (файлы машинописного текста)
      • 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.info(event.request);
});

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

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

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

tsc --build src/main

Вот и все!

Спасибо за подробное объяснение, @JaffaTheCake! Добавьте это в закладки.

andris.vilde 30.05.2019 14:07

Отличный ответ +1. К вашему сведению, я создал минимальную настройку с рабочим примером для TS с Web Worker, вот мое решение: github.com/gibbok/typescript-веб-работники Я использую приведение к DedicatedWorkerGlobalScope, чтобы помочь TS получить типы для себя. Я надеюсь, может быть полезным.

GibboK 26.08.2020 17:59

@GibboK, этот проект, на который вы ссылаетесь, не решает проблему конфликтов между типами worker и dom, потому что он полностью исключает типы dom, я думаю, что ваш пример может быть слишком минимальным, чтобы быть полезным в реальной ситуации.

Louis 10.01.2021 22:48

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