How to load library in a theme component

from How to require external libraries in a component helper file? - #2 by merefield

Hey @merefield – Is this still how to do this?

I’m trying to pul in qrcode.js to generate a QRcode in the browser.

I’m getting blocked by CSP as well. I don’t understand how it’s a CSP problem if it’s on the same host. This is on a production server using discourse_theme to debug.

I’m putting this in an initializer:

import loadScript from "discourse/lib/load-script";
import { withPluginApi } from "discourse/lib/plugin-api";
// import QRCode from "discourse/lib/qrcode";
export default {
  name: "qrcode",
  ensureQRCode() {
    return loadScript(settings.theme_uploads.QRCode).then(() => {
      return loadScript(settings.theme_uploads.QRCode);
  initialize(container) {
    withPluginApi("0.8.7", (api) => {
      api.decorateCookedElement((cooked, postWidget) => {
        const placeholderNodes = cooked.querySelectorAll(
        // const qr = new QRCode(
        //   document.getElementById("qrcode"),
        //   ""
        // );

And it seems that the function doesn’t get called to load the script if I don’t call this.ensureQRCode();, which you don’t seem to be doing in your component.

The script is available and I can retrive it (so I got the stuff in the about.json and /assets/qrcode.js right), but the browser refuses to load it.


The result of your loadscript is a promise so you need to put your code relying on it in a .then block as per my example code


I don’t know if this is a similar thing (I suspect it isn’t) but holy smoly is it driving me nuts because this should be simple to do.

1 Like

Thanks very much!

But I thought I did that:

    return loadScript(settings.theme_uploads.QRCode).then(() => {
      return loadScript(settings.theme_uploads.QRCode);

I tried very hard to change your example as little as possible :slight_smile:

Maybe I need to use a .then when I’m trying to use the code later?

But that doesn’t solve the CSP issue, does it?



My two main advices are:

Put the library in the assets folder

This solves CSP, makes the theme self-contained and is considered a good practice, instead of loading it from third-parties.

Load it lazily

Only when needed, you can load it lazily using await loadScript. This means it won’t be loaded in pages where it isn’t needed, slowing your whole site.

A good example of a theme that follows those good practices is GitHub - discourse/discourse-mermaid-theme-component


Yes, precisely. :+1:. That’s how it works in my example.


One more question: What’s the difference between ...initializers/mycode.js and ...api-initializers/mycode.js?

And much thanks to both of you!!

That was a good example! I was able to make sense of it!

Well, I thought I followed your example. Javascript still seems like a twisty maze of passages that all look alike.