Page profiler never stores above-the-fold background images: `b` is always sent with empty selector maps

未关闭 适合新手
#1,216 0 条评论 0 个 reaction 已指派 1 人 在 GitHub 查看

维护者通常 1 天内回复

@girishpanchal30 已经在做这个了。

开始于 2026年11月6日。

评估

难度
2/5
预计耗时
1-3 小时
新手友好度
77/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
javascript
领域
performance

调研方向

阅读 assets/js/modules/main.js 第 110–139 行附近的代码,并结合 assets/js/modules/image-detector.js 第 82–104 行附近的 observer 回调。启用背景懒加载并使用 ?optml_debug=1 重现问题,然后检查背景选择器的 payload。完成标准是:每种设备的首屏背景元素及其 URL 均已存储,并具有相应的懒加载排除项。

由索引模型根据 Issue 内容生成。

描述

bug
Description

On a normal page visit, the page profiler sends every background selector with an empty object, for example "b":{"[style*=\"background-image:url(\"]":{}}. This happens even when a background element is above the fold and its URL has been found. The stored profile ends up with "bg":{"<selector>":[]} for every device. Optimole therefore never learns which background images are above the fold, and the lazy-load CSS can only exempt the LCP background.

Cause

In assets/js/modules/main.js, the IntersectionObserver is created with the first selectorMap instance. Shortly after, selectorMap is replaced with a new Map:

// main.js:110-111
let selectorMap = new Map();
const observer = optmlImageDetector.createIntersectionObserver(aboveTheFoldImages, selectorMap);
...
// main.js:135
selectorMap = backgroundResult.selectorMap;

The observer callback (image-detector.js:100) checks selectorMap.has(baseSelector) against the original Map, which is always empty. Above-the-fold background elements are therefore never recorded. Meanwhile _processBackgroundSelectors (main.js:174) builds b from the new Map, which has the selector keys but no entries. With ?optml_debug=1, the log never prints Element with selector "…" is above the fold for background elements.

Expected: each matched selector lists the above-the-fold elements and their URLs, e.g. {"[style*=\"background-image:url(\"]":{"#content > … > div.wp-block-cover__image-background…":["https://…/qa-hero-bg.jpg"]}}.

Verification of the cause

I changed one line in the served script so it fills the existing Map instead of replacing it (backgroundResult.selectorMap.forEach((v, k) => selectorMap.set(k, v))). With that change:

  • The payload contained the selector and its URL.
  • The server stored them for mobile and desktop.
  • The lazy-load CSS on the page added a :not(...) exclusion for each above-the-fold background element, not only the LCP one.

I tested this on a page with two background groups side by side.

Impact

On pages with a single hero, nothing visible changes, because the hero is also the LCP element and is exempted and preloaded anyway. On pages with several background images above the fold, the ones that aren't the LCP element are still lazy-loaded. They can appear late and cost LCP/CLS points, which is what the profiler is meant to prevent.

Possible fix

Fill the existing Map, or pass the Map from processBackgroundSelectors to the observer, instead of reassigning selectorMap.

A related timing detail: extractBackgroundImageUrls runs right after processBackgroundSelectors (main.js:139), before the 300/600 ms wait. A background that gets optml-bg-lazyloaded during the wait would be sent with null URLs.

Not related to #1204 / #1214: it appears on both the released 4.2.17 build and the #1214 build. Found while testing #1204.

Step-by-step reproduction instructions
  1. Optimole 4.2.17, connected, with Lazy load and background lazy load on.
  2. Create a page whose first block has a background image in an inline style. For example, a Cover block with "Fixed background" on, or a Group block with a background image.
  3. In a private window (logged out), open the page with ?optml_debug=1 appended. Keep the console open.
  4. In the console, look at Sending background selectors:. Or look at the payload of the request to /wp-json/optml/v1/optimizations.
  5. Load the page in a mobile-width window too, so both devices are profiled. Then open it with ?optml_debug=true and read the <!-- plugin=optimole-wp measurement#… --> comment after </html>.

Result: b contains each matched selector with {}, and the stored profile shows "bg":{"…":[]} for both devices. Only the LCP background (lcp.bgUrls) is stored.

Screenshots, screen recording, code snippet or Help Scout ticket

Code links:
https://github.com/Codeinwp/optimole-wp/blob/v4.2.17/assets/js/modules/main.js#L110-L135
https://github.com/Codeinwp/optimole-wp/blob/v4.2.17/assets/js/modules/image-detector.js#L82-L104

Environment info

Optimole 4.2.17 (same code on master), WordPress + Neve, PHP 8.5, Chromium desktop 1440px / mobile 390px

Is the issue you are reporting a regression

No

主要语言
PHP
星标
74
派生
14
平均合并
1 天 20 小时
30 天内合并 PR
39

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

Codeinwp/optimole-wp 的其他 Issue

查看 Codeinwp/optimole-wp 的全部 Issue

相似的 Issue

更多 PHP Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。