Using the JS API

Discourse’s JavaScript API allows themes and plugins to make extensive customizations to the user experience. The simplest way to use it is to create a new theme from the admin panel, click “Edit Code”, and then head to the JS tab.

For file-based themes, the API can be used by creating a file in the api-initializers directory. For theme’s that’s {theme}/javascripts/api-initializers/init-theme.gjs, and for plugins, it’s {plugin}/assets/javascripts/discourse/api-initializers/init-plugin.js. The content should be:

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

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

All the available APIs are listed in the plugin-api.gjs source code in Discourse core, along with a short description and examples.

For a full tuturial, including examples of JS API usage, check out:


This document is version controlled - suggest changes on github.

39개의 좋아요

What’s the best way to “import” as a Site Customisation? - is it just to use require?

Whilst this works:

<script type="text/discourse-plugin" version="0.1">
var HamburgerMenuComponent = require('discourse/components/hamburger-menu').default;
</script>

This does not:

<script type="text/discourse-plugin" version="0.1">
import {default as HamburgerMenuComponent2 } from 'discourse/components/hamburger-menu';

</script>

Where I get this error:

<script type="text/discourse-js-error">unknown: 'import' and 'export' may only appear at the top level (3:0)
  1 | Discourse._registerPluginCode('0.1', api => {
  2 |   
> 3 | import {default as HamburgerMenuComponent2 } from 'discourse/components/hamburger-menu';
    | ^
  4 | 
  5 | 
  6 | }); at <eval>:8695:14</script>
2개의 좋아요

Instead of importing it, you can look it up with

api.container.lookupFactory('component:hamburger-menu')
5개의 좋아요

Is there a way to get access to the h helper from virtual-dom in a site customization? I’m trying to add a simple dropdown widget to use in our header, and I can’t get that darned h, even though I can get createWidget

Does:

h = require('virtual-dom').h;

not work?

2개의 좋아요

Yes it does! Works perfectly, thanks a ton!

I wouldn’t recommend doing it that way as it would likely break future compatibility. You can use this for now but I’ll try to introduce a workaround shortly that will be safer long term.

5개의 좋아요

Makes sense, it’s kinda circumventing the whole Plugin API thing and relying on implementation details of the ES6 compilation output, both things that are Dangerous™

Anyways, I’ll definitely keep an eye out for a better solution

I’ll try to get to it soon and I’ll reply in this topic, so watch it and you’ll see :slight_smile:

4개의 좋아요

Actually thinking about it, the decorateWidget helper gets called with an object that has the h method. How are you inserting your widget if not via a decorator?

If you could post code that would be helpful.

{{mount-widget}} in a template for a plugin outlet.

1개의 좋아요

Ah that’s clever – I didn’t think people would try that. Okay, let me try something out.

Okay, I’ve added h to the pluginApi object as long as you request plugin api v0.3:

<script type="text/discourse-plugin" version="0.3">
  console.log(api.h('b', ['hello', 'world']));
</script>

That should work for you!

https://github.com/discourse/discourse/commit/b10b6c673d5f4936d0ee107e16531df106fae75e

9개의 좋아요

This is now deprecated as of:

1개의 좋아요

Updated here, and in a bunch of other version-controlled docs. Thanks for the heads-up @NateDhaliwal

2개의 좋아요

이 링크는 더 이상 작동하지 않으며, 다음과 같은 메시지를 받습니다:

discourse의 main 브랜치에는 app/assets/javascripts/discourse/app/lib/plugin-api.gjs 경로가 포함되어 있지 않습니다.

2개의 좋아요

아, 그건 JavaScript 파일이 app/assets/javascripts/ 대신 frontend/ 디렉터리로 이동되었기 때문이에요.

PR을 열었습니다:

5개의 좋아요

이 PR을 다시 올립니다. 검토해 주실 수 있을까요? 감사합니다!

1개의 좋아요

12월에 병합되었습니다. :tada:

1개의 좋아요