Hello,
I was trying to optimize my site and I’m reporting to you with the help of AI the problem I discovered :
BRFPANEL localised twice — identical ~107 KB payload duplicated in frontend HTML
Bricksforge 3.1.8.7 · includes/Frontend.php:596-597
Summary
On the frontend, Bricksforge emits its entire BRFPANEL payload twice. The same
$args array is localised to two different handles that both load on the frontend:
// includes/Frontend.php:596-597
wp_localize_script('bricksforge-panel', 'BRFPANEL', $args);
wp_localize_script('bricksforge-node-editor', 'BRFPANEL', $args);
On our homepage that is 107,421 characters of JSON printed twice. With
Perfmatters’ “defer inline JavaScript” converting inline scripts to base64 data
URIs, each copy becomes ~143 KB of HTML, so the duplicate costs ~143 KB of raw
HTML per page view.
Because bricksforge-node-editor already declares bricksforge-panel as a
dependency (includes/Assets.php:201-205), the BRFPANEL global is guaranteed to
be defined before bricksforge_nodes_editor.js executes. The second localisation
therefore appears redundant.
Environment
| Bricksforge | 3.1.8.7 |
| Bricks | 2.3.10 (child theme active) |
| WordPress | 7.0.2 |
| PHP | 8.5.6 |
| Server | LiteSpeed (OpenLiteSpeed 1.8.4) |
| Active Bricksforge tools | Element Conditions, Bricksforge Panel, Scroll Smoother, Email Designer, API Query Builder (ids 2, 6, 7, 13, 18) |
| Other relevant plugins | Perfmatters 2.6.6, LiteSpeed Cache 7.8.1, BricksExtras 1.7.2, Advanced Themer 3.3.15 |
includes/Frontend.php sha1 |
b21fec051c4cf4215b667338c8f0d8525a9dca65 |
Note: “Animation Controls” is not among our activated tools — the payload is
still emitted twice because the timelines path runs regardless.
Evidence
Both blocks were extracted from the live page and decoded. They are byte-for-byte
identical except the trailing sourceURL comment WordPress appends:
blob A: 107,478 chars → ends "...}};\n//# sourceURL=bricksforge-panel-js-extra"
blob B: 107,484 chars → ends "...}};\n//# sourceURL=bricksforge-node-editor-js-extra"
first divergence at character 107,464 — i.e. only inside that comment
Payload composition (identical in both):
| Key | Bytes |
|---|---|
panelNodes |
90,269 |
panel |
16,373 |
| everything else | ~265 |
| total | 106,907 |
Impact measured on our site
Homepage, before and after suppressing the second copy:
| Before | After | Saved | |
|---|---|---|---|
| Raw HTML | 1,528,011 B | 1,384,604 B | −143,407 B |
| gzip (as served) | 295,882 B | 256,529 B | −39,353 B (−13%) |
| brotli | 182,006 B | 181,823 B | −183 B |
The gzip figure is the meaningful one for anyone not serving brotli: gzip’s 32 KB
window cannot reach back far enough to dedupe a 143 KB repeat, so the duplicate
costs real transfer bytes. Brotli’s larger window collapses it almost entirely,
which is presumably why this has gone unnoticed on brotli-enabled hosts.
Workaround we are using
A wp_enqueue_scripts hook at PHP_INT_MAX that drops the node-editor copy, but
only when it is provably safe:
add_action('wp_enqueue_scripts', function () {
if (is_admin()) return;
if (function_exists('bricks_is_builder') && bricks_is_builder()) return;
global $wp_scripts;
if (!($wp_scripts instanceof WP_Scripts)) return;
$node = $wp_scripts->registered['bricksforge-node-editor'] ?? null;
$panel = $wp_scripts->registered['bricksforge-panel'] ?? null;
if (!$node || !$panel) return;
// both must carry the same global, and the dependency must guarantee ordering
if (strpos($node->extra['data'] ?? '', 'var BRFPANEL') === false) return;
if (strpos($panel->extra['data'] ?? '', 'var BRFPANEL') === false) return;
if (!in_array('bricksforge-panel', (array) $node->deps, true)) return;
unset($wp_scripts->registered['bricksforge-node-editor']->extra['data']);
}, PHP_INT_MAX);
Verification that nothing broke
Compared against an unmodified control site, with the workaround active:
window.BRFPANELstill exposes all 7 keys (ajaxNonce,ajaxurl,postId,
panel,panelNodes,panelActivated,activeTemplate)BRFPANEL.panelNodesstill holds its 14 entries;BRFPANEL.panelstill length 1- GSAP reports 92 tweens on both — identical
ScrollTrigger/SplitTextpresent on both; zero console errorsbricksforge_panel.jsandbricksforge_nodes_editor.jsboth still load- Our header GSAP menu animation behaves identically
Suggested fix
If bricksforge_nodes_editor.js genuinely only reads the global (rather than
needing its own -js-extra block), the second call can simply be dropped — the
dependency already guarantees ordering.
If a belt-and-braces guarantee is preferred, an alternative is to localise onto the
lowest handle in the dependency chain only, or to register a tiny shared
bricksforge-data handle that both scripts depend on and localise once onto that.
Either way the frontend payload halves.
Aside — a related opportunity
panelNodes alone is 90 KB of the 107 KB, and is emitted in full on every frontend
page. If timelines/nodes can be filtered to those actually referenced by the
rendered page (the timelines path already supports a per-post “load on” restriction),
that would be a further substantial reduction. Entirely separate from the
duplication bug, but in the same area of the code.
Thank you for reading. Please let me know if you can improve this based on what the AI suggests ![]()
Kind regards,
Barnabas