Split up theme Javascript into multiple files

Complex theme javascript can be split into multiple files, to keep things nicely organised.

To use this functionality, simply add files to the /javascripts folder in your theme directory. Currently, these files can not be edited from the Discourse UI, so you must use the Theme CLI or source the theme from git.

Javascript files are treated exactly the same as they are in core/plugins, so you should follow the same file/folder structure. Theme files are loaded after core/plugins, so if the filenames match, the theme version will take precedence.


As an example, you can now accomplish Using Plugin Outlet Connectors from a Theme or Plugin by adding a single file to your theme:

/javascripts/my-theme/connectors/discovery-list-container-top/add-header-message.hbs

Welcome
{{currentUser.username}}. Please visit
<a class="nav-link" href="http://google.com" target="_blank">My Site</a>

To add a connector class, add another file

/javascripts/my-theme/connectors/discovery-list-container-top/add-header-message.js

import { isAppleDevice } from "discourse/lib/utilities";

export default {
  shouldRender(args, component) {
    return isAppleDevice();
  },
};

If you want to simply move some existing theme javascript out of a <script type="text/discourse-plugin" block, you should wrap it in an initializer like this:

/javascripts/my-theme/initializers/initialize-stuff.js

import { withPluginApi } from "discourse/lib/plugin-api";
export default {
  name: "my-initializer",
  initialize() {
    withPluginApi("0.8.7", (api) => {
      // Do something with the API here
    });
  },
};

If you need a totally different .js asset (e.g. for a web worker), check out this topic.


This document is version controlled - suggest changes on github.

27 Likes

Suppose I don’t know anything about the core/plugins file hierarchies, because I just came here to make a new theme component. Where do I look to find out? What are the naming conventions for directories and the files inside them?

Just looking at different theme/components circulating around, there are all kinds of different nesting schemes and subdirectories floating around. I have not been able to figure out a pattern, or find any documentation. (E.g., what is the difference between /initializers and /api-initializers and /pre-initializers? :crying_cat_face:)

1 Like

Files in here use the API. I honestly also wondered this for a while, why can’t I put the api-initializers files in initializers?

Yeah. It’s hard to make sense of. I prefer not to think about the number of times I spent 3 hours on something only to find that I named something wrong or put it in the wrong place, or sometimes, forgot to include it one of the seemingly many ways there are to do that (in plugin.rb, in an include in a js file–what path? Do I need an extension?)

Best is to use Install the Discourse Theme CLI console app to help you build themes and have it create a theme Skelton for you. And it makes it very easy to debug since it automatically uploads it to your server (a plain old production server) and (usually) reloads your browser automatically.

No idea what or if there is a difference (I don’t think so? But I have little clue). I would use the one that is in the theme Skelton.

There is a repo called all-the-themes. You can get that and search it for examples. And always use the one that’s been changed more recently.

3 Likes

A lot of EmberJS (and Rails) relies on Convention. This is great most of the time, but can be incredbily frustrating when you get something even slightly wrong, e.g. naming.

3 Likes

FWIW, I found an explanation of api-initializers/ here:

(And that connects it to the Ember docs, and then it starts making sense.)

It still would be nice to have a basic enumeration/explanation of the directory structure possibilities in one document. (E.g., I know connectors/ is a thing… are there more?)

Also, FWIW: the Theme CLI app pulls the skeleton from:

It only mentions api-initializers/.

(I am, in fact, using the Theme CLI app, but started using it after I already had the beginnings of a theme component, so I had skipped the skeleton step.)

2 Likes