Tecnoblog 使用 Discourse 评论系统的体验

你好!

我对这个新功能感到非常兴奋。我期待像这样的解决方案已经很久了,我们 Tecnoblog 的读者给出的初步反馈也非常棒——他们非常喜欢社区集成。

然而,经过一些实际测试,我发现了一些技术障碍,我们需要克服这些障碍,才能让这个系统感觉像一个真正的原生评论系统,更重要的是,让它能够适应高流量网站的需求。

以下是我目前的发现:

1. 性能与服务器负载

嵌入完整应用后,我们的服务器负载显著增加。查看 Cloudflare 数据,我们的请求量增加了 10 倍。以下是一些优化建议:

  • 懒加载: 对 JS 实现懒加载有很大帮助(我已经在使用一个变通方法)。
            <script type="text/javascript">
                DiscourseEmbed = {
                    discourseUrl: '<?php echo esc_url($discourse_url); ?>',
                    
                    <?php if ($use_topic_id): ?>
                        // ID 模式:主题保存在数据库中,不受 URL 变化影响
                        topicId: <?php echo intval($topic_id); ?>,
                    <?php else: ?>
                        // URL 模式:当通过 API 创建失败时的后备方案
                        discourseEmbedUrl: '<?php echo esc_url($permalink); ?>',
                    <?php endif; ?>
                    fullApp: true,
                    embedHeight: '800px',
                };

                (function() {
                    var container = document.getElementById('discourse-comments');

                    // 检查浏览器是否支持 IntersectionObserver
                    if ('IntersectionObserver' in window) {
                        var observer = new IntersectionObserver(function(entries, observer) {
                            entries.forEach(function(entry) {
                                if (entry.isIntersecting) {
                                    // 当 div 进入屏幕时加载脚本
                                    loadDiscourse();
                                    observer.unobserve(entry.target);
                                }
                            });
                        }, { rootMargin: "1500px" }); // 在到达 div 前 1500px 时加载

                        observer.observe(container);
                    } else {
                        // 旧浏览器的后备方案
                        loadDiscourse();
                    }

                    function loadDiscourse() {
                        var d = document.createElement('script'); 
                        d.type = 'text/javascript'; 
                        d.async = true;
                        d.src = window.DiscourseEmbed.discourseUrl + 'javascripts/embed.js';
                        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(d);
                    }
                })();
            </script>

在这里你可以看到实现懒加载后请求数量下降的情况(网站的部分内容仍然被缓存,所以这不是最终结果):

  • 精简负载: 我们能否减少嵌入内容中加载的资源?例如,我注意到有对聊天 URL 和 AI 积分检查的查询——这些在嵌入视图中是必需的吗?

  • 请求频率: 实时 POST 请求有点过于频繁。也许我们可以降低嵌入版本的轮询频率?

  • 缓存: 改进嵌入主题的缓存管理,以应对流量高峰。

2. 分析数据混乱

目前,嵌入内容正在触发 Google Analytics/GTM 脚本。这导致我们的页面浏览量翻倍(一次点击对应帖子,另一次对应 iframe),从而扰乱了我们的数据。理想情况下,系统应该能够检测到它处于 iframe 中,并自动禁用所有跟踪脚本(包括 Discourse 的分析脚本)。

3. iframe 高度问题

这可能是用户体验方面最大的障碍。如果帖子没有评论,会出现一个奇怪的空白区域。如果有一个长线程,iframe 会在前 2 或 3 条评论处被截断,迫使用户“滚动中滚动”,这在移动设备上尤其糟糕。

要真正与 Disqus 等产品竞争,我们需要高度是动态的(根据评论数量调整),并且还需要一个“加载更多”按钮,在达到一定数量的回复后展开线程。

4. 插件冲突

由于嵌入内容会加载所有活动的插件,我们遇到了一些奇怪的行为。例如,“Google One Tap”会在博客帖子中弹出。当用户登录时,iframe 会刷新并将他们带到社区主页,而不是评论线程。能够手动禁用嵌入视图中的特定插件将是一个巨大的帮助。

5. 登录摩擦

当前的流程有点影响转化率:用户点击登录 → 打开新标签页 → 登录完成 → 用户留在社区主页。回到博客帖子时,iframe 仍然显示未登录状态,直到用户手动刷新整个页面。这是一个令人困惑的循环,导致人们在评论前放弃并离开。

自从启用新的嵌入功能以来,我们的每日注册量增加了两倍多,这很好。然而,我们的参与度指标没有任何变化。事实上,我们的DAU/MAU 下降了——我们有更多登录用户,但他们没有互动。像“每日活跃用户”、“新贡献者”和“发帖数”这样的指标都没有增加。

这证明了人们想要参与讨论,但他们在登录循环中迷失了方向,在真正发表评论之前就放弃了帖子。

6. 移动 UI

在移动设备上,回复窗口占据了整个屏幕,因此你会失去正在回复的对话的所有上下文。感觉有点压抑——任何能让它更紧凑的改进都会是一个巨大的胜利。


我真的很希望将这个系统作为 Tecnoblog(以及我们拥有的另一个网站)的默认系统。如果你希望深入探讨其中任何一点,请告诉我!

14 个赞

这将在

中得到修复。

11 个赞

感谢 @Thiago_Mobilon 提供的详细反馈!

我会处理这个清单,并争取最终覆盖所有内容。

我刚刚在这里检查了一下,看起来你的 Discourse 站点上的 CSS 配置有误。你有重复的 cache-control 标头,其中一个设置为 no-cache

curl -v https://tecnoblog.net/comunidade/stylesheets/common_cd45efa28175431b0b8ff143783178d55206920b.css?__ws=tecnoblog.net -s 2>&1 | grep cache-control
< cache-control: max-age=31556952, public, immutable
< cache-control: no-store, no-cache, must-revalidate, private
9 个赞

你使用的是 Discourse 内置的 Google Analytics 集成吗?

8 个赞

在以下 PR 中处理这些:

9 个赞

已在

UX: Support dynamic iframe height for full app embed mode - Pull Request #39297 - discourse/discourse - GitHub 中处理

11 个赞

我认为 Cloudflare 添加该标头是因为我为 /comunidade/ 目录绕过了缓存。如果不将其移除,Cloudflare 将会对 Discourse 的 CSS 和 JS 应用其缓存规则,这可能会在后续引发冲突。

无论如何,我提出缓存问题主要是为了降低服务器负载。CSS 文件是静态的,对吧?如果是这样,它们未被缓存虽然不理想,但不会直接增加服务器负载。

5 个赞

我正在使用 Discourse 与 Google Tag Manager 的集成。

4 个赞

它们会影响终端用户的性能,因为每篇文章都需要发出 59 个请求来下载 1.43MB 的 CSS(压缩后为 340KB)。

此外,它们也是由 Ruby 服务器提供的,因为我们期望网站不会破坏缓存,这意味着在正常情况下,这条路由很少被使用。

如果我没记错的话,提供缓存失效的文件甚至会导致它们访问数据库。

4 个赞

这个想法很棒,我正在添加原生支持。

11 个赞

这是一个在移动设备上撰写内容时更普遍的问题,将受益于 Creating/Editing a post on mobile: let's discuss the 2026 Discourse experience 中提到的改进。

8 个赞

我们为访问主题页面的匿名用户提供了出色的缓存机制,并且也支持这种新模式。因此,只要配备足够的 Pitchfork 工作进程和 Redis I/O 工作进程,您就能很好地扩展系统以应对流量高峰。

5 个赞

轮询机制会在后台标签页或高负载情况下自动降低频率,这里也应该适用同样的逻辑。

5 个赞

已同意标记这些内容

8 个赞

我在让动态高度功能正常工作方面遇到了一些困难。尽管我已经更新了 Discourse 并刷新了我的代码片段以应用最新配置,但问题仍然存在。

        <h4 class="comments-main-title component-title">评论</h4>
        <div id='discourse-comments'></div>

        <meta name='discourse-username' content='<?php echo esc_attr($discourse_author); ?>'>

        <script type="text/javascript">
            DiscourseEmbed = {
                discourseUrl: '<?php echo esc_url($discourse_url); ?>',
                
                <?php if ($use_topic_id): ?>
                    // ID 模式:主题保存在数据库中,不受 URL 变化影响
                    topicId: <?php echo intval($topic_id); ?>,
                <?php else: ?>
                    // URL 模式:当通过 API 创建失败时的备用方案
                    discourseEmbedUrl: '<?php echo esc_url($permalink); ?>',
                <?php endif; ?>
                fullApp: true,
                lazyLoad: true, // 禁用 iframe 的延迟加载
                lazyLoadMargin: '1500', // 开始加载前距离视口的像素数
                dynamicHeight: true,
                embedMinHeight: '400',
                embedMaxHeight: '3000',
					  embedHeight: '800px',
                // className: 'CLASS_NAME',
            };

            (function() {
            var d = document.createElement('script'); d.type = 'text/javascript'; d.async = true;
            d.src = DiscourseEmbed.discourseUrl + 'javascripts/embed.js';
            (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(d);
            })();
        </script>
4 个赞

我们可以在这里使用 <iframe loading="lazy"> 吗?这样就不需要自定义 JS 或 Intersection Observer 了?

4 个赞

哦,现在大多数浏览器都广泛支持这个功能了吗?长知识了!我会尽快修改。

8 个赞

感谢测试,已发现问题

5 个赞

太棒了!动态高度现在按预期工作了。然而,这引入了一个小问题:当我点击回复时,回复输入框试图调整到 iframe 的高度。在这种情况下,它错误地变成了 7385px 的高度。

该帖子包含 31 条评论,嵌入的 iframe 高度为 9757px(我将 embedMaxHeight 设置为 15000px)。

更新:我实际上注意到评论表单将 iframe 的高度扩展到最大值,因此当我点击“放弃”时,布局在评论下方留下了巨大的空白区域。

Screenshot 2026-04-16 at 16.03.37

5 个赞

我想你需要在那里设置一个更合理的 max-height 值,比如 1000 到 1500px。

这样这个功能就能解决你最初的问题:

并且可以扩展到一定程度,但考虑到 Discourse 原生的无限滚动行为,你并不希望高度增加太多。

这个功能短期内不会解决“滚动中嵌套滚动”的问题。

至于移动端的编辑器,我正在研究我们能做些什么。

6 个赞