I got a few questions regarding plugin-outlet
, custom-html
, appEvents
in mount-widget.js
and ES6.
I’ve included some code snippets, and that’s why this post looks too long. It’s code from Discourse source code, not mine. So, it’s guaranteed that you won’t be reading my (hard-to-read) code.
While trying to read Discourse code, I wanted to try ‘something’ and created my own Rails project and created javascripts/something.js.es6
and javascripts/something-else.js
. And imported them in application.html.erb
with:
<%= javascript_include_tag 'something-else' %> # loads
<%= javascript_include_tag 'something' %> # Throws error
And apparently, .es6
throws error. After some googling, I’ve discovered that I could use the babel-transpiler
gem, but in the Discourse Gemfile, I don’t see babel-tranpiler
gem being used. Googling “discourse es6” gives me:
https://meta.discourse.org/t/new-es6-features-via-babeljs/24920
which links to this commit. The Gemfile says it uses 6to5
but I don’t see that either in my Discourse folder.
How do you use ES6 in Discourse?
plugin-outlet
.
It seems like the plugin-outlet uses data stored in Ember.TEMPLATES
to ‘findOutlets’:
// app/assets/javascripts/discourse/lib/plugin-connectors.js.es6
function buildConnectorCache() {
_connectorCache = {};
findOutlets(Ember.TEMPLATES, (outletName, resource, uniqueName) => {
_connectorCache[outletName] = _connectorCache[outletName] || [];
_connectorCache[outletName].push({
templateName: resource.replace("javascripts/", ""),
template: Ember.TEMPLATES[resource],
classNames: `${outletName}-outlet ${uniqueName}`,
connectorClass: findClass(outletName, uniqueName)
});
});
}
But I can’t find where and how Ember.TEMPLATES
is defined. TEMPLATES
doesn’t seem like a Ember thing.
I did notice that I could prompt Ember.TEMPLATES
on my Discourse instance, and it contains many entries, more than 450 on my instance. All entries seem like “template” files.
The only occurrence where I see it being defined is:
# lib/theme_javascript_compiler.rb
# TODO Error handling for handlebars templates
def append_ember_template(name, hbs_template)
name = name.inspect
compiled = EmberTemplatePrecompiler.new(@theme_id).compile(hbs_template)
content << <<~JS
(function() {
if ('Ember' in window) {
Ember.TEMPLATES[#{name}] = Ember.HTMLBars.template(#{compiled});
}
})();
JS
rescue Barber::PrecompilerError => e
raise CompileError.new e.instance_variable_get(:@error) # e.message contains the entire template, which could be very long
end
but this function was used in:
# app/models/theme_field.rb
def process_html(html)
...
doc.css('script[type="text/x-handlebars"]').each do |node|
name = node["name"] || node["data-template-name"] || "broken"
is_raw = name =~ /\.raw$/
hbs_template = node.inner_html
begin
if is_raw
js_compiler.append_raw_template(name, hbs_template)
else
js_compiler.append_ember_template(name, hbs_template)
end
Here, I didn’t bother to read more because the file was under app/models/
that I thought this had something to do with the database.
Is there a function that searches for the template files and assigns to Ember.TEMPLATES
? And in which file?
Regarding custom-html
… I’m getting these questions from trying to read the application.hbs
by the way.
// app/assets/javascripts/discourse/components/custom-html.js.es6
import { getCustomHTML } from "discourse/helpers/custom-html";
...
export default Ember.Component.extend({
...
init() {
...
const html = getCustomHTML(name);
// app/assets/javascripts/discourse/helpers/custom-html.js.es6
let _customizations = {};
export function getCustomHTML(key) {
const c = _customizations[key];
if (c) {
return new Handlebars.SafeString(c);
}
...
// Set a fragment of HTML by key. It can then be looked up with `getCustomHTML(key)`.
export function setCustomHTML(key, html) {
_customizations[key] = html;
}
In this case VSCode search gives me that setCustomHTML
isn’t used elsewhere besides the test file.
How is the _customizations
filled? Or is this because I’m not using any “custom-html”?
Came up with the question while trying to read site-header
component.
appEvents
. I’ve seen:
// app/assets/javascripts/discourse/components/mount-widget.js.es6
dispatch(eventName, key) {
this._childEvents.push(eventName);
const caller = refreshArg =>
this.eventDispatched(eventName, key, refreshArg);
this._dispatched.push([eventName, caller]);
this.appEvents.on(eventName, caller);
},
And many appEvents.on
and appEvents.off
lines in other files as well. But how is this.appEvents
‘injected’ into mount-widget
?
I’ve only discovered it defined:
// app/assets/javascripts/discourse/widgets/widget.js.es6
export default class Widget {
constructor(attrs, register, opts) {
...
this.appEvents = register.lookup("app-events:main");
and what I’ve discovered, mount-widget
has connection to the Widget class in widget.js
only through:
rerenderWidget() {
...
const newTree = new this._widgetClass(args, this.register, opts);
So, in summary "how does app/assets/javascripts/discourse/components/site-header.js.es6
use this.appEvents
? I don’t see it defined as a property for site-header
"
I’m sorry if the question looks too big, but I thought this would help you understand my confusion.