June 17, 2026
cd7d0f3d0d3319fe3c0f1133fc57743d6d56a6f3ba557474e74be7258450b4e9 Previous:
c3591477 Bundle: 90.4 KB MobileBridgeNext safe area insets now inject styles via Constructable Stylesheets instead of a style element.
Highlights
- MobileBridgeNext now injects safe area inset styles using the Constructable Stylesheets API and document.adoptedStyleSheets instead of appending a style element to document.head.
- Safe area inset style injection now includes feature detection and exits gracefully if CSSStyleSheet or adoptedStyleSheets APIs are unavailable.
- The function for intercepting native browser APIs was renamed from restoreProperty to interceptProperty, affecting the fetch, print, share, window.open, and history modules.
Infrastructure Changes
REPORT.md +4 -4
@@ -1,12 +1,12 @@
# Shopify App Bridge — Unminification Report
Generated: 2026-06-05T09:03:20.567Z
Generated: 2026-06-17T09:31:45.467Z
## Files
| File | Size | Lines | Type |
|------|------|-------|------|
| _bootstrap.js | 29.2KB | 1013 | Infrastructure |
| _bootstrap.js | 29.5KB | 1028 | Infrastructure |
| _remote-ui.js | 6.0KB | 255 | Infrastructure |
| _utilities.js | 72.9KB | 2721 | Infrastructure |
| _web-vitals.js | 11.6KB | 527 | Infrastructure |
@@ -24,7 +24,7 @@ Generated: 2026-06-05T09:03:20.567Z
| picker.js | 451B | 18 | Module |
| polaris.js | 240B | 12 | Module |
| pos.js | 5.7KB | 248 | Module |
| print.js | 573B | 25 | Module |
| print.js | 575B | 25 | Module |
| resource-picker.js | 2.8KB | 119 | Module |
| reviews.js | 365B | 16 | Module |
| s-app-nav.js | 175B | 10 | Module |
@@ -46,7 +46,7 @@ Generated: 2026-06-05T09:03:20.567Z
| user.js | 940B | 37 | Module |
| visibility.js | 973B | 34 | Module |
| web-vitals.js | 1.8KB | 64 | Module |
| **Total** | **171.9KB** | **6526** | |
| **Total** | **172.2KB** | **6541** | |
## Pipeline Stages
modules/_bootstrap.js +27 -12
@@ -168,7 +168,7 @@
removeEventListener: globalThis.removeEventListener.bind(globalThis),
postMessage: globalThis.parent.postMessage.bind(globalThis.parent),
});
const c = Tt();
const c = restoreProperty();
const l = (function (t) {
const n = t.decodeSignal;
return (t) => {
@@ -467,18 +467,18 @@
})(n.get('shopify-reload'));
}
}
v.resolve(undefined);
return void (async function () {
const t = window.name.endsWith('/src');
if (n) {
window.opener = n;
window.fetch = n.fetch;
window.shopify = n.shopify;
window.polaris = n.polaris;
const t = window.open;
restoreProperty(self, 'open', function (n, e, i) {
interceptProperty(self, 'open', function (n, e, i) {
return n != null && Dt(n).protocol !== 'https:'
? window.opener.open(n, e, i)
: t.call(this, n, e, i);
@@ -934,20 +934,35 @@
I(oe, t.disabledFeatures);
(function (t) {
if (!A('MobileBridgeNext')) return;
const n = document.createElement('style');
if (
n.textContent =
typeof CSSStyleSheet != 'function' ||
"\n :root { --shopify-safe-area-inset-bottom: 0px; }\n body::after { content: ''; display: block; height: var(--shopify-safe-area-inset-bottom); }\n ";
typeof CSSStyleSheet.prototype.replaceSync != 'function' ||
document.head.appendChild(n);
!('adoptedStyleSheets' in Document.prototype)
)
return;
let n;
try {
n = new CSSStyleSheet();
n.replaceSync(
":root { --shopify-safe-area-inset-bottom: 0px; }\nbody::after { content: ''; display: block; height: var(--shopify-safe-area-inset-bottom); }",
);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, n];
} catch {
return;
}
const e = n.cssRules[0];
const i = (t) => {
const n = Math.max(0, Math.floor(t || 0));
e.style.setProperty('--shopify-safe-area-inset-bottom', n + 'px');
};
t.then((t) => {
const n = t?.safeAreaInsets?.bottom;
if (!n) return;
if (n) {
const e = (t) => {
i(n.value ?? 0);
document.documentElement.style.setProperty('--shopify-safe-area-inset-bottom', t + 'px');
n.subscribe?.((t) => i(t));
};
}
e(n.value ?? 0);
n.subscribe?.((t) => e(t));
});
h.send('Loading.stop');
y.ready = Promise.resolve();
})();
modules/_utilities.js Truncated +19 -19
@@ -567,7 +567,7 @@ var createPrivateKey = 0;
function checkPrivateField(t) {
return `__private_${createPrivateKey++}_${t}`;
}
function Tt(t = false) {
function restoreProperty(t = false) {
let n = null;
let e = t ? null : new Set();
var i = checkPrivateField('value');
@@ -682,11 +682,11 @@ function Tt(t = false) {
},
};
}
Tt(true);
restoreProperty(true);
const interceptProperty = Symbol();
const Tt = Symbol();
function restoreProperty(t, n, e) {
function interceptProperty(t, n, e) {
const i = t[n];
e[interceptProperty] = i;
e[Tt] = i;
Object.defineProperty(t, n, {
enumerable: true,
configurable: true,
@@ -696,7 +696,7 @@ function restoreProperty(t, n, e) {
return i;
}
function ORIGINAL_SYMBOL(t, n) {
const e = t[n][interceptProperty];
const e = t[n][Tt];
if (e) {
Object.defineProperty(t, n, {
enumerable: true,
@@ -725,7 +725,7 @@ const Lt = ({ api, protocol, internalApiPromise }) => {
verified: false,
};
}
restoreProperty(globalThis, 'fetch', async function (a, s) {
interceptProperty(globalThis, 'fetch', async function (a, s) {
const request = new Request(a instanceof Request ? a.clone() : a, s);
const { appOrigins: u = [] } = api.config;
const url = new URL(request.url);
@@ -816,16 +816,16 @@ const It = ({ api, protocol, internalApiPromise }) => {
return i;
};
};
const deepClone = Symbol();
const Mt = Symbol();
class Mt {
class deepClone {
constructor(t, n, e, i) {
this.action = t;
this.type = n;
this.data = e;
this[deepClone] = i;
this[Mt] = i;
}
finish() {
this[deepClone]();
this[Mt]();
}
}
class safeAsyncCall {
@@ -1017,7 +1017,7 @@ const zt = ({ internalApiPromise, saveBarManager, rpcEventTarget }) => {
true,
);
const a = self.open;
restoreProperty(self, 'open', function (t, e, i) {
interceptProperty(self, 'open', function (t, e, i) {
const o = t ? Dt(t).protocol : undefined;
if (t == null || !o || !Ut.includes(o)) return a.call(this, t, e, i);
if (saveBarManager.isSaveBarVisible) {
@@ -1095,16 +1095,16 @@ const zt = ({ internalApiPromise, saveBarManager, rpcEventTarget }) => {
});
}
}
restoreProperty(history, 'pushState', function (t, n, e) {
interceptProperty(history, 'pushState', function (t, n, e) {
c.call(history, t, n, e);
s.pushState(e);
});
restoreProperty(history, 'replaceState', function (t, n, e) {
interceptProperty(history, 'replaceState', function (t, n, e) {
c.call(history, t, n, e);
s.replaceState(e);
});
const d = HTMLFormElement.prototype.submit;
restoreProperty(HTMLFormElement.prototype, 'submit', function () {
interceptProperty(HTMLFormElement.prototype, 'submit', function () {
saveBarManager.setFormSubmitting();
d.call(this);
});
@@ -1139,7 +1139,7 @@ const generateId = ({ protocol, internalApiPromise }) => {
}
if (i && 'navigate' in i) {
i.navigate;
const n = restoreProperty(i, 'navigate', function (e, i) {
const n = interceptProperty(i, 'navigate', function (e, i) {
const o = s(e);
return o
? (protocol.send('Navigation.redirect.admin.path', {
@@ -1169,7 +1169,7 @@ const generateId = ({ protocol, internalApiPromise }) => {
);
else {
const t = history.pushState;
restoreProperty(history, 'pushState', function (n, e, i) {
interceptProperty(history, 'pushState', function (n, e, i) {
const r = location.href;
t.call(this, n, e, i);
if (i && new URL(i, r).href !== r) {
@@ -1180,7 +1180,7 @@ const generateId = ({ protocol, internalApiPromise }) => {
ORIGINAL_SYMBOL(history, 'pushState');
});
const n = history.replaceState;
restoreProperty(history, 'replaceState', function (t, e, i) {
interceptProperty(history, 'replaceState', function (t, e, i) {
const r = location.href;
n.call(this, t, e, i);
if (i && new URL(i, r).href !== r) {
@@ -1201,7 +1201,7 @@ const generateId = ({ protocol, internalApiPromise }) => {
);
}
const r = self.open;
restoreProperty(self, 'open', function (e, i, o) {
interceptProperty(self, 'open', function (e, i, o) {
if (e == null) return r.call(this, e, i, o);
const a = (function (t) {
const url = new URL(t, location.href);
Diff truncated at 200 lines
Module Changes
modules/fetch.js +1 -1
@@ -23,7 +23,7 @@ const Lt = ({ api, protocol, internalApiPromise }) => {
verified: false,
};
}
restoreProperty(globalThis, 'fetch', async function (a, s) {
interceptProperty(globalThis, 'fetch', async function (a, s) {
const request = new Request(a instanceof Request ? a.clone() : a, s);
const { appOrigins: u = [] } = api.config;
const url = new URL(request.url);
modules/intents.js +1 -1
@@ -44,7 +44,7 @@ const intentsModule = ({ api, protocol, internalApiPromise, signalFactory }) =>
'AppFrame.propertiesEvent',
({ properties }) => {
const o = (function (t, n, e) {
return new Mt('configure', 'gid://flow/stepReference/' + t, n, () =>
return new deepClone('configure', 'gid://flow/stepReference/' + t, n, () =>
e.send('AppFrame.navigateBack'),
);
})(
modules/print.js +1 -1
@@ -4,8 +4,8 @@
*/
const printModule = ({ protocol, internalApiPromise }) => {
restoreProperty(self, 'print', function () {
interceptProperty(self, 'print', function () {
const e = document.scrollingElement?.scrollHeight || document.body.offsetHeight;
SHOPIFY_PROTOCOLS(async () => {
const { print: i } = (await internalApiPromise) || {};
modules/share.js +1 -1
@@ -4,9 +4,9 @@
*/
const shareModule = ({ protocol, internalApiPromise }) => {
const e = navigator.share;
restoreProperty(navigator, 'share', async function (i) {
interceptProperty(navigator, 'share', async function (i) {
if (!i) return e.call(navigator, i);
const { share: o } = (await internalApiPromise) || {};
const { title: r, text: a, url: s } = i;