与工人一起构建 TypeScript 项目 [英] Structuring a TypeScript project with workers

查看:43
本文介绍了与工人一起构建 TypeScript 项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我应该如何构建一个包含主线程 (DOM) 脚本和工作线程的项目?例如:

How should I structure a project that includes main thread (DOM) script, and workers? Eg:

// 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 抗争:

Whenever I've tried this in the past I feel like I've been fighting TypeScript by either:

  • 使用一个 tsconfig.json 同时具有 worker 和DOM 类型.但这当然不是准确的类型.
  • 使用多个 tsconfig.json.但是项目边界使得它们之间很难引用类型.
  • Using one tsconfig.json that has both worker & DOM types. But of course this isn't accurate type-wise.
  • Using multiple tsconfig.json. But then the project boundary makes it hard to reference types between them.

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

Additionally, how do I declare the global in a worker? Previously I've used declare var self: DedicatedWorkerGlobalScope, but is there a way to actually set the global (rather than just setting self)?

推荐答案

非常感谢 Mattias Buelens 指出我朝着正确的方向前进.

Many thanks to Mattias Buelens who pointed me in the right direction.

这是一个工作示例.

项目结构为:

  • dist
  • src
    • generic-tsconfig.json
    • main
      • (打字稿文件)
      • tsconfig.json
      • (打字稿文件)
      • tsconfig.json
      • (打字稿文件)
      • tsconfig.json

      这包含每个项目通用的配置:

      This contains the config common to each project:

      {
        "compilerOptions": {
          "target": "esnext",
          "module": "esnext",
          "strict": true,
          "moduleResolution": "node",
          "rootDir": ".",
          "outDir": "../dist",
          "composite": true,
          "declarationMap": true,
          "sourceMap": true
        }
      }
      

      我故意避免调用这个 tsconfig.json,因为它本身不是一个项目.根据您的需要调整上述内容.以下是重要部分:

      I've deliberately avoided calling this tsconfig.json, as it isn't a project itself. Adapt the above to your needs. Here are the important parts:

      • outDir - 这是转译后的脚本、声明和源映射所在的位置.
      • rootDir - 通过将其设置为 src 目录,每个子项目(maindedicated-worker>, service-worker) 将作为 outDir 中的子目录出现,否则它们将尝试共享同一目录并相互覆盖.
      • composite - 这是 TypeScript 在项目之间保持引用所必需的.
      • outDir - This is where the transpiled script, declarations and source maps will go.
      • rootDir - By setting this to the src directory, each of the subprojects (main, dedicated-worker, service-worker) will appear as subdirectories in the outDir, otherwise they'll try and share the same directory and overwrite each other.
      • composite - This is required for TypeScript to keep references between projects.

      不要在此文件中包含 references.他们会因为一些无证的原因而被忽略(这就是我被卡住的地方).

      Do not include references in this file. They'll be ignored for some undocumented reason (this is where I got stuck).

      这是主线程"项目的配置,例如可以访问文档的 JavaScript.

      This is the config for the 'main thread' project, As in, the JavaScript that will have access to the document.

      {
        "extends": "../generic-tsconfig.json",
        "compilerOptions": {
          "lib": ["esnext", "dom"],
        },
        "references": [
          {"path": "../dedicated-worker"},
          {"path": "../service-worker"}
        ]
      }
      

      • extends - 这指向我们上面的通用配置.
      • compilerOptions.lib - 此项目使用的库.在这种情况下,JS 和 DOM.
      • references - 由于这是主项目(我们构建的项目),它必须引用所有其他子项目以确保它们也被构建.
        • extends - This points to our generic config above.
        • compilerOptions.lib - The libs used by this project. In this case, JS and the DOM.
        • references - Since this is the main project (the one we build), it must reference all other subprojects to ensure they're also built.
        • 这是专用工作器的配置(您使用 new Worker() 创建的那种).

          This is the config for the dedicated worker (the kind you create with new Worker()).

          {
            "extends": "../generic-tsconfig.json",
            "compilerOptions": {
              "lib": ["esnext", "webworker"],
            }
          }
          

          除非您从中导入内容(例如类型),否则您无需在此处引用其他子项目.

          You don't need to reference the other sub projects here unless you import things from them (eg types).

          TypeScript 不会区分不同的 worker 上下文,尽管它们具有不同的全局变量.因此,事情变得有点混乱:

          TypeScript doesn't differentiate between different worker contexts, despite them having different globals. As such, things get a little messy:

          postMessage('foo');
          

          这是有效的,因为 TypeScript 的webworker"类型为所有专用工作器全局变量创建全局变量.但是:

          This works, as TypeScript's "webworker" types create globals for all dedicated worker globals. However:

          self.postMessage('foo');
          

          ...这失败了,因为 TypeScript 给了 self 一个不存在的类型,它有点像一个抽象的全局工人.

          …this fails, as TypeScript gives self a non-existent type that's sort-of an abstract worker global.

          要解决此问题,请将其包含在您的来源中:

          To fix this, include this in your source:

          declare var self: DedicatedWorkerGlobalScope;
          export {};
          

          这会将 self 设置为正确的类型.

          This sets self to the correct type.

          除非文件是模块,否则 declare var 位不起作用,并且虚拟导出使 TypeScript 将其视为模块.这意味着您在模块范围内声明了 self,该范围目前不存在.否则,您将尝试在全局声明它确实已经存在.

          The declare var bit doesn't work unless the file is a module, and the dummy export makes TypeScript treat it as a module. This means you're declaring self in the module scope, which doesn't currently exist. Otherwise, you're trying to declare it on the global, where it does already exist.

          同上.

          {
            "extends": "../generic-tsconfig.json",
            "compilerOptions": {
              "lib": ["esnext", "webworker"],
            }
          }
          

          使用 Service Worker 类型

          如上所述,TypeScript 的webworker"类型为所有专用工作器全局变量创建全局变量.但这不是一个专门的工人,所以有些类型是不正确的:

          Using service worker types

          As above, TypeScript's "webworker" types create globals for all dedicated worker globals. But this isn't a dedicated worker, so some of the types are incorrect:

          postMessage('yo');
          

          TypeScript 不会抱怨上述问题,但它会在运行时失败,因为 postMessage 不在 service worker 全局上.

          TypeScript doesn't complain about the above, but it'll fail at runtime as postMessage isn't on the service worker global.

          不幸的是,您无法修复真正的全局,但您仍然可以修复self:

          Unfortunately there's nothing you can do to fix the real global, but you can still fix self:

          declare var self: ServiceWorkerGlobalScope;
          export {};
          

          现在您需要确保通过 self 访问每个对 Service Worker 特殊的全局变量.

          Now you need to ensure every global that's special to service workers is accessed via 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);
          });
          

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

          The same issues and workarounds exist for other worker types, such as worklets and shared workers.

          tsc --build src/main
          

          就是这样!

          这篇关于与工人一起构建 TypeScript 项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆