Большое спасибо 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