Skip to content

Add support for bfcache#40750

Open
GrimLink wants to merge 7 commits intomagento:2.4-developfrom
GrimLink:feature/add-support-for-bfcache
Open

Add support for bfcache#40750
GrimLink wants to merge 7 commits intomagento:2.4-developfrom
GrimLink:feature/add-support-for-bfcache

Conversation

@GrimLink
Copy link
Copy Markdown
Member

@GrimLink GrimLink commented Apr 20, 2026

This pull request makes Magento 2 storefront pages eligible for the browser Back/Forward Cache (BFCache). BFCache is one of the highest-impact performance optimisations available in modern browsers. When eligible, navigating back or forward restores a frozen snapshot of the page instantly, eliminating the network round-trip and re-render entirely. Google's Chrome data shows BFCache restores are on average 10x faster than a normal navigation. It improves Core Web Vitals scores (LCP, INP) and directly benefits conversion rates on pages users return to, such as product listings, PDPs, and the cart. Magento 2 is currently ineligible on all storefront pages due to two blockers: the Cache-Control: no-store response header and several JS components that leave interactive elements in a broken state on restore. This pull request removes both.

Description (*)

1. Cache-Control: no-store response header

PHP and Varnish VCL configurations set Cache-Control: no-store on all non-static frontend responses. Browsers treat no-store as an explicit opt-out from BFCache regardless of other headers. The fix replaces no-store, no-cache, must-revalidate, max-age=0 with no-cache, must-revalidate, max-age=0 in Framework\App\Response\Http::setNoCacheHeaders(), Magento_Cms 404 controller, and all four Varnish VCL versions (4, 5, 6, 7). The Varnish vcl_backend_response Hit-For-Pass conditions are simplified to remove the now-unreachable no-store checks and the dead Surrogate-Control condition (Magento never sets that header from PHP).

2. Stale JavaScript state on BFCache restore

When a page is restored from BFCache the browser fires a pageshow event with persisted: true. Without explicit handling, interactive UI state is frozen at the moment of navigation. A pageshow handler is added to each affected component:

  • lib/web/mage/menu.js — collapses open submenus and clears mobile nav open state
  • Magento_Checkout/js/view/minicart.js — closes the minicart dropdown and resets the addToCartCalls loading counter
  • Magento_Checkout/js/sidebar.js — re-enables the checkout button (disabled on click to prevent double-submit)
  • Magento_Customer/js/customer-data.js — re-runs the section staleness check (init()) so the cart counter, customer name, and other section-driven UI reflect changes made on other pages while this page was cached. Also reloads the page if the PHP-rendered login state does not match localStorage, which happens when the user logs in or out on another page while this one is cached.
  • Magento_Customer/js/customer-global-session-loader.js — re-runs the missing-firstname check on restore
  • Magento_Theme/js/view/messages.js — clears cookie and customerData flash messages
  • Magento_Catalog/js/catalog-add-to-cart.js — resets button text and removes the disabled class
  • Magento_Checkout/js/proceed-to-checkout.js — re-enables the proceed-to-checkout button
  • Magento_Customer/js/view/authentication-popup.js — resets the isLoading observable
  • Magento_Newsletter/js/newsletter-sign-up.js — re-enables the submit button
  • Magento_Review/js/submit-review.js — re-enables the submit button
  • Magento_Customer/js/addressValidation.js — re-enables the save address button
  • Magento_Multishipping/js/overview.js — hides the loading indicator and restores the Place Order button
  • adminhtml/Magento/backend/web/js/theme.js — recalculates menu scroll position, closes any open admin nav submenu and overlay, clears the search field active state, and hides stale loading popups

Related Pull Requests

Fixed Issues (if relevant)

  1. Fixes Registers an unload listener #38376

Manual testing scenarios (*)

  1. Open a storefront page and inspect the Cache-Control response header. Verify it contains no-cache, must-revalidate, max-age=0 and does not contain no-store.
  2. On a product page, click Add to Cart and immediately navigate away before the request completes. Hit back. Verify the button is re-enabled and shows the default label.
  3. Open the minicart dropdown, navigate to another page, then hit back. Verify the dropdown is closed on restore.
  4. Add a product to cart to trigger a success message, then navigate to another page and hit back. Verify the success message is not re-displayed.
  5. Log in, visit a category page, log out on another tab, then hit back. Verify the page reloads and shows the logged-out header state.
  6. Add an item to cart on one tab, then hit back on another tab with a BFCache-cached page. Verify the cart counter updates to reflect the new item.

Questions or comments

BFCache compatibility has already been implemented as third-party modules by two major ecosystem projects. Mage-OS includes it in https://github.com/mage-os/module-theme-optimization and Hyvä includes it in https://github.com/hyva-themes/magento2-theme-module.

Integrating these changes natively into Magento 2 core removes the need for those workarounds and makes all storefronts benefit by default.

Contribution checklist (*)

  • Pull request has a meaningful description of its purpose
  • All commits are accompanied by meaningful commit messages
  • All new or changed code is covered with unit/integration tests (if applicable)
  • README.md files for modified modules are updated and included in the pull request if any README.md predefined sections require an update
  • All automated tests passed successfully (all builds are green)

This allows the use of the bfcache
This makes sure any JS code gets reseted to the default state for a improved UX
This makes sure any JS code gets reseted to the default state for a improved UX
This checks for a invalid state and forces a reload.
While this could be done beter the core logic does not allow this, so instead we use the current logic and use a simple refresh to update the page state, simple but 100% efficient.
@m2-assistant
Copy link
Copy Markdown

m2-assistant Bot commented Apr 20, 2026

Hi @GrimLink. Thank you for your contribution!
Here are some useful tips on how you can test your changes using Magento test environment.
❗ Automated tests can be triggered manually with an appropriate comment:

  • @magento run all tests - run or re-run all required tests against the PR changes
  • @magento run <test-build(s)> - run or re-run specific test build(s)
    For example: @magento run Unit Tests

<test-build(s)> is a comma-separated list of build names.

Allowed build names are:
  1. Database Compare
  2. Functional Tests CE
  3. Functional Tests EE
  4. Functional Tests B2B
  5. Integration Tests
  6. Magento Health Index
  7. Sample Data Tests CE
  8. Sample Data Tests EE
  9. Sample Data Tests B2B
  10. Static Tests
  11. Unit Tests
  12. WebAPI Tests
  13. Semantic Version Checker

You can find more information about the builds here
ℹ️ Run only required test builds during development. Run all test builds before sending your pull request for review.


For more details, review the Code Contributions documentation.
Join Magento Community Engineering Slack and ask your questions in #github channel.

@ct-prd-pr-scan
Copy link
Copy Markdown

The security team has been informed about this pull request due to the presence of risky security keywords. For security vulnerability reports, please visit Adobe's vulnerability disclosure program on HackerOne or email psirt@adobe.com.

@GrimLink
Copy link
Copy Markdown
Member Author

@magento run all tests

@ct-prd-pr-scan
Copy link
Copy Markdown

The security team has been informed about this pull request due to the presence of risky security keywords. For security vulnerability reports, please visit Adobe's vulnerability disclosure program on HackerOne or email psirt@adobe.com.

@GrimLink
Copy link
Copy Markdown
Member Author

@magento run Functional Tests B2B, Functional Tests CE, Functional Tests EE

@GrimLink
Copy link
Copy Markdown
Member Author

@magento run all tests

@GrimLink
Copy link
Copy Markdown
Member Author

@magento run all tests

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Priority: P3 May be fixed according to the position in the backlog. Progress: pending review

Projects

Status: Pending Review

Development

Successfully merging this pull request may close these issues.

Registers an unload listener

2 participants