如何在自定义主题/插件中安装 npm 包

你好!

是否可以在 Discourse 主题/插件中安装 npm 包(通过 package.json 或类似方式)?我们正在寻求在不同应用之间复用一些组件,如果无法实现,这将是一个阻碍。

谢谢!

你可以大致采用我们在核心部分的做法:通过 package.json 添加 npm 包,然后将 JS 文件复制到主题文件夹中(例如 javascripts/discourse/lib/)。不过,我认为无法直接从 node_modules 导入这些包,那样可能行不通。

假设我们有一段纯 JavaScript 代码(例如可以包含并运行以支持自定义 Web 组件的代码)就像这个,我该如何用你们的方法运行它?当我将其复制并粘贴到主题中的 discourse/lib 目录时,它无法正常工作。

我猜它无法工作是因为代码“没有在正确的时间被调用”?比如它没有在页面加载时或在浏览器环境中被调用。

此外,为了给大家提供上下文,如果我尝试使用 https://unpkg.com/ 并将其包含在头部,我会收到如下错误:

在回复评论并传达单一信息后,我按照 DISCOURSE_CDN_URL causes content security policy violations? 的指引解决了错误:

关闭 content_security_policy 设置

我仍在排查脚本为何无法正常工作,因为出现了另一个错误,但希望目前为止的解决步骤能对其他用户有所帮助。

附注:我遇到的错误如下:

不过脚本已经成功加载了 :man_shrugging:

最后,对于同一任务中的某人。我通过以下方式使其生效:

  1. 关闭 content_security_policy 设置
  2. 以编程方式显式添加脚本(不使用 $.getScript,也不使用其他方法)。

一个有效的示例摘要片段如下(请将 web-component 替换为适合您情况的组件):

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);
}

更好的方法是在“内容安全策略 script-src”站点设置或主题组件中将该特定 URL 加入白名单,详见 利用内容安全策略缓解 XSS 攻击

此外,您可以import loadScript from "discourse/lib/load-script";,然后使用该函数加载外部脚本(而不是自定义 addScript 注入器)。

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

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

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

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