在主题和组件中延迟加载JavaScript

感谢 @david,我们现在在主题中实现 JavaScript“急切”加载有了一个非常清晰的模式。

这意味着你只需将 *.js.es6 文件放入 javascripts 目录,其工作方式与插件完全一致,这太棒了。

例如,现在你可以通过以下方式创建一个初始化器,它与插件具有 100% 的兼容性:

  • 创建一个名为 /javascripts/discourse/initializers/my-init.js.es6 的文件
import { withPluginApi } from "discourse/lib/plugin-api";

function initialize(api) {
  // 在此处通过 api 进行初始化
}

export default {
  name: "discourse-otp",

  initialize() {
    withPluginApi("0.8.28", initialize);
  }
};

这是一个极其重要的功能,因为我们现在可以将大型复杂主题拆分成许多部分,并获得代码检查、语法高亮等所有便利功能。

然而,在某些情况下,我们可能希望可选地交付一个 JavaScript 负载。

例如,假设我们要装饰帖子,但仅限于具有非常特定 Markdown 格式的帖子。在我们确定需要使用之前,下载一个 100KB 的大型库是没有意义的。

我通过遵循以下巧妙的更改在我的组件中解决了这个问题:

https://github.com/discourse/discourse/commit/719a93c312b9caa6c71de22d67f1ce1a78c1c8b2

具体做法如下:

import loadScript from "discourse/lib/load-script";

function generateOtp($elem) {
  loadScript(settings.theme_uploads.jsotp).then(() => {
     // 此处放置相关代码
  });
}

这意味着:

  1. 我需要在“主题授权扩展名”中添加 .js
  2. 我需要在“内容安全策略 script src"中为特定资源添加 CSP 绕过。
  3. 我需要在 about.json 中命名该资源。

作为主题组件编写者,这带来了过多的摩擦,因为在分发竞争中,要求具备如此高水平的“忍者”技能是不现实的。

我认为要让这一功能真正可用,我们可以从以下两个方案中选择一个:

  1. 我们可以教导系统自动为活动主题中的 .js 资源配置 CSP,并默认允许主题上传 .js 文件。
  2. 我们可以转向类似 javascript_cache 的机制,供非延迟加载的主题 JavaScript 使用。

我倾向于方案 1,因为在主题授权扩展名中添加 .js 非常简单,而自动配置 CSP 也不应是不可能完成的任务。

@pmusaraj / @Johani / @Osama,你们对此有什么看法?

10 个赞

The ability to reference theme uploads in JS is a great addition! :100:

This makes a lot of sense to me because anything you can do in a .js file can already be done in files in the javascripts folder of the theme. So, I don’t see any harm in allowing themes to have .js uploads by default.

7 个赞

Reviving this because the only thing left here is to teach CSP to allow theme js uploads. js files have been default-allowed as theme uploads for a while now.

If theme js uploads are not blocked by CSP, then components like Image Annotator - Allows you to annotate images in the previewer won’t need to load their dependencies on the homepage (~170kb gzip). That component, for example, will only need to load those dependencies if the composer is opened. Plus, it never needs to load them to anon viewers.

Also, this change would “allow” themes to have web worker files that can do some heavy lifting off the main thread.

Allow in quotes above because you can have them as blobs, but it’s much nicer to have them in separate files instead of messing around with javascript in a string.

4 个赞

我这里有个好消息,实现起来有点棘手,但我们终于要支持本地 JS 资源了,这样就可以在主题组件中使用 Web Workers 了。

没有其他干净的方法可以通过 CSP 来实现这一点,从同一域提供 worker 文件可以解决这里巨大的漏洞。

3 个赞

注意… 这已经发布了 :confetti_ball:

5 个赞