How to install npm packages in custom themes/plugins

Hello!

Is it possible to install npm packages (via package.json or similar) in Discourse Themes/Plugins? We are looking to reuse some components across apps and this can be a blocker if it’s not possible.

Thanks!

You could sorta do what we do in core, which is, add npm packages via package.json and then copy JS files to a theme folder (like javascripts/discourse/lib/ for example) but you can’t import the packages from node_modules directly, I don’t think that would work.

2 个赞

Assuming we have a plain Javascript code (Like something we can include and run to support a custom web component) like this one how I can run it with your approach? When I copy and paste it into discourse/lib within my theme it doesn’t work.

I assume it doesn’t work because the code is “not being called at the right time?” like is not being called when the page is loaded and within the browser environment.

Furthermore, to give context to everyone If I try to use the https://unpkg.com/ and include it into the header I get an error like:

After reply to the comment and convey the information in a single idea I get rid of the error by following DISCOURSE_CDN_URL causes content security policy violations?

Turning off content_security_policy setting

I still figure out why the script doesn’t work as I have another error but maybe so far can be useful for someone else.

FYI, the error I am having is this one:

But the script has loaded :man_shrugging:

Finally, for someone within the same quest. I make it work by:

  1. Turning off content_security_policy setting
  2. Explicitly adding the script programatically (not using $.getScript not using other approach).

A example summary snippet of what works for me is (replace web-component for what makes sense in your case):

import { withPluginApi } from "discourse/lib/plugin-api";

let flag = false;

export default {
  name: "web-component",
  initialize() {
    withPluginApi("0.8", api => {
      api.onAppEvent("page:changed", () => {
        if (flag) return;

        addScript(
          "https://unpkg.com/web-component@0.0.1/dist/web-component/web-component.js",
          { defer: "", crossorigin: "anonymous" }
        );

        addWebComponent(
          "web-component",
          {
            id: "web-component"
          },
          `Hello world`
        );

        flag = true;
      });
    });
  }
};

function addWebComponent(tag, attrs, content) {
  var component = document.createElement(tag);

  Object.keys(attrs).forEach(key => {
    component.setAttribute(key, attrs[key]);
  });
  component.textContent = content;

  document.body.appendChild(component);
}

function addScript(src, attrs) {
  var script = document.createElement("script");

  script.setAttribute("src", src);

  Object.keys(attrs).forEach(key => {
    script.setAttribute(key, attrs[key]);
  });

  document.body.appendChild(script);
}

1 个赞

The better way to do this is to whitelist that specific URL either in the content securty policy script src site setting or in your theme component, see Mitigate XSS Attacks with Content Security Policy for more details.

And also, you can import loadScript from "discourse/lib/load-script"; and then use that to load an external script (instead of defining your own addScript injector).

6 个赞

抱歉挖坟,但这是我能找到的最相关的帖子。
我正试图在插件中添加这个包。我想使用 import { RadixDappToolkit, RadixNetwork } from '@radixdlt/radix-dapp-toolkit' 来导入它。

它也可以通过 Yarn 使用,我认为这是 Discourse 使用的方式,但我认为我不能就这样把它添加为依赖项……可以吗?

我不确定是否也可以只使用 unpkg 加载它,因为它有很多依赖项。我有什么选择?任何提示都将不胜感激。

抱歉问题很宽泛,但我非常困惑。谢谢!