Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for inline web workers #19891

Closed
rubenlg opened this issue Nov 10, 2017 · 2 comments
Closed

Support for inline web workers #19891

rubenlg opened this issue Nov 10, 2017 · 2 comments
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints

Comments

@rubenlg
Copy link

rubenlg commented Nov 10, 2017

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:

  • It's easy to enforce that code to be self-contained (imports fail, no references to other code in the file, etc)
  • The compiler can be aware that it is web worker code and use the right typings for self.

Cons:

  • If it is a string template, one could make parts of it dynamic, and then the compiler won't be able to parse it.
  • Can break existing code using a tag named worker.
  • Hard to integrate with other build tools, such as minimizers, that might run after the typescript compiler.

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:

  • Doesn't introduce new syntax on the language.
  • Won't break existing code.
  • Integrates nicely with minimizers and uglifiers that might optimize the code and rename the function.

Cons:

  • Much harder to isolate code. In the example above, the worker function could be calling stuff from the module or other modules that won't exist in the worker context.
  • The compiler thinks that the code is running in the context of the main thread, using the wrong d.ts library for self. That's why the cast of self to WorkerGlobalScope is needed.

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:

  • Integrates nicely with minimizers and uglifiers that might optimize the code and rename the function.
  • It's easier for the compiler to validate that the function is a valid worker, because it doesn't use any external code.
  • The compile is now aware that self means WorkerGlobalScope inside that function.

Cons:

  • Requires extra syntax and extra library functions.

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
Copy link
Contributor

mhegazy commented Nov 13, 2017

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 #5151

@mhegazy mhegazy added the Out of Scope This idea sits outside of the TypeScript language design constraints label Nov 13, 2017
@typescript-bot
Copy link
Collaborator

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

@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints
Projects
None yet
Development

No branches or pull requests

3 participants