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() {
    window.console.log(settings.theme_uploads.QRCode);
    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(
          ".d-wrap[data-wrap=qrcode]"
        );
        this.ensureQRCode();
        // const qr = new QRCode(
        //   document.getElementById("qrcode"),
        //   "http://jindo.dev.naver.com/collie"
        // );
...

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.

2 Likes

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

3 Likes

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?

image

2 Likes

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

6 Likes

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

3 Likes

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.

3 Likes