Javascript assets in a theme component

I’m trying to build an STL preview theme component. There is an excellent javascript library for this, but I’m not sure how to make it work in a theme component.

It’s regular javascript, not es6, which I think means I can’t just stick it in the “javascripts” directory and import it, right? Besides, the library seem to rely on being imported from a script tag.

So I can create a script tag and add it to the document head, but how do I find the name of the library js file? Also, the library is made up of several JS files, and it assumes that those files will be available in the same directory. It goes on to create additional script tags to load the rest of the library.

So, should these files go in the javascripts directory? Or should they be treated as assets? The closest thing I can find to doing something similar is the discourse-math plugin, but if possible I would prefer to keep this as a theme component…

This seems to show how to do it for a plugin: How to ship javascript library with plugin?
Still haven’t found anything for a theme component.

I don’t know, but you don’t have any good answers!

The next thing to look at is the…thing…about including other files in the theme component.

I think some of the big theme components are where to look. Basically, I think, the file structure is the theme component is the same and ember will just load those theme files same as a plugin.

I don’t think so, each component gets it’s own virtual directory I think. Something like discourse/theme-10/… So to load stuff from there I have to at least know what the directory is somehow.

1 Like

Assets names seem to only be accessible as variables, and the real names are long and complicated numbers, so that won’t work either.
It kind of seems like there is no way to do this as a component right now, so I’m going to sideload the JS files through nginx and access them that way for now. Probably means this component will only work for me unfortunately.

You can add the normal script tag to the header.html file inside your theme component.

sideloading works!
Once. :frowning:

If I navigate to another topic and back to the topic with the STL in it, then it doesn’t work. I’m not sure why because there is no error in the javascript console. I saw a thread somewhere earlier that talked about onload weirdness, and given that these scripts use onload, maybe it’s related?

True, but viewstl code isn’t meant to be inlined.
With the sideloading I put a script tag like this in common/head_tag.html:

<script src="/xi/viewstl/stl_viewer.min.js"></script>

(/xi/ is served from nginx)

Discourse is a SPA. You can’t just slap a script that now on the onLoad as that won’t work. You will need to hook into our API endpoints. Check Developer’s guide to Discourse Themes

Alrighty then, I’m going to have a go at replacing the crufty script-tag-based loading with something else then.

I have now read this page several times, but I still can’t make it work.
I’m trying to load three.js with import statements, but it seems regardless of what I do, it complains that it can’t find the import. The weird part is that I can import other files just fine, and the error message is entirely unhelpful.

Anyways, here is what I get, maybe someone can help:

Here is the import that doesn’t work:

And here is the error I get:

_application-547e0be66174ffd22a4d74fd8b568f6a3892a266cff18cb078c08d6357227acb.js:74333 An error occurred in the "STL previews" theme/component: Error: Could not find module `discourse/theme-17/three/build/three.module` imported from `discourse/theme-17/stlviewer/StlViewer`
    at h (_ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:74612)
    at _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:74581
    at _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:74665
    at _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:74490
    at require (_ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:74663)
    at h (_ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:74616)
    at _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:74581
    at _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:74665
    at _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:74490
    at require (_ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:74663)
(anonymous) @ _application-547e0be66174ffd22a4d74fd8b568f6a3892a266cff18cb078c08d6357227acb.js:74333
u @ _application-547e0be66174ffd22a4d74fd8b568f6a3892a266cff18cb078c08d6357227acb.js:74325
initialize @ _application-547e0be66174ffd22a4d74fd8b568f6a3892a266cff18cb078c08d6357227acb.js:74304
i.initialize @ _application-547e0be66174ffd22a4d74fd8b568f6a3892a266cff18cb078c08d6357227acb.js:7723
(anonymous) @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:49335
e.each @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:67724
e.walk @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:67638
e.each @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:67568
e.topsort @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:67576
_runInitializer @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:49361
runInitializers @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:49333
_bootSync @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:47768
domReady @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:47668
n._run @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:67275
n._join @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:67251
n.join @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:66968
f @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:53760
(anonymous) @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:53864
l @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:3776
c @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:3844
setTimeout (async)
(anonymous) @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:3882
u @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:3510
fireWith @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:3640
fire @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:3648
u @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:3510
fireWith @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:3640
ready @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:4120
z @ _ember_jquery-36a23101c869ab0dc53fc908de69adb785731593573d32bdeef416acc1076ef4.js:4130

Is ‘.’ a magical module separator or something?

I guess ‘.’ is magical, because when I rename three.module.js to three_module.js, I get a completely different problem: I can’t load the theme anymore. (500 error)

I’ve also tried importing three.js directly from a CDN with a full url, and that doesn’t seem to work either…

If you just need Just In Time loading of a javascript asset, like I do here where I require a D3 library, you can use this pattern with Loadscript:

and further up:

Loadscript returns a Promise, so you have to perform a .then on the result. (I’m not certain, but assume the result is implicitly cached, so will run faster second time etc.)

As you can see, you can string them together to load several scripts one after the other.

Note that it’s running inside an Ember Component and is fired off the didInsertElement hook. Learn more about Ember Components here: Templates are HTML - Components - Ember Guides

Note also the script themselves are housed in javacsripts/assets directory.

I based this on @joffreyjaffeux’s code somewhere used to load in a completely different script (thanks Joffrey! :+1: )

Here’s a Discourse example:

Tip: always dig through the Official and Pavilion TCs and Plugins that are doing something similar to see how they achieve things :).


Interesting, thanks for the pointers.
I will try using loadScript and see if that can solve my problem.


I decided to try a simpler approach.
I just create an iframe which loads an HTML page which can do all the ugly script things to make the preview work. Right now it’s not in a re-usable format, but it would be relatively simple to create a plugin for it.