Структурирование проекта TypeScript с рабочими - PullRequest
26 голосов
/ 29 мая 2019

Как мне структурировать проект, включающий сценарий основного потока (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);
};

worker.ts

// 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 Ответ

23 голосов
/ 30 мая 2019

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

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

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

  • 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.log(event.request);
});

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

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

Building

tsc --build src/main

И это все!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...