使用 worker 构建 TypeScript 项目
Structuring a TypeScript project with workers
我应该如何构建包含主线程 (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
同时具有 worker 和 DOM 类型。但当然这在类型方面并不准确。
- 使用多个
tsconfig.json
。但是项目边界使得它们之间很难引用类型。
另外,如何在worker中声明global?以前我用过 declare var self: DedicatedWorkerGlobalScope
,但有没有办法实际设置全局(而不是仅仅设置 self
)?
非常感谢 Mattias Buelens 为我指明了正确的方向。
项目结构为:
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
这是 'main thread' 项目的配置,如 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 不区分不同的 worker 上下文,尽管它们具有不同的全局变量。因此,事情变得有点混乱:
postMessage('foo');
这是有效的,因为 TypeScript 的 "webworker" 类型为所有专用的工作全局变量创建了全局变量。然而:
self.postMessage('foo');
…这失败了,因为 TypeScript 给 self
一个 non-existent 类型,它是 sort-of 全局抽象工作者。
要解决此问题,请将其包含在您的源代码中:
declare var self: DedicatedWorkerGlobalScope;
export {};
这会将 self
设置为正确的类型。
除非文件是模块,否则 declare var
位不起作用,并且虚拟导出使 TypeScript 将其视为模块。这意味着您在模块范围内声明 self
,该范围当前不存在。否则,您正试图在全局上声明它,它 已经存在。
src/service-worker/tsconfig.json
同上
{
"extends": "../generic-tsconfig.json",
"compilerOptions": {
"lib": ["esnext", "webworker"],
}
}
使用服务工作者类型
如上所述,TypeScript 的 "webworker" 类型为所有专用的工作全局变量创建全局变量。但这不是一个专门的工人,所以有些类型不正确:
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
就是这样!
我应该如何构建包含主线程 (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
同时具有 worker 和 DOM 类型。但当然这在类型方面并不准确。 - 使用多个
tsconfig.json
。但是项目边界使得它们之间很难引用类型。
另外,如何在worker中声明global?以前我用过 declare var self: DedicatedWorkerGlobalScope
,但有没有办法实际设置全局(而不是仅仅设置 self
)?
非常感谢 Mattias Buelens 为我指明了正确的方向。
项目结构为:
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
这是 'main thread' 项目的配置,如 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 不区分不同的 worker 上下文,尽管它们具有不同的全局变量。因此,事情变得有点混乱:
postMessage('foo');
这是有效的,因为 TypeScript 的 "webworker" 类型为所有专用的工作全局变量创建了全局变量。然而:
self.postMessage('foo');
…这失败了,因为 TypeScript 给 self
一个 non-existent 类型,它是 sort-of 全局抽象工作者。
要解决此问题,请将其包含在您的源代码中:
declare var self: DedicatedWorkerGlobalScope;
export {};
这会将 self
设置为正确的类型。
除非文件是模块,否则 declare var
位不起作用,并且虚拟导出使 TypeScript 将其视为模块。这意味着您在模块范围内声明 self
,该范围当前不存在。否则,您正试图在全局上声明它,它 已经存在。
src/service-worker/tsconfig.json
同上
{
"extends": "../generic-tsconfig.json",
"compilerOptions": {
"lib": ["esnext", "webworker"],
}
}
使用服务工作者类型
如上所述,TypeScript 的 "webworker" 类型为所有专用的工作全局变量创建全局变量。但这不是一个专门的工人,所以有些类型不正确:
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
就是这样!