microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.69k stars 12.44k forks source link

Support for inline web workers #19891

Closed rubenlg closed 6 years ago

rubenlg commented 6 years ago

This is a suggestion to add support for inline web workers on the typescript compiler. Right now, if one wants to write an inline web worker, this is how it looks like:

const blob = new Blob([
`
self.onmessage = event => {
  // Process the event
  self.postMessage(/* potential response */);
};`]);
const worker = new Worker(window.URL.createObjectURL(blob));

However, the code for the worker has to be javascript. There is an alternative to put the worker in a separate file and have tsc compile it to javascript, but inline workers have benefits in certain situations such as shared libraries, where one might want to avoid adding burden to the binaries using the library to build and host the generated worker code.

Proposal 1:

Use tagged string literals, and have a special tag worker that is a keyword of the language and runs the compiler on the string, e.g:

const blob = new Blob([
worker`
self.onmessage = (event: MessageEvent) => {
  // Process the event
  self.postMessage(/* potential response */);
};`]);
const worker = new Worker(window.URL.createObjectURL(blob));

Pros:

Cons:

Proposal 2

Use existing compiler infra and function.toString(), and expose WorkerGlobalScope to main thread code:

function worker(self: WorkerGlobalScope) {
  self.onmessage = (event: MessageEvent) => {
    // Process the event
    self.postMessage(/* potential response */);
  };
}
const blob = new Blob([`${worker.toString()}; ${worker.name}(self);`]);
const worker = new Worker(window.URL.createObjectURL(blob));

Pros:

Cons:

Proposal 3

Similar to 2, but make the compiler a bit more aware that the function is an inline worker by introducing a keywork worker for functions. Also, introduce a library function blobOf() that consumes a worker function and returns a blob.

worker function myWorker() {
  self.onmessage = (event: MessageEvent) => {
    // Process the event
    self.postMessage(/* potential response */);
  };
}
const blob = blobOf(myWorker);
const worker = new Worker(window.URL.createObjectURL(blob));

Pros:

Cons:

I personally lean towards the second proposal because it seems much simpler. The only change required is to expose the WorkerGlobalScope interface in the d.ts library for the main thread.

Thoughts?

mhegazy commented 6 years ago

You can achieve your request today using a Language Service plugin for errors/intellisense in your string template and a post build step to convert TS to JS using ts.transpileModule.

There are other examples out there for similar patterns, e.g. lit-html, graph-ql, or pug. For instance, here is a VSCode plugin for lit-html that uses string templates. VSCode has a library to simplify the process of creating such extensions.

In general there are so many things that you can do in a string literal, and adding support for all of these in the language would not be a salable task; and for that, this request would be out-of-scope of the TS project at the time being.

Also the general request is in the same vein as https://github.com/Microsoft/TypeScript/issues/5151

typescript-bot commented 6 years ago

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.