typescript - 用 worker 构建一个 TypeScript 项目

标签 typescript service-worker web-worker

我应该如何构建一个包含主线程 (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 .但是项目边界使得它们之间很难引用类型。

  • 此外,我如何在工作人员中声明全局?以前我用过declare var self: DedicatedWorkerGlobalScope ,但是有没有办法实际设置全局(而不仅仅是设置 self )?

    最佳答案

    非常感谢 Mattias Buelens谁给我指明了正确的方向。

    Here's a working example .

    项目结构为:

  • dist
  • src
  • generic-tsconfig.json
  • main
  • ( typescript 文件)
  • tsconfig.json
  • dedicated-worker
  • ( typescript 文件)
  • tsconfig.json
  • service-worker
  • ( typescript 文件)
  • 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目录中,每个子项目( maindedicated-workerservice-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
    这是专用 worker 的配置(您使用 new Worker() 创建的那种)。
    {
      "extends": "../generic-tsconfig.json",
      "compilerOptions": {
        "lib": ["esnext", "webworker"],
      }
    }
    

    您不需要在此处引用其他子项目,除非您从中导入内容(例如类型)。

    使用专用 worker 类型

    尽管它们具有不同的全局变量,但 TypeScript 不会区分不同的工作器上下文。因此,事情变得有点困惑:
    postMessage('foo');
    

    这是有效的,因为 TypeScript 的“webworker”类型为所有专用的工作器全局变量创建全局变量。然而:
    self.postMessage('foo');
    

    ...这失败了,因为 TypeScript 给出了 self一种不存在的类型,有点像抽象的 worker 全局。

    要解决此问题,请将其包含在您的源中:
    declare var self: DedicatedWorkerGlobalScope;
    export {};
    

    本套self到正确的类型。
    declare var除非文件是模块,否则 bit 不起作用,并且虚拟导出使 TypeScript 将其视为模块。这意味着您要声明 self在当前不存在的模块范围内。否则,您会尝试在它已经存在的全局变量上声明它。
    src/service-worker/tsconfig.json
    和上面一样。
    {
      "extends": "../generic-tsconfig.json",
      "compilerOptions": {
        "lib": ["esnext", "webworker"],
      }
    }
    

    使用 Service Worker 类型

    如上所述,TypeScript 的“webworker”类型为所有专用工作器全局变量创建全局变量。但这不是一个专门的 worker ,所以有些类型是不正确的:
    postMessage('yo');
    

    TypeScript 不会提示上述问题,但它会在运行时失败,如 postMessage不在 service worker 全局上。

    不幸的是,您无法修复真正的全局,但您仍然可以修复 self :
    declare var self: ServiceWorkerGlobalScope;
    export {};
    

    现在,您需要确保通过 self 访问对 Service Worker 而言特别的每个全局变量。 .
    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);
    });
    

    其他工作人员类型(例如工作集和共享工作人员)也存在相同的问题和解决方法。

    build

    tsc --build src/main
    

    就是这样!

    关于typescript - 用 worker 构建一个 TypeScript 项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56356655/

    相关文章:

    javascript - 如何通过 PostMessage 将 Serviceworker 响应主体 ReadableByteStream 作为 Blob 返回?

    javascript - Javascript 异步函数和 Web worker 之间的区别?

    html - Web Workers 消息顺序

    javascript - 如何使用间隔将 Angular 范围绑定(bind)到网络 worker 的结果?

    Angular 2 Firebase如何获取对象中的数组

    javascript - Typescript 未知扩展 T 延迟类型

    javascript - Angular 6 中具有相应组件的子路由

    angular - 拥有一个自定义类型有什么好处,它只是另一个自定义类型对象的数组

    javascript - 有没有办法打开mailto : and tel: links from a service worker?

    google-chrome - Chrome显示高速缓存存储使用率高