# Defer loading JavaScript in Themes and Components

**URL:** https://meta.discourse.org/t/defer-loading-javascript-in-themes-and-components/126370
**Category:** Development
**Tags:** dev-news
**Created:** [August 21, 2019, 7:45am UTC](https://meta.discourse.org/t/defer-loading-javascript-in-themes-and-components/126370 "2019-08-21T07:45:07Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [August 21, 2019, 7:45am UTC](https://meta.discourse.org/t/defer-loading-javascript-in-themes-and-components/126370/1 "2019-08-21T07:45:07Z")

</div>

Thanks to @david we have a very clean pattern for “eager” loading JavaScript in themes.

This means you just put `*.js.es6` files into the `javascripts` directory and it works exactly like plugins do, this is glorious.

For example this is how you do an initializer now, which has 100% parity with plugins:

- Create a file called `/javascripts/discourse/initializers/my-init.js.es6`

```plaintext
import { withPluginApi } from "discourse/lib/plugin-api";

function initialize(api) {
  // init via api here
}

export default {
  name: "discourse-otp",

  initialize() {
    withPluginApi("0.8.28", initialize);
  }
};

```

This is an enormously important feature cause we can now split up large complex themes into a lot of pieces, get linting, syntax highlighting and all the good stuff.

However, in some cases we may want to **optionally** ship a JS payload.

For example, say we are decorating posts, but only posts with very specific markdown. There is no point downloading a **100KB** fancy library till we know we are going to use it.

I worked around this in my component following this fancy change:

[https://github.com/discourse/discourse/commit/719a93c312b9caa6c71de22d67f1ce1a78c1c8b2](https://github.com/discourse/discourse/commit/719a93c312b9caa6c71de22d67f1ce1a78c1c8b2)

With:

```plaintext
import loadScript from "discourse/lib/load-script";

function generateOtp($elem) {
  loadScript(settings.theme_uploads.jsotp).then(() => {
     // stuff goes here
  });
}

```

This meant

1. I needed to add `.js` to `theme authorized extensions`
2. I needed to add a bypass to the CSP for the particular asset in `content security policy script src`
3. I needed to name the asset in my about.json

As a theme component writer, this is just too much friction cause you have no chance in the distribution game requiring this level of ninja.

I am thinking to make this usable there are 2 alternatives we can pick from

1. We can teach the system to auto CSP the `.js` assets in active themes and by default allow themes to upload `.js`

2. We can shift towards something like javascript\_cache that non defer theme js uses.

I am kind of leaning on 1 cause adding `.js` to theme authorized extensions seems trivial and auto CSP should not be impossible.

@pmusaraj / @Johani / @Osama any thoughts here?

---

<div class="post-metadata">

### Author: ![Johani](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/johani/32/176920_2.png) [@Johani](https://meta.discourse.org/u/Johani)
#### Post date: [August 21, 2019, 8:40am UTC](https://meta.discourse.org/t/defer-loading-javascript-in-themes-and-components/126370/2 "2019-08-21T08:40:30Z")

</div>

The ability to reference theme uploads in JS is a great addition! 💯

> [@sam](#):
>
> We can teach the system to auto CSP the `.js` assets in active themes and by default allow themes to upload `.js`

This makes a lot of sense to me because anything you can do in a `.js` file can already be done in files in the `javascripts` folder of the theme. So, I don’t see any harm in allowing themes to have `.js` uploads by default.

---

<div class="post-metadata">

### Author: ![Johani](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/johani/32/176920_2.png) [@Johani](https://meta.discourse.org/u/Johani)
#### Post date: [December 30, 2021, 1:52am UTC](https://meta.discourse.org/t/defer-loading-javascript-in-themes-and-components/126370/3 "2021-12-30T01:52:28Z")

</div>

Reviving this because the only thing left here is to teach CSP to allow theme `js` uploads. `js` files have been default-allowed as theme uploads for a while now.

If theme `js` uploads are not blocked by CSP, then components like [Image Annotator - Allows you to annotate images in the previewer](https://meta.discourse.org/t/image-annotator-allows-you-to-annotate-images-in-the-previewer/161936) won’t need to load their dependencies on the homepage (~170kb gzip). That component, for example, will only need to load those dependencies if the composer is opened. Plus, it never needs to load them to anon viewers.

Also, this change would “allow” themes to have [web worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) files that can do some heavy lifting off the main thread.

Allow in quotes above because you can have them as blobs, but it’s much nicer to have them in separate files instead of messing around with javascript in a string.

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [March 29, 2022, 6:59am UTC](https://meta.discourse.org/t/defer-loading-javascript-in-themes-and-components/126370/4 "2022-03-29T06:59:11Z")

</div>

I have some good news here, it is a bit gnarly to implement but at last we are going to support local JS assets for cases when we want to use web workers in theme components.

[https://github.com/discourse/discourse/pull/16312](https://github.com/discourse/discourse/pull/16312)

There is no other clean way to push this through the CSP, serving worker files from the same domain resolves the giant hole here.

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [April 7, 2022, 6:15am UTC](https://meta.discourse.org/t/defer-loading-javascript-in-themes-and-components/126370/5 "2022-04-07T06:15:18Z")

</div>

Note… this has now shipped 🎊

> [@Discourse theme components now support Wasm confetti\_ball](https://meta.discourse.org/t/discourse-theme-components-now-support-wasm/223574):
>
> [WebAssembly](https://webassembly.org/) (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 pos…
