← back to Newmor Onboard

data/live-2026-09-09/theme/snippets/cpc-collection-guard.liquid

70 lines

{%- comment -%}
  cpc-collection-guard.liquid — Custom Price Calculator perf guard, SITE-WIDE.
  ------------------------------------------------------------------
  The Custom Price Calculator app (cdn-assets.custompricecalculator.com/shopify/calculator.js) spins up
  a throwaway WebGL fingerprint context PER PRODUCT CARD. On any page with a product grid — collection,
  search, home, AND product pages (their related / "pairs well with" carousels) — this floods past the
  browser's ~16-context limit, evicting live contexts ("Too many active WebGL contexts") and stalling the
  GPU, which makes rows visibly pop/stutter on scroll.

  Fix = CAP the calculator's WebGL contexts (not a blanket block):
    - Non-product (listing) pages: cap 0  → block the whole flood (no per-card price calc needed there).
    - Product pages:               cap 6  → the main price widget initializes normally (verified: price
      renders identically), while the related-grid flood beyond 6 is blocked. Stays well under ~16 → no stall.
  Plus a fetch de-dupe for the calculator's duplicate /calculator/app/pageurl config storm (all pages),
  and a reveal-softener that stops the Boost image reveal "pop" on listing grids. Fails open.

  Placement: {% render 'cpc-collection-guard' %} at the top of the normal storefront <head> in theme.liquid.
{%- endcomment -%}

{%- assign cpc_cap = 0 -%}
{%- if template contains 'product' -%}{%- assign cpc_cap = 6 -%}{%- endif -%}

{%- unless template contains 'product' -%}
  <style>
    .boost-sd__product-image-img,
    .boost-sd__product-image-img--main {
      transition: none !important;
      transform: none !important;
      animation: none !important;
    }
  </style>
{%- endunless -%}

<script>
(function () {
  var CAP = {{ cpc_cap }};
  try {
    var origGetContext = HTMLCanvasElement.prototype.getContext;
    var cpcCount = 0;
    HTMLCanvasElement.prototype.getContext = function (type) {
      if (String(type).indexOf('webgl') !== -1) {
        var stack = '';
        try { stack = (new Error()).stack || ''; } catch (e) {}
        if (stack.indexOf('custompricecalculator') !== -1) {
          cpcCount++;
          if (cpcCount > CAP) return null;   // block the per-card flood; allow the first CAP for the real widget
        }
      }
      return origGetContext.apply(this, arguments);
    };
  } catch (e) { /* fail open */ }

  try {
    var origFetch = window.fetch;
    var inflight = {};
    window.fetch = function (input) {
      var url = (typeof input === 'string') ? input : (input && input.url) || '';
      if (url.indexOf('custompricecalculator.com') !== -1 && url.indexOf('/calculator/app/pageurl') !== -1) {
        if (inflight[url]) return inflight[url].then(function (r) { return r.clone(); });
        var pr = origFetch.apply(this, arguments);
        inflight[url] = pr;
        if (pr && pr.finally) pr.finally(function () { setTimeout(function () { delete inflight[url]; }, 5000); });
        return pr;
      }
      return origFetch.apply(this, arguments);
    };
  } catch (e) { /* fail open */ }
})();
</script>