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 devlopers 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

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?


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.


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


I used this same pattern in core