Modernizing inline script tags for templates & JS API

Using <script type='text/discourse-plugin> or <script type='text/x-handlebars'> in themes is now deprecated. Any use of these tags in themes should be updated according to the instructions below.

Regular <script> and <script type='text/javascript'> are unaffected by this change.

Timeline

These are rough estimates, subject to change

  • May 2025 - console deprecation messages enabled

  • July 2025 - admin warning banners enabled

  • September 2025 - removal of feature

Converting <script type='text/x-handlebars'>

Templates introduced using this method should be moved to dedicated .hbs files, or refactored into gjs files.

To keep as HBS, connector templates can be placed in:

{theme}/javascripts/discourse/connectors/{outlet-name}/{connector-name}.hbs

and component templates can be placed in:

{theme}/javascripts/discourse/components/{component-name}.hbs

To build connectors and components in the modern .gjs format, check out this chapter of the theme developer tutorial:

Converting <script type='text/discourse-plugin'>

Code inside these tags can be migrated to a dedicated JavaScript file.

If you develop your theme via the admin panel interface, copy the code out of the <script>, and move it into the JS tab (where it says // your code here).

If you develop your theme locally, create a new file at

{theme}/javascripts/discourse/api-initializers/init-theme.js

then add this wrapper, and place your code in the indicated spot:

import { apiInitializer } from "discourse/lib/api";

export default apiInitializer((api) => {
  // Your code here
});

In script tags, the only way to import other JS modules was using the require() syntax. While that will still work in a .js file, it will soon be deprecated, so now would be a good time to convert it to modern ES6 imports. For example:

- const I18n = require("discourse-i18n").default;
+ import I18n from "discourse-i18n";
- const { h } = require("virtual-dom");
+ import { h } from "virtual-dom";

For more information on JS initializers:

12 Likes

Maybe a very dumb question, but I have a very very simple theme component that I put directly into the admin console under <head>:

<script type="text/x-handlebars" data-template-name="/connectors/top-notices/whos-online-below-site-header">
{{whos-online}}
</script>

If I’m following this post correctly, does it mean that I now have to create a separate theme component folder, host it on GitHub and add the component just for something as simple as adding to a plugin outlet?

I sure hope not, as it’ll break most of my simple theme components :grimacing:

There is the JS tab now, so you can probably use api.renderInOutlet now.

1 Like

Ah, I didn’t see that this was possible to do with connectors/components as well, but in the linked article found this:

Maybe easier than I thought, thank you!

1 Like