Att använda WebWorkers i Typescript med Webpack och worker-loader utan anpassade loader-strängar


Jag försöker få webbarbetare att fungera bra tillsammans med Typescript och Webpacks worker-loader. Det finns ett exempel i deras dokumentation på hur man uppnår detta genom en anpassad moduldeklaration, men detta förlitar sig på att använda webpack worker-loader!./myWorker-syntaxen.

Jag vill kunna ladda arbetare genom en anpassad *.worker.js webpack use-regel istället för att uttryckligen lista loadern i importsträngen. Något med TypeScript verkar inte gilla att definiera eller ändra en moduldeklaration om det är en vanlig relativ import, och fastnar på faktumet att arbetsfilen inte är en modul, även med en moduldeklaration för den.

Jag har en arbetare som ser ut som

// test.worker.ts
/// <reference lib="webworker" />

const worker: DedicatedWorkerGlobalScope = self as any;

worker.onmessage = ({ data }) => {
  if (data instanceof Array) {
    worker.postMessage(data.join(' ') + '!');
  }
};

Ett uttalande som ser ut som

// custom.d.ts
declare module '*.worker' {
  class TestWorker extends Worker {
    constructor();
  }

  export default TestWorker
}

Och används i min huvudapp som

import TestWorker from './test.worker';

const testWorker = new TestWorker();
testWorker.onmessage = ({ data }: { data: string }) => {
  console.log(data);
};

testWorker.postMessage([
  'hello',
  'I',
  'am',
  'a',
  'web',
  'worker',
]);

Felutdata är

TypeScript error in /worker-test/src/index.tsx(9,24):File '/worker-test/src/test.worker.ts' is not a module.  TS2306

Att ändra importen till worker-loader!./test.worker verkar fungera och gör att TypeScript förstår den anpassade deklarationen, men jag försöker verkligen undvika att använda anpassade loader-strängar eftersom avsikten är att integrera detta i create-react-app som inte tillåter dessa.

Finns det ett sätt att få vanliga relativa importer att känna igen en anpassad moduldeklaration?

Svar #1

Du var nästan där!

Ändra moduldeklarationen för att inkludera filändelsen:

// custom.d.ts
declare module '*.worker.ts' {
  class TestWorker extends Worker {
    constructor();
  }

  export default TestWorker
}

Och ditt import ska också inkludera filändelsen:

import TestWorker from './test.worker.ts';

Det här gjorde susen för mig - att ange filtillägget vid importen förhindrar att TS importerar det som en modul, och att ange filtillägget i deklarationen gör att TS slutar klaga eftersom du importerar en .ts-fil genom att också ange filtillägget.

Relaterade artiklar