Discourse theme components now support Wasm 🎊

WebAssembly (Wasm) is a technology that ships in all modern browsers that lets developers ship portable binary programs.

This means that developers can use almost any programming language and target the web.

In the context of Discourse this opens up the door to shipping a fairly rich set of extensions that were only available to plugin creators in the past.

Examples could be:

  • Image watermarking / resizing / cropping
  • Graph generation using graphviz or svgbob
  • Programming sandboxes (eg: a posts that embed a Ruby runtime)
  • and much more

In the past due to the Discourse Content Security Policy access to Wasm was shut down except for installations with both local uploads and no CDN.

New interfaces were added to client side to support shipping JavaScript assets in a theme that are unconditionally reachable via local domain.

This enables theme developers to cleanly host Wasm, the flow is:

component → local web worker → Wasm hosted on CDN

Discourse svgbob is an end-to-end example of the new patterns, the 2 key changes are:

  1. All .js assets are also made available off CDN on local server:
{
...
  "assets": {
    "worker": "assets/will-be-avilable-on-local.js"
  }
}
  1. The URL for the local asset is accessible via settings.theme_uploads_local

So in the example above:

settings.theme_uploads_local.worker; // local asset
settings.theme_uploads.worker; // cdn asset
35 Likes

Not specifically wasm related, but I found something else interesting about this code, is it new?

In your example, loadScript is no longer required? (I believe the import is redundant?):

and instead worker script is loaded JIT when the worker is found not to exist?

using the URL built from the asset reference.

That’s a nice pattern and very helpful!

However, I have a question about workers.

If I used a third party worker script, and that contains importScripts() statements to include additional scripts into the worker’s global scope, how do I include those scripts for import inside the theme component?

I might be asking: how do we require a script from url within a Discourse Theme Component?

2 Likes

What I did in this scenario is using a postMessage from the main JS script with the URLs to be imported. This is received o the message handler on the worker that can importScript the URLs received.

2 Likes

Thank you Rafael!. Do you have an open source example to reference?

2 Likes

I used this same pattern in core

6 Likes

I am using the theme creator to create a new theme component that is supposed to use wasm. As a starting point, I tried uploading svgbob as a theme component. However, I am not allowed to do that, because it contains a wasm file.

Is that an intended limitation of the theme creator? Or can one not just install svgbob as-is?

2 Likes

I suspect we just have file type limitation on theme creator that need lifting.

3 Likes

I reset themecreator to use the default ‘theme authorized extensions’, which includes WASM. So it should work now @Heinenen.

(not sure why it was on a non-default setting… maybe in the past one of the common extensions was missing :man_shrugging:)

2 Likes

Yes, very cool, I can confirm that it works now. Thank you!

3 Likes

Okay, it seems I have to paddle back a bit, I don’t think it’s working perfectly quite yet.
I tried uploading svgbob again and that worked.

After now also trying to upload my own wasm-file, taken from MDN, I get the error:
An error occurred: You supplied invalid parameters to the request: string contains null byte

On my dev container, this is not a problem and I can upload the same file without a problem.

2 Likes

Isn’t running a binary from the website a security exposure that should be chosen carefully? That may be a reason why it was not default. What do you think @Roman_Rizzi?

1 Like

It is allowed in themes by default. It’s just the site setting on discourse.theme-creator.io which had been changed. (that’s a regular discourse site, with a plugin that allows anyone to upload and share themes).

WASM is still sandboxed by the browser, so the security exposure is equivalent to a .js file.

4 Likes