@builder.io/partytown
Version:
Relocate resource intensive third-party scripts off of the main thread and into a web worker.
73 lines (67 loc) • 4.72 kB
JavaScript
const PartytownSnippet = "/* Partytown 0.10.3-dev1734732935152 - MIT builder.io */\nconst t={preserveBehavior:!1},e=e=>{if(\"string\"==typeof e)return[e,t];const[n,r=t]=e;return[n,{...t,...r}]},n=Object.freeze((t=>{const e=new Set;let n=[];do{Object.getOwnPropertyNames(n).forEach((t=>{\"function\"==typeof n[t]&&e.add(t)}))}while((n=Object.getPrototypeOf(n))!==Object.prototype);return Array.from(e)})());!function(t,r,o,i,a,s,c,d,l,p,u=t,f){function h(){f||(f=1,\"/\"==(c=(s.lib||\"/~partytown/\")+(s.debug?\"debug/\":\"\"))[0]&&(l=r.querySelectorAll('script[type=\"text/partytown\"]'),i!=t?i.dispatchEvent(new CustomEvent(\"pt1\",{detail:t})):(d=setTimeout(v,999999999),r.addEventListener(\"pt0\",w),a?y(1):o.serviceWorker?o.serviceWorker.register(c+(s.swPath||\"partytown-sw.js\"),{scope:c}).then((function(t){t.active?y():t.installing&&t.installing.addEventListener(\"statechange\",(function(t){\"activated\"==t.target.state&&y()}))}),console.error):v())))}function y(e){p=r.createElement(e?\"script\":\"iframe\"),t._pttab=Date.now(),e||(p.style.display=\"block\",p.style.width=\"0\",p.style.height=\"0\",p.style.border=\"0\",p.style.visibility=\"hidden\",p.setAttribute(\"aria-hidden\",!0)),p.src=c+\"partytown-\"+(e?\"atomics.js?v=0.10.3-dev1734732935152\":\"sandbox-sw.html?\"+t._pttab),r.querySelector(s.sandboxParent||\"body\").appendChild(p)}function v(n,o){for(w(),i==t&&(s.forward||[]).map((function(n){const[r]=e(n);delete t[r.split(\".\")[0]]})),n=0;n<l.length;n++)(o=r.createElement(\"script\")).innerHTML=l[n].innerHTML,o.nonce=s.nonce,r.head.appendChild(o);p&&p.parentNode.removeChild(p)}function w(){clearTimeout(d)}s=t.partytown||{},i==t&&(s.forward||[]).map((function(r){const[o,{preserveBehavior:i}]=e(r);u=t,o.split(\".\").map((function(e,r,o){var a;u=u[o[r]]=r+1<o.length?u[o[r]]||(a=o[r+1],n.includes(a)?[]:{}):(()=>{let e=null;if(i){const{methodOrProperty:n,thisObject:r}=((t,e)=>{let n=t;for(let t=0;t<e.length-1;t+=1)n=n[e[t]];return{thisObject:n,methodOrProperty:e.length>0?n[e[e.length-1]]:void 0}})(t,o);\"function\"==typeof n&&(e=(...t)=>n.apply(r,...t))}return function(){let n;return e&&(n=e(arguments)),(t._ptf=t._ptf||[]).push(o,arguments),n}})()}))})),\"complete\"==r.readyState?h():(t.addEventListener(\"DOMContentLoaded\",h),t.addEventListener(\"load\",h))}(window,document,navigator,top,window.crossOriginIsolated);";
/**
* The `type` attribute for Partytown scripts, which does two things:
*
* 1. Prevents the `<script>` from executing on the main thread.
* 2. Is used as a selector so the Partytown library can find all scripts to execute in a web worker.
*
* @public
*/
const SCRIPT_TYPE = `text/partytown`;
const getMethods = (obj) => {
const properties = new Set();
let currentObj = obj;
do {
Object.getOwnPropertyNames(currentObj).forEach((item) => {
if (typeof currentObj[item] === 'function') {
properties.add(item);
}
});
} while ((currentObj = Object.getPrototypeOf(currentObj)) !== Object.prototype);
return Array.from(properties);
};
Object.freeze(getMethods([]));
function serializeConfig(config) {
return JSON.stringify(config, (key, value) => {
if (typeof value === 'function') {
value = String(value);
if (value.startsWith(key + '(')) {
value = 'function ' + value;
}
}
if (key === 'loadScriptsOnMainThread') {
value = value.map((scriptUrl) => Array.isArray(scriptUrl)
? scriptUrl
: [
typeof scriptUrl === 'string' ? 'string' : 'regexp',
typeof scriptUrl === 'string' ? scriptUrl : scriptUrl.source,
]);
}
return value;
});
}
const createSnippet = (config, snippetCode) => {
const { forward = [], ...filteredConfig } = config || {};
const configStr = serializeConfig(filteredConfig);
return [
`!(function(w,p,f,c){`,
`if(!window.crossOriginIsolated && !navigator.serviceWorker) return;`,
Object.keys(filteredConfig).length > 0
? `c=w[p]=Object.assign(w[p]||{},${configStr});`
: `c=w[p]=w[p]||{};`,
`c[f]=(c[f]||[])`,
forward.length > 0 ? `.concat(${JSON.stringify(forward)})` : ``,
`})(window,'partytown','forward');`,
snippetCode,
].join('');
};
/**
* Function that returns the Partytown snippet as a string, which can be
* used as the innerHTML of the inlined Partytown script in the head.
*
* @public
*/
const partytownSnippet = (config) => createSnippet(config, PartytownSnippet);
exports.SCRIPT_TYPE = SCRIPT_TYPE;
exports.partytownSnippet = partytownSnippet;
;