@symbo.ls/brender 3.14.670 → 3.14.671
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/dist/esm/pageWeight.js +1 -0
- package/dist/esm/render.js +31 -30
- package/package.json +5 -5
- package/pageWeight.js +284 -0
- package/render.js +57 -13
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @symbo.ls/brender
|
|
2
2
|
|
|
3
|
+
## 3.14.671
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- XMA round 8 (page weight and core size). Default builds look and behave the same; opt-in options save more.
|
|
8
|
+
|
|
9
|
+
Built pages (brender), on by default with no visible change, each with an off switch:
|
|
10
|
+
|
|
11
|
+
- The inline sprite holds only the page's icons (`brender.spriteIcons: 'all'` restores all).
|
|
12
|
+
- Atomic CSS only for classes in the page's markup (`brender.cssClasses: 'all'`).
|
|
13
|
+
- The element-path registry ships as a tree when the client reads it (`brender.registryFormat: 'paths'`).
|
|
14
|
+
|
|
15
|
+
Opt-in:
|
|
16
|
+
|
|
17
|
+
- `build.prepareDesignSystem: { pages: false }`: built pages do not request the prepared design-system file (`false` keeps meaning `{ shell: false }`).
|
|
18
|
+
- `brender.cssVariables: 'page'`: a built page carries only the CSS variables it reads.
|
|
19
|
+
- `build.treeShakeFeatures: true | { keep: [...] }`: a production `smbls build` drops unused autoGrow, inertOutside, bridge, viewEvents, lazy route groups, viewTransition, live sync, the pre-rendered boot (kept when the build pre-renders) and getSafeInk. Using a dropped feature logs a loud error naming the option.
|
|
20
|
+
|
|
21
|
+
Core: the full `esm` dist no longer carries esbuild `__esm` wrappers (namespace objects marked pure): about 2 KB Brotli less in every build.
|
|
22
|
+
|
|
23
|
+
Fix (round 7 options): the build scan for `treeShakeComponents`, `treeShakeIcons`, `treeShakeLibraries` and `treeShakeFeatures` reads only what the app loads (the symbols dir without tests, the entry document, symbols.json, and what they import). Files in scripts/, tests/, tool configs and worker files no longer keep components alive, and they no longer change the build output.
|
|
24
|
+
|
|
25
|
+
- Updated dependencies
|
|
26
|
+
- smbls@3.14.848
|
|
27
|
+
- @symbo.ls/utils@3.14.848
|
|
28
|
+
- @symbo.ls/element@3.14.813
|
|
29
|
+
- @symbo.ls/scratch@3.14.795
|
|
30
|
+
|
|
3
31
|
## 3.14.670
|
|
4
32
|
|
|
5
33
|
### Patch Changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const E=/<svg\b[^>]*\sid="svgSprite"[^>]*>/,x=/\s*<symbol\b[^>]*>[\s\S]*?<\/symbol>/y,m=/\s*<\/svg>/y,O=/^\s*<symbol\b[^>]*?\sid="([^"]+)"/,y=/#([^\s"'()<>&,;#]+)/g,w=(e,c)=>{if(typeof e!="string"||!e)return c;y.lastIndex=0;let t;for(;t=y.exec(e);)c.add(t[1]);return c},q=(e,c="")=>{const t={html:e,kept:0,dropped:0};if(typeof e!="string")return t;const s=E.exec(e);if(!s)return t;const n=s.index;let o=n+s[0].length;const r=[];for(;;){x.lastIndex=o;const f=x.exec(e);if(!f)break;const p=O.exec(f[0]);r.push({text:f[0],id:p?p[1]:null}),o=x.lastIndex}if(m.lastIndex=o,!m.exec(e))return t;const g=m.lastIndex,i=e.slice(0,n)+e.slice(g),u=w(c,w(i,new Set)),a=new Set,h=new Map;for(const f of r)f.id&&h.set(f.id,f);const S=[...u];for(;S.length;){const f=S.pop(),p=h.get(f);if(!(!p||a.has(p))){a.add(p);for(const k of w(p.text,new Set))h.has(k)&&S.push(k)}}const d=r.filter(f=>!f.id||a.has(f));if(d.length===r.length)return{html:e,kept:d.length,dropped:0};const v=s[0]+d.map(f=>f.text).join("")+e.slice(o,g);return{html:e.slice(0,n)+v+e.slice(g),kept:d.length,dropped:r.length-d.length}},M=e=>e.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g,'""').replace(/\[[^\]]*\]/g,"[]"),T=/\.(-?(?:[_A-Za-z -]|\\.)(?:[\w --]|\\.)*)/g,P=e=>e.replace(/\\(?:([0-9a-fA-F]{1,6})\s?|(.))/g,(c,t,s)=>t?String.fromCodePoint(parseInt(t,16)):s),L=e=>{const c=[];let t=0,s=null;for(let n=0;n<e.length;n++){const o=e[n];if(s){o==="\\"?n++:o===s&&(s=null);continue}o==='"'||o==="'"?s=o:o==="{"?(c.push(e.slice(t,n).trim()),t=n+1):(o==="}"||o===";")&&(t=n+1)}return c},C=e=>{const c=[];for(const t of L(String(e||""))){if(!t||t[0]==="@")continue;T.lastIndex=0;const s=M(t);let n;for(;n=T.exec(s);)c.push(P(n[1]))}return c},A=/\sclass\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+))/gi,F=(...e)=>{const c=new Set;for(const t of e){if(typeof t!="string"||!t)continue;A.lastIndex=0;let s;for(;s=A.exec(t);){const n=s[1]??s[2]??s[3]??"";for(const o of n.split(/\s+/))o&&c.add(o.replace(/&/g,"&"))}}return c},N=(e,c)=>{const t=[];for(const s of e||[]){if(!s)continue;const n=C(s);(!n.length||n.some(o=>c.has(o)))&&t.push(s)}return t},b=/var\(\s*(--[\w-]+)/g,_=/^\s*(--[\w-]+)\s*:([\s\S]*)$/,I=(e,c)=>{if(typeof e!="string"||!e)return c;b.lastIndex=0;let t;for(;t=b.exec(e);)c.add(t[1]);return c},R=(e,c)=>{let t="",s=0,n=null,o=0;for(let r=0;r<e.length;r++){const l=e[r];if(n){l==="\\"?r++:l===n&&(n=null);continue}if(l==='"'||l==="'")n=l;else if(l==="(")o++;else if(l===")")o=Math.max(0,o-1);else{if(o)continue;l==="{"?(t+=e.slice(s,r+1),s=r+1):l===";"?(t+=c(e.slice(s,r),";"),s=r+1):l==="}"&&(t+=c(e.slice(s,r),"")+"}",s=r+1)}}return t+e.slice(s)},B=(e,...c)=>{if(typeof e!="string"||!e)return{css:e,kept:0,dropped:0};const t=new Map,s=new Set;R(e,i=>{const u=_.exec(i);if(u){const a=t.get(u[1])||[];a.push(u[2]),t.set(u[1],a)}else I(i,s);return""});for(const i of c)I(i,s);const n=new Set,o=[...s];for(;o.length;){const i=o.pop();if(!(n.has(i)||!t.has(i))){n.add(i);for(const u of t.get(i))for(const a of I(u,new Set))o.push(a)}}let r=0,l=0;return{css:R(e,(i,u)=>{const a=_.exec(i);return!a||n.has(a[1])?(a&&r++,i+u):(l++,"")}),kept:r,dropped:l}};export{N as classRulesForPage,F as markupClasses,C as ruleClasses,q as trimSpriteToPage,B as trimVariablesToPage};
|
package/dist/esm/render.js
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import{resolve as p,join as Ne,dirname as T}from"path";import{existsSync as h,unlinkSync as He,readFileSync as J,realpathSync as Ue}from"fs";import{resolvePackageEntry as We}from"./packageEntry.js";import{tmpdir as Je}from"os";import{randomBytes as ze}from"crypto";import{createRequire as ie}from"module";import{pathToFileURL as Ye}from"url";import{createEnv as ye}from"./env.js";import{resetKeys as be,assignKeys as Se,mapKeysToElements as we}from"./keys.js";import{extractMetadata as ae,generateHeadHtml as Xe}from"./metadata.js";import"./hydrate.js";import{composeIntoShell as Ve}from"./shell.js";import{fetchSSRTranslations as Qe}from"./prefetch.js";import{createEarlySeedScript as Ze}from"@symbo.ls/fetch";import{headerEntries as et}from"@symbo.ls/fetch/rest";import{brenderRegistryBlock as tt,brenderStampMeta as ot,escapeRegExp as nt,jsonForScript as st,polyglotFallbackLang as Q,polyglotLangStorageKey as rt,polyglotAddressLang as ct,polyglotStartupScript as it}from"@symbo.ls/utils";let Z=null;const at=async()=>{if(Z)return Z;try{return Z=(await import("@symbo.ls/funcql")).funcqlPlugin,Z}catch{return null}};import"linkedom";import{createEarlySeedBlock as lt}from"@symbo.ls/fetch";import{reset as ft}from"@symbo.ls/css";const ee=(e,t)=>{if(!e||!t)return;if(e[t]!==void 0)return e[t];const o=t.split(".");let n=e;for(const s of o){if(n==null||typeof n!="object")return;n=n[s]}return n},te=(e,t)=>Q(e?.lang,t),Re=(e,t,o,n)=>{if(o?.translations){const r=o.translations[t];if(r){const i=ee(r,e);if(i!==void 0)return i}}if(n?.translations){const r=n.translations[t];if(r){const i=ee(r,e);if(i!==void 0)return i}}const s=Q(void 0,o);if(s!==t&&o?.translations){const r=o.translations[s];if(r){const i=ee(r,e);if(i!==void 0)return i}}},ut=function(e,t){if(!e)return"";const o=this?.context,n=o?.polyglot,s=this?.state?.root||o?.state?.root,r=Re(e,t||te(s,n),n,s);if(r!==void 0)return r;const i=pe(ue);return n&&i&&i.labelKeys.add(e),e},ke=function(){return te(this?.state?.root,this?.context?.polyglot)},$=(e,t=new WeakMap)=>{if(e===null||typeof e!="object")return e;if(t.has(e))return t.get(e);if(Array.isArray(e)){const n=[];t.set(e,n);for(const s of e)n.push(typeof s=="object"&&s!==null?$(s,t):s);return n}const o={};t.set(e,o);for(const n of Object.keys(e)){const s=e[n];o[n]=typeof s=="object"&&s!==null?$(s,t):s}return o};let q=null;try{import.meta.url&&(q=ie(import.meta.url))}catch{}const pt=()=>{if(!import.meta.url||!q)return{isMonorepo:!1,monorepoRoot:null,resolvePackage:l=>l};const e=Ue(new URL(".",import.meta.url).pathname),t=p(e,"../..");if(h(p(t,"packages","smbls","src","createDomql.js")))return{isMonorepo:!0,monorepoRoot:t};let n;try{const l=q.resolve("smbls/package.json");n=T(l)}catch{let l=e;for(;l!==T(l);){const g=p(l,"node_modules","smbls");if(h(p(g,"package.json"))){n=g;break}l=T(l)}}let s=q;if(n)try{s=ie(p(n,"package.json"))}catch{}let r,i=process.cwd();for(;i!==T(i);){if(h(p(i,"package.json"))){r=i;break}i=T(i)}let m=s;if(r)try{m=ie(p(r,"package.json"))}catch{}return{isMonorepo:!1,smblsRoot:n,brenderDir:e,projectRoot:r,_smblsRequire:s,_projectRequire:m}},P=(e,t)=>{const o=e.isMonorepo?[q]:[e._smblsRequire,e._projectRequire,q].filter(Boolean);for(const n of o)try{return n.resolve(t)}catch{}return null},Eo=(e,t,...o)=>{if(e.isMonorepo)return p(e.monorepoRoot,"packages",t,...o);const n=P(e,`${t}/package.json`);return n?p(T(n),...o):null},To=(e,t,...o)=>{if(e.isMonorepo)return p(e.monorepoRoot,"plugins",t,...o);const n=P(e,`@symbo.ls/${t}/package.json`);return n?p(T(n),...o):null},le=(e,t,...o)=>{if(e.isMonorepo){for(const s of["packages","plugins"]){const r=p(e.monorepoRoot,s,t,...o);if(h(r))return r}return null}const n=P(e,`@symbo.ls/${t}/package.json`);return n?p(T(n),...o):null},xe=(e,t,...o)=>{if(e.isMonorepo)return p(e.monorepoRoot,"packages","domql","packages",t,...o);const n=P(e,`@symbo.ls/${t}/package.json`);return n?p(T(n),...o):null};let oe=null;const je="smbls/ssr",mt=async()=>{const e=await import("smbls/ssr");if(typeof e?.createDomqlElement!="function")throw new Error("smbls/ssr does not export createDomqlElement");return e},_e=()=>(oe||(oe=dt().catch(e=>{throw oe=null,e})),oe),dt=async()=>{const e=pt();let t;if(q&&e.isMonorepo)t=p(e.monorepoRoot,"packages","smbls","src","createDomql.js");else{let f;try{return await mt()}catch(a){f=a}if(!q)throw new Error(`brender: ${je} is not available in this bundled runtime (${f.message}). Bundle smbls \u2265 the release that adds the smbls/ssr export alongside @symbo.ls/brender.`);const c=e.smblsRoot&&p(e.smblsRoot,"src","createDomql.js");if(c&&h(c))t=c;else throw new Error(`brender: cannot load ${je} (${f.message}). Server rendering needs smbls installed in this project, at a release that exports smbls/ssr`+(e.smblsRoot?` (found smbls at ${e.smblsRoot}).`:" (no smbls package found)."))}const o=await import("esbuild"),n=Ne(Je(),`br_createDomql_${ze(6).toString("hex")}.mjs`),s=We,r=e.isMonorepo?await import(Ye(p(e.monorepoRoot,"scripts","vite-workspace-source.mjs")).href):null,i=r?new Set(r.workspacePackageRoots().map(f=>r.workspacePackageAt(f).name)):null,m=/^(?:smbls(?:\/.*)?|domql|css-in-props(?:\/.*)?|@symbo\.ls\/[^/]+)$/,l={name:"workspace-resolve",setup(f){r&&(f.onResolve({filter:/^[^./]/},c=>{if(m.test(c.path))return;const a=c.path.split("/"),u=c.path.startsWith("@")?a.slice(0,2).join("/"):a[0];if(!i.has(u))return;const d=r.resolveWorkspaceSource(c.path,c.importer||t);return d?{path:d}:{errors:[{text:`"${c.path}" names no source file in the workspace`}]}}),f.onLoad({filter:/[\\/]dist[\\/]/},c=>r.isWorkspaceDist(c.path)?{errors:[{text:`${c.path} is a BUILD of a workspace package \u2014 the render bundles source`}]}:void 0)),f.onResolve({filter:/^smbls/},c=>{const a=c.path.replace(/^smbls\/?/,""),u=e.isMonorepo?p(e.monorepoRoot,"packages","smbls"):e.smblsRoot;if(!u)return;if(!a){const b=s(u);return b?{path:b}:void 0}const d=p(u,a);if(h(d))return{path:d};if(h(d+".js"))return{path:d+".js"};const y=p(d,"index.js");if(h(y))return{path:y}}),f.onResolve({filter:/^domql$/},c=>{if(e.isMonorepo){const a=p(e.monorepoRoot,"packages","domql","src","index.js");if(h(a))return{path:a};const u=p(e.monorepoRoot,"packages","domql","index.js");if(h(u))return{path:u}}else try{const a=_require.resolve("domql/package.json"),u=s(T(a));if(u)return{path:u}}catch{}}),f.onResolve({filter:/^@symbo\.ls\//},c=>{const a=c.path.replace("@symbo.ls/","");if(a==="sync")return{path:"sync-stub",namespace:"brender-stub"};if(e.isMonorepo){for(const d of["packages","plugins"]){const y=p(e.monorepoRoot,d,a,"src","index.js");if(h(y))return{path:y};const b=p(e.monorepoRoot,d,a,"index.js");if(h(b))return{path:b}}const u=p(e.monorepoRoot,"packages","default-config","blank","index.js");if(a==="default-config"&&h(u))return{path:u}}else{const u=le(e,a,"src","index.js");if(u&&h(u))return{path:u};const d=le(e,a,"index.js");if(d&&h(d))return{path:d};if(a==="default-config"){const y=le(e,"default-config","blank","index.js");if(y&&h(y))return{path:y}}}}),f.onResolve({filter:/^@domql\//},c=>{const a=c.path.replace("@symbo.ls/","");if(e.isMonorepo){const u=p(e.monorepoRoot,"packages","domql","packages",a,"src","index.js");if(h(u))return{path:u};const d=p(e.monorepoRoot,"packages","domql","packages",a,"index.js");if(h(d))return{path:d}}else{const u=xe(e,a,"src","index.js");if(u&&h(u))return{path:u};const d=xe(e,a,"index.js");if(d&&h(d))return{path:d}}}),f.onResolve({filter:/^css-in-props/},c=>{let a;if(e.isMonorepo)a=p(e.monorepoRoot,"packages","css-in-props");else{const y=P(e,"css-in-props/package.json");y&&(a=T(y))}if(!a)return;const u=c.path.replace(/^css-in-props\/?/,"");if(u){const y=p(a,u),b=p(y,"index.js");if(h(b))return{path:b};if(h(y+".js"))return{path:y+".js"};if(h(y))return{path:y}}const d=s(a);if(d)return{path:d}}),f.onResolve({filter:/^@emotion\//},c=>{let a;if(e.isMonorepo)a=p(e.monorepoRoot,"node_modules",c.path);else{const u=P(e,`${c.path}/package.json`);if(!u)return;a=T(u)}if(h(a)){const u=p(a,"package.json");if(h(u))try{const d=JSON.parse(J(u,"utf8")),y=d.module||d.main||"dist/emotion-css.esm.js";return{path:p(a,y)}}catch{}return{path:a}}}),f.onResolve({filter:/\.json$/},c=>{if(c.resolveDir){const a=p(c.resolveDir,c.path);if(h(a))return{path:a}}}),f.onLoad({filter:/smbls\/.*options\.js$/},async c=>{if(!c.path.includes("smbls/")||!c.path.endsWith("options.js"))return;let a=J(c.path,"utf8");return a=a.replace(/import\s*\{[^}]*version[^}]*\}\s*from\s*['"][^'"]*package\.json['"][^;\n]*/,"const version = '0.0.0'"),a=a.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:a,loader:"js"}}),f.onLoad({filter:/smbls\/.*init\.js$/},async c=>{if(!c.path.includes("smbls/")||!c.path.endsWith("init.js"))return;let a=J(c.path,"utf8");return a=a.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:a,loader:"js"}}),f.onLoad({filter:/.*/,namespace:"brender-stub"},()=>({contents:"export const SyncComponent = {}; export const Inspect = {}; export const Notifications = {}; export const syncPlugin = () => ({}); export const notificationsPlugin = () => ({}); export const seedRawDesignSystem = () => {}; export const inspectPlugin = () => ({}); export default {}",loader:"js"})),f.onLoad({filter:/smbls\/src\/router\.js$/},async c=>{let a=J(c.path,"utf8");return a=a.replace(/import\s*\{\s*Link\s*\}\s*from\s*['"]smbls['"]/,"const Link = { tag: 'a', attr: { href: (el) => el.href } }"),{contents:a,loader:"js"}}),f.onLoad({filter:/fetchOnCreate\.js$/},async c=>{if(!c.path.includes("smbls/"))return;let a=J(c.path,"utf8");return a=a.replace(/window\s*&&\s*window\.location\s*\?\s*window\.location\.host\.includes/g,"window && window.location && window.location.host ? window.location.host.includes"),{contents:a,loader:"js"}})}};await o.build({entryPoints:[t],bundle:!0,format:"esm",platform:"node",outfile:n,write:!0,logLevel:"warning",plugins:[l],nodePaths:e.isMonorepo?[p(e.monorepoRoot,"node_modules")]:[...e.smblsRoot?[p(e.smblsRoot,"node_modules")]:[],...e.projectRoot?[p(e.projectRoot,"node_modules")]:[],...e.smblsRoot?[p(e.smblsRoot,"..","..","node_modules")]:[]].filter(f=>h(f)),supported:{"import-attributes":!1},external:["fs","path","os","crypto","url","http","https","stream","util","events","buffer","child_process","worker_threads","net","tls","dns","dgram","zlib","assert","querystring","string_decoder","readline","perf_hooks","async_hooks","v8","vm","cluster","inspector","module","process","tty","color-contrast-checker","linkedom"]});const g=await import(`file://${n}`);if(process.env.BRENDER_DEBUG)console.log("[brender] Bundle saved:",n);else try{He(n)}catch{}return g},gt={Box:{},Focusable:{},Block:{display:"block"},Inline:{display:"inline"},Flex:{display:"flex"},InlineFlex:{display:"inline-flex"},Grid:{display:"grid"},InlineGrid:{display:"inline-grid"},Link:{tag:"a",attr:{href:e=>e.href,target:e=>e.target,rel:e=>e.rel}},A:{extends:"Link"},RouteLink:{extends:"Link"},Img:{tag:"img",attr:{src:e=>{let t=e.src;return typeof t=="string"&&t.includes("{{")&&(t=e.call("replaceLiteralsWithObjectFields",t,e.state)),t},alt:e=>e.alt,loading:e=>e.loading}},Image:{extends:"Img"},Button:{tag:"button"},FocusableComponent:{tag:"button"},Form:{tag:"form"},Input:{tag:"input"},TextArea:{tag:"textarea"},Textarea:{tag:"textarea"},Select:{tag:"select"},Label:{tag:"label"},Iframe:{tag:"iframe"},Video:{tag:"video"},Audio:{tag:"audio"},Canvas:{tag:"canvas"},Span:{tag:"span"},P:{tag:"p"},H1:{tag:"h1"},H2:{tag:"h2"},H3:{tag:"h3"},H4:{tag:"h4"},H5:{tag:"h5"},H6:{tag:"h6"},Svg:{tag:"svg",attr:{xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink"}},Text:{tag:"span"}},ht=(e,t)=>{const o={};return Ee(e,(n,s)=>{if(!s.__brKey)return;const r=t(n);o[r===""?"__root":r]=s.__brKey}),o},Ee=(e,t)=>{const o=n=>{const s=n&&n.__ref;if(s&&(t(n,s),s.__children))for(const r of s.__children)o(n[r])};o(e)},yt=new Set(["app","config","pages","components","state","snippets","designSystem","dependencies","functions","methods","files","sharedLibraries"]);let F=0;const Te=Symbol.for("brender.fetchTracked"),fe=()=>F,bt=256*1024,St=1024*1024,wt=new Set(["accept-language","accept"]),ve={renders:0,record:null},Rt=50,ue={renders:0,record:null},Le=(e,t)=>{e.renders++,e.renders===1?e.record=t():e.record&&(e.record.tainted=!0);const o=e.record;return{record:o,close:()=>{e.renders--,e.record===o&&(e.record=null)}}},pe=e=>e.record&&!e.record.tainted?e.record:null,kt=e=>{try{const t=new URL(e);return t.origin+t.pathname}catch{return String(e).split("?")[0]}},me=(e,t,o)=>{!e||e.tainted||e.failures.length>=Rt||e.failures.push({url:kt(t),reason:o})},De=e=>e&&typeof e=="object"&&typeof e.url=="string"?e.url:String(e),xt=e=>{const[t,o]=e,n=t&&typeof t=="object"&&typeof t.url=="string",s=De(t),r=String(o&&o.method||n&&t.method||"GET").toUpperCase(),i={},m=l=>{if(!l)return;const g=!Array.isArray(l)&&typeof l.entries!="function";for(const[f,c]of et(l))g&&c==null||(i[String(f).toLowerCase()]=String(c))};return n&&m(t.headers),o&&m(o.headers),{url:s,method:r,headers:i}},jt=(e,t,o,n)=>{if(!o||!o.ok||typeof o.clone!="function")return;const s=o.headers&&o.headers.get&&o.headers.get("content-type")||"";if(!/json|^text\//i.test(s))return;let r;try{r=o.clone()}catch{return}n(r.text().then(i=>{e.tainted||i.length>bt||e.bytes+i.length>St||(e.bytes+=i.length,e.entries.push({url:t.url,lang:t.headers["accept-language"]||"",status:o.status,type:s,body:i}))},()=>{}))},_t=()=>{const e=globalThis.fetch;if(typeof e!="function"||e[Te])return;const t=function(...o){F++;let n=!1;const s=()=>{n||(n=!0,F--)},r=c=>{F++,c.then(()=>{F--},()=>{F--})},i=pe(ve),m=pe(ue);let l=null;if(i)try{l=xt(o),(l.method!=="GET"||!/^https?:/i.test(l.url)||Object.keys(l.headers).some(c=>!wt.has(c)))&&(l=null)}catch{l=null}const g=()=>De(o[0]);let f;try{f=e.apply(this,o)}catch(c){throw me(m,g(),c&&c.message||"failed"),s(),c}return f&&typeof f.then=="function"?f.then(c=>{l&&jt(i,l,c,r),m&&c&&c.ok===!1&&me(m,g(),"HTTP "+c.status),s()},c=>{me(m,g(),c&&c.message||"network error"),s()}):s(),f};t[Te]=!0,globalThis.fetch=t},vo=({brRegistry:e,fetchSeed:t,hydrateFlag:o=!0}={})=>{if(!e||!Object.keys(e).length)return"";const n=st(e);return o?`<script>window.__BR_REGISTRY__=${n};window.__BRENDER_HYDRATE__=true<\/script>`+(t&&t.length?`
|
|
2
|
-
`+
|
|
1
|
+
import{resolve as m,join as He,dirname as _}from"path";import{existsSync as h,unlinkSync as Ue,readFileSync as z,realpathSync as We}from"fs";import{resolvePackageEntry as Je}from"./packageEntry.js";import{tmpdir as Ye}from"os";import{randomBytes as ze}from"crypto";import{createRequire as le}from"module";import{pathToFileURL as Ve}from"url";import{createEnv as Se}from"./env.js";import{resetKeys as Re,assignKeys as ke,mapKeysToElements as we}from"./keys.js";import{extractMetadata as pe,generateHeadHtml as Xe}from"./metadata.js";import"./hydrate.js";import{composeIntoShell as Qe}from"./shell.js";import{trimSpriteToPage as Ze,classRulesForPage as et,markupClasses as tt,trimVariablesToPage as ot}from"./pageWeight.js";import{fetchSSRTranslations as nt}from"./prefetch.js";import{createEarlySeedScript as st}from"@symbo.ls/fetch";import{headerEntries as rt}from"@symbo.ls/fetch/rest";import{brenderRegistryBlock as ct,brenderRegistryTreeBlock as it,brenderStampMeta as at,escapeRegExp as lt,jsonForScript as pt,polyglotFallbackLang as oe,polyglotLangStorageKey as ft,polyglotAddressLang as ut,polyglotStartupScript as mt}from"@symbo.ls/utils";let ne=null;const dt=async()=>{if(ne)return ne;try{return ne=(await import("@symbo.ls/funcql")).funcqlPlugin,ne}catch{return null}};import"linkedom";import{createEarlySeedBlock as gt}from"@symbo.ls/fetch";import{reset as ht}from"@symbo.ls/css";const se=(e,t)=>{if(!e||!t)return;if(e[t]!==void 0)return e[t];const o=t.split(".");let n=e;for(const s of o){if(n==null||typeof n!="object")return;n=n[s]}return n},re=(e,t)=>oe(e?.lang,t),xe=(e,t,o,n)=>{if(o?.translations){const r=o.translations[t];if(r){const i=se(r,e);if(i!==void 0)return i}}if(n?.translations){const r=n.translations[t];if(r){const i=se(r,e);if(i!==void 0)return i}}const s=oe(void 0,o);if(s!==t&&o?.translations){const r=o.translations[s];if(r){const i=se(r,e);if(i!==void 0)return i}}},yt=function(e,t){if(!e)return"";const o=this?.context,n=o?.polyglot,s=this?.state?.root||o?.state?.root,r=xe(e,t||re(s,n),n,s);if(r!==void 0)return r;const i=de(me);return n&&i&&i.labelKeys.add(e),e},je=function(){return re(this?.state?.root,this?.context?.polyglot)},L=(e,t=new WeakMap)=>{if(e===null||typeof e!="object")return e;if(t.has(e))return t.get(e);if(Array.isArray(e)){const n=[];t.set(e,n);for(const s of e)n.push(typeof s=="object"&&s!==null?L(s,t):s);return n}const o={};t.set(e,o);for(const n of Object.keys(e)){const s=e[n];o[n]=typeof s=="object"&&s!==null?L(s,t):s}return o};let O=null;try{import.meta.url&&(O=le(import.meta.url))}catch{}const bt=()=>{if(!import.meta.url||!O)return{isMonorepo:!1,monorepoRoot:null,resolvePackage:l=>l};const e=We(new URL(".",import.meta.url).pathname),t=m(e,"../..");if(h(m(t,"packages","smbls","src","createDomql.js")))return{isMonorepo:!0,monorepoRoot:t};let n;try{const l=O.resolve("smbls/package.json");n=_(l)}catch{let l=e;for(;l!==_(l);){const g=m(l,"node_modules","smbls");if(h(m(g,"package.json"))){n=g;break}l=_(l)}}let s=O;if(n)try{s=le(m(n,"package.json"))}catch{}let r,i=process.cwd();for(;i!==_(i);){if(h(m(i,"package.json"))){r=i;break}i=_(i)}let f=s;if(r)try{f=le(m(r,"package.json"))}catch{}return{isMonorepo:!1,smblsRoot:n,brenderDir:e,projectRoot:r,_smblsRequire:s,_projectRequire:f}},H=(e,t)=>{const o=e.isMonorepo?[O]:[e._smblsRequire,e._projectRequire,O].filter(Boolean);for(const n of o)try{return n.resolve(t)}catch{}return null},Co=(e,t,...o)=>{if(e.isMonorepo)return m(e.monorepoRoot,"packages",t,...o);const n=H(e,`${t}/package.json`);return n?m(_(n),...o):null},qo=(e,t,...o)=>{if(e.isMonorepo)return m(e.monorepoRoot,"plugins",t,...o);const n=H(e,`@symbo.ls/${t}/package.json`);return n?m(_(n),...o):null},fe=(e,t,...o)=>{if(e.isMonorepo){for(const s of["packages","plugins"]){const r=m(e.monorepoRoot,s,t,...o);if(h(r))return r}return null}const n=H(e,`@symbo.ls/${t}/package.json`);return n?m(_(n),...o):null},Ee=(e,t,...o)=>{if(e.isMonorepo)return m(e.monorepoRoot,"packages","domql","packages",t,...o);const n=H(e,`@symbo.ls/${t}/package.json`);return n?m(_(n),...o):null};let ce=null;const Te="smbls/ssr",St=async()=>{const e=await import("smbls/ssr");if(typeof e?.createDomqlElement!="function")throw new Error("smbls/ssr does not export createDomqlElement");return e},_e=()=>(ce||(ce=Rt().catch(e=>{throw ce=null,e})),ce),Rt=async()=>{const e=bt();let t;if(O&&e.isMonorepo)t=m(e.monorepoRoot,"packages","smbls","src","createDomql.js");else{let p;try{return await St()}catch(a){p=a}if(!O)throw new Error(`brender: ${Te} is not available in this bundled runtime (${p.message}). Bundle smbls \u2265 the release that adds the smbls/ssr export alongside @symbo.ls/brender.`);const c=e.smblsRoot&&m(e.smblsRoot,"src","createDomql.js");if(c&&h(c))t=c;else throw new Error(`brender: cannot load ${Te} (${p.message}). Server rendering needs smbls installed in this project, at a release that exports smbls/ssr`+(e.smblsRoot?` (found smbls at ${e.smblsRoot}).`:" (no smbls package found)."))}const o=await import("esbuild"),n=He(Ye(),`br_createDomql_${ze(6).toString("hex")}.mjs`),s=Je,r=e.isMonorepo?await import(Ve(m(e.monorepoRoot,"scripts","vite-workspace-source.mjs")).href):null,i=r?new Set(r.workspacePackageRoots().map(p=>r.workspacePackageAt(p).name)):null,f=/^(?:smbls(?:\/.*)?|domql|css-in-props(?:\/.*)?|@symbo\.ls\/[^/]+)$/,l={name:"workspace-resolve",setup(p){r&&(p.onResolve({filter:/^[^./]/},c=>{if(f.test(c.path))return;const a=c.path.split("/"),u=c.path.startsWith("@")?a.slice(0,2).join("/"):a[0];if(!i.has(u))return;const d=r.resolveWorkspaceSource(c.path,c.importer||t);return d?{path:d}:{errors:[{text:`"${c.path}" names no source file in the workspace`}]}}),p.onLoad({filter:/[\\/]dist[\\/]/},c=>r.isWorkspaceDist(c.path)?{errors:[{text:`${c.path} is a BUILD of a workspace package \u2014 the render bundles source`}]}:void 0)),p.onResolve({filter:/^smbls/},c=>{const a=c.path.replace(/^smbls\/?/,""),u=e.isMonorepo?m(e.monorepoRoot,"packages","smbls"):e.smblsRoot;if(!u)return;if(!a){const E=s(u);return E?{path:E}:void 0}const d=m(u,a);if(h(d))return{path:d};if(h(d+".js"))return{path:d+".js"};const b=m(d,"index.js");if(h(b))return{path:b}}),p.onResolve({filter:/^domql$/},c=>{if(e.isMonorepo){const a=m(e.monorepoRoot,"packages","domql","src","index.js");if(h(a))return{path:a};const u=m(e.monorepoRoot,"packages","domql","index.js");if(h(u))return{path:u}}else try{const a=_require.resolve("domql/package.json"),u=s(_(a));if(u)return{path:u}}catch{}}),p.onResolve({filter:/^@symbo\.ls\//},c=>{const a=c.path.replace("@symbo.ls/","");if(a==="sync")return{path:"sync-stub",namespace:"brender-stub"};if(e.isMonorepo){for(const d of["packages","plugins"]){const b=m(e.monorepoRoot,d,a,"src","index.js");if(h(b))return{path:b};const E=m(e.monorepoRoot,d,a,"index.js");if(h(E))return{path:E}}const u=m(e.monorepoRoot,"packages","default-config","blank","index.js");if(a==="default-config"&&h(u))return{path:u}}else{const u=fe(e,a,"src","index.js");if(u&&h(u))return{path:u};const d=fe(e,a,"index.js");if(d&&h(d))return{path:d};if(a==="default-config"){const b=fe(e,"default-config","blank","index.js");if(b&&h(b))return{path:b}}}}),p.onResolve({filter:/^@domql\//},c=>{const a=c.path.replace("@symbo.ls/","");if(e.isMonorepo){const u=m(e.monorepoRoot,"packages","domql","packages",a,"src","index.js");if(h(u))return{path:u};const d=m(e.monorepoRoot,"packages","domql","packages",a,"index.js");if(h(d))return{path:d}}else{const u=Ee(e,a,"src","index.js");if(u&&h(u))return{path:u};const d=Ee(e,a,"index.js");if(d&&h(d))return{path:d}}}),p.onResolve({filter:/^css-in-props/},c=>{let a;if(e.isMonorepo)a=m(e.monorepoRoot,"packages","css-in-props");else{const b=H(e,"css-in-props/package.json");b&&(a=_(b))}if(!a)return;const u=c.path.replace(/^css-in-props\/?/,"");if(u){const b=m(a,u),E=m(b,"index.js");if(h(E))return{path:E};if(h(b+".js"))return{path:b+".js"};if(h(b))return{path:b}}const d=s(a);if(d)return{path:d}}),p.onResolve({filter:/^@emotion\//},c=>{let a;if(e.isMonorepo)a=m(e.monorepoRoot,"node_modules",c.path);else{const u=H(e,`${c.path}/package.json`);if(!u)return;a=_(u)}if(h(a)){const u=m(a,"package.json");if(h(u))try{const d=JSON.parse(z(u,"utf8")),b=d.module||d.main||"dist/emotion-css.esm.js";return{path:m(a,b)}}catch{}return{path:a}}}),p.onResolve({filter:/\.json$/},c=>{if(c.resolveDir){const a=m(c.resolveDir,c.path);if(h(a))return{path:a}}}),p.onLoad({filter:/smbls\/.*options\.js$/},async c=>{if(!c.path.includes("smbls/")||!c.path.endsWith("options.js"))return;let a=z(c.path,"utf8");return a=a.replace(/import\s*\{[^}]*version[^}]*\}\s*from\s*['"][^'"]*package\.json['"][^;\n]*/,"const version = '0.0.0'"),a=a.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:a,loader:"js"}}),p.onLoad({filter:/smbls\/.*init\.js$/},async c=>{if(!c.path.includes("smbls/")||!c.path.endsWith("init.js"))return;let a=z(c.path,"utf8");return a=a.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:a,loader:"js"}}),p.onLoad({filter:/.*/,namespace:"brender-stub"},()=>({contents:"export const SyncComponent = {}; export const Inspect = {}; export const Notifications = {}; export const syncPlugin = () => ({}); export const notificationsPlugin = () => ({}); export const seedRawDesignSystem = () => {}; export const inspectPlugin = () => ({}); export default {}",loader:"js"})),p.onLoad({filter:/smbls\/src\/router\.js$/},async c=>{let a=z(c.path,"utf8");return a=a.replace(/import\s*\{\s*Link\s*\}\s*from\s*['"]smbls['"]/,"const Link = { tag: 'a', attr: { href: (el) => el.href } }"),{contents:a,loader:"js"}}),p.onLoad({filter:/fetchOnCreate\.js$/},async c=>{if(!c.path.includes("smbls/"))return;let a=z(c.path,"utf8");return a=a.replace(/window\s*&&\s*window\.location\s*\?\s*window\.location\.host\.includes/g,"window && window.location && window.location.host ? window.location.host.includes"),{contents:a,loader:"js"}})}};await o.build({entryPoints:[t],bundle:!0,format:"esm",platform:"node",outfile:n,write:!0,logLevel:"warning",plugins:[l],nodePaths:e.isMonorepo?[m(e.monorepoRoot,"node_modules")]:[...e.smblsRoot?[m(e.smblsRoot,"node_modules")]:[],...e.projectRoot?[m(e.projectRoot,"node_modules")]:[],...e.smblsRoot?[m(e.smblsRoot,"..","..","node_modules")]:[]].filter(p=>h(p)),supported:{"import-attributes":!1},external:["fs","path","os","crypto","url","http","https","stream","util","events","buffer","child_process","worker_threads","net","tls","dns","dgram","zlib","assert","querystring","string_decoder","readline","perf_hooks","async_hooks","v8","vm","cluster","inspector","module","process","tty","color-contrast-checker","linkedom"]});const g=await import(`file://${n}`);if(process.env.BRENDER_DEBUG)console.log("[brender] Bundle saved:",n);else try{Ue(n)}catch{}return g},kt={Box:{},Focusable:{},Block:{display:"block"},Inline:{display:"inline"},Flex:{display:"flex"},InlineFlex:{display:"inline-flex"},Grid:{display:"grid"},InlineGrid:{display:"inline-grid"},Link:{tag:"a",attr:{href:e=>e.href,target:e=>e.target,rel:e=>e.rel}},A:{extends:"Link"},RouteLink:{extends:"Link"},Img:{tag:"img",attr:{src:e=>{let t=e.src;return typeof t=="string"&&t.includes("{{")&&(t=e.call("replaceLiteralsWithObjectFields",t,e.state)),t},alt:e=>e.alt,loading:e=>e.loading}},Image:{extends:"Img"},Button:{tag:"button"},FocusableComponent:{tag:"button"},Form:{tag:"form"},Input:{tag:"input"},TextArea:{tag:"textarea"},Textarea:{tag:"textarea"},Select:{tag:"select"},Label:{tag:"label"},Iframe:{tag:"iframe"},Video:{tag:"video"},Audio:{tag:"audio"},Canvas:{tag:"canvas"},Span:{tag:"span"},P:{tag:"p"},H1:{tag:"h1"},H2:{tag:"h2"},H3:{tag:"h3"},H4:{tag:"h4"},H5:{tag:"h5"},H6:{tag:"h6"},Svg:{tag:"svg",attr:{xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink"}},Text:{tag:"span"}},wt=(e,t)=>{const o={};return ve(e,(n,s)=>{if(!s.__brKey)return;const r=t(n);o[r===""?"__root":r]=s.__brKey}),o},ve=(e,t)=>{const o=n=>{const s=n&&n.__ref;if(s&&(t(n,s),s.__children))for(const r of s.__children)o(n[r])};o(e)},xt=new Set(["app","config","pages","components","state","snippets","designSystem","dependencies","functions","methods","files","sharedLibraries"]);let U=0;const Le=Symbol.for("brender.fetchTracked"),ue=()=>U,jt=256*1024,Et=1024*1024,Tt=new Set(["accept-language","accept"]),De={renders:0,record:null},_t=50,me={renders:0,record:null},$e=(e,t)=>{e.renders++,e.renders===1?e.record=t():e.record&&(e.record.tainted=!0);const o=e.record;return{record:o,close:()=>{e.renders--,e.record===o&&(e.record=null)}}},de=e=>e.record&&!e.record.tainted?e.record:null,vt=e=>{try{const t=new URL(e);return t.origin+t.pathname}catch{return String(e).split("?")[0]}},ge=(e,t,o)=>{!e||e.tainted||e.failures.length>=_t||e.failures.push({url:vt(t),reason:o})},Ae=e=>e&&typeof e=="object"&&typeof e.url=="string"?e.url:String(e),Lt=e=>{const[t,o]=e,n=t&&typeof t=="object"&&typeof t.url=="string",s=Ae(t),r=String(o&&o.method||n&&t.method||"GET").toUpperCase(),i={},f=l=>{if(!l)return;const g=!Array.isArray(l)&&typeof l.entries!="function";for(const[p,c]of rt(l))g&&c==null||(i[String(p).toLowerCase()]=String(c))};return n&&f(t.headers),o&&f(o.headers),{url:s,method:r,headers:i}},Dt=(e,t,o,n)=>{if(!o||!o.ok||typeof o.clone!="function")return;const s=o.headers&&o.headers.get&&o.headers.get("content-type")||"";if(!/json|^text\//i.test(s))return;let r;try{r=o.clone()}catch{return}n(r.text().then(i=>{e.tainted||i.length>jt||e.bytes+i.length>Et||(e.bytes+=i.length,e.entries.push({url:t.url,lang:t.headers["accept-language"]||"",status:o.status,type:s,body:i}))},()=>{}))},$t=()=>{const e=globalThis.fetch;if(typeof e!="function"||e[Le])return;const t=function(...o){U++;let n=!1;const s=()=>{n||(n=!0,U--)},r=c=>{U++,c.then(()=>{U--},()=>{U--})},i=de(De),f=de(me);let l=null;if(i)try{l=Lt(o),(l.method!=="GET"||!/^https?:/i.test(l.url)||Object.keys(l.headers).some(c=>!Tt.has(c)))&&(l=null)}catch{l=null}const g=()=>Ae(o[0]);let p;try{p=e.apply(this,o)}catch(c){throw ge(f,g(),c&&c.message||"failed"),s(),c}return p&&typeof p.then=="function"?p.then(c=>{l&&Dt(i,l,c,r),f&&c&&c.ok===!1&&ge(f,g(),"HTTP "+c.status),s()},c=>{ge(f,g(),c&&c.message||"network error"),s()}):s(),p};t[Le]=!0,globalThis.fetch=t},Mo=({brRegistry:e,fetchSeed:t,hydrateFlag:o=!0}={})=>{if(!e||!Object.keys(e).length)return"";const n=pt(e);return o?`<script>window.__BR_REGISTRY__=${n};window.__BRENDER_HYDRATE__=true<\/script>`+(t&&t.length?`
|
|
2
|
+
`+st(t):""):`<script>window.__BR_REGISTRY__=${n}<\/script>`},At=3e4,Ct=2147483647;let Ce=Promise.resolve();const qe=()=>{},qt=e=>{const t=Ce.then(e);return Ce=t.then(qe,qe),t},Mt=e=>{if(e===void 0)return At;if(e===0||e===!1||e===1/0)return 0;if(typeof e!="number"||!(e>0))throw new TypeError(`brender: options.timeout is a number of milliseconds, or 0 / false for no limit \u2014 not ${JSON.stringify(e)}`);return Math.min(e,Ct)},It=(e,t)=>{const o=e.route||"/",n=e.pathname||o,s=n===o?o:`${n} (route ${o})`,r=new Error(`brender: the render of ${s} did not finish within ${t} ms and was abandoned, so the renders after it can run (options.timeout)`);return r.code="BRENDER_RENDER_TIMEOUT",r.route=o,r.pathname=n,r.timeout=t,r},Ot=e=>{e.closed=!0;for(const t of e.undo.splice(0))t()},Pt=e=>{let t=!1;return()=>{t||(t=!0,e())}},Me=(e,t={})=>{let o;try{o=Mt(t.timeout)}catch(n){return Promise.reject(n)}return qt(()=>Ft(e,t,o))},Ft=async(e,t,o)=>{await _e();const n={closed:!1,undo:[]},s=Bt(e,t,n);if(!o)return s;let r;const i=new Promise((f,l)=>{r=setTimeout(()=>{Ot(n),l(It(t,o))},o)});try{return await Promise.race([s,i])}finally{clearTimeout(r)}},Bt=async(e,t,o)=>{const{route:n="/",pathname:s,state:r,context:i,prefetch:f=!1}=t,l=s||n;$t();const g=$e(me,()=>({failures:[],labelKeys:new Set,tainted:!1}));try{return await Kt(e,{route:n,locationPath:l,stateOverrides:r,contextOverrides:i,prefetch:f},g.record,o)}finally{g.close()}},Kt=async(e,{route:t,locationPath:o,stateOverrides:n,contextOverrides:s,prefetch:r},i,f)=>{const l=()=>{if(f.closed)throw new Error("brender: this render was abandoned at its timeout")};let g;if(r){try{g=await nt(e)}catch(d){f.closed||console.warn("[brender] SSR translation fetch failed:",d.message)}l()}const{window:p,document:c}=Se(),a=c.body;p.location.pathname=o;const u=[ie("document",c),ie("location",p.location),ie("localStorage",p.localStorage),ie("sessionStorage",p.sessionStorage)].map(Pt);f.undo.push(...u);try{const{createDomqlElement:d,PRERENDER_REGISTRY_FORMATS:b}=await _e();l();const E=L(e.app||{}),x={...e.config||{}};e.polyglot&&!x.polyglot&&(x.polyglot=e.polyglot),e.fetch&&!x.fetch&&(x.fetch=e.fetch),e.router&&!x.router&&(x.router=e.router);for(const y of Jt)e[y]!=null&&x[y]==null&&(x[y]=e[y]);const w=x.polyglot?{...x.polyglot}:void 0,X=ut(o,w);X&&p.localStorage.setItem(ft(w),X),g&&w&&(w.translations={...w.translations||{},...g});const v=L(e.state||{});(g||w)&&(v.root||(v.root={}),w&&(v.root.lang=oe(v.root.lang,w)),g&&(v.root.translations={...v.root.translations||{},...g})),ht();const P={};for(const y in e){if(xt.has(y))continue;const k=e[y];P[y]=k&&typeof k=="object"?L(k):k}const A={...P,state:v,...n?{state:{...v,...n}}:{},dependencies:L(e.dependencies||{}),components:L(e.components||{}),snippets:L(e.snippets||{}),pages:L(e.pages||{}),functions:{...e.functions||{},polyglot:yt,getActiveLang:je,getLang:je},methods:e.methods||{},designSystem:L(e.designSystem||{}),files:e.files||{},sharedLibraries:e.sharedLibraries||[],...x,...w?{polyglot:w}:{},document:c,window:p,parent:{node:a},initOptions:{},domqlOptions:{sourcemap:!1},firstRender:!1,sync:!1,inspect:!1,notifications:!1,isolateDesignSystem:!0,isolateFetchCache:!0,captureDesignSystem:!0,...s||{}},G=await dt();l(),G&&(A.plugins=A.plugins||[],A.plugins.some(y=>y.name==="funcql")||A.plugins.push(G)),Re();const S=$e(De,()=>({entries:[],bytes:0,tainted:!1})),C=S.record;let j;try{j=await d(E,A),l();const y=Date.now(),k=r?2e3:50,K=ae=>new Promise(Ne=>setTimeout(Ne,ae));for(await K(Math.min(50,k));r&&!f.closed&&ue()>0&&Date.now()-y<k;)await K(10),ue()===0&&await K(Math.max(0,Math.min(50,k-(Date.now()-y))));if(l(),r&&await Gt(j,w)){l();const ae=Date.now();for(await K(Math.min(50,k));!f.closed&&ue()>0&&Date.now()-ae<k;)await K(10);l()}}finally{S.close()}const q=C&&!C.tainted&&!(x.fetch&&x.fetch.seed===!1)?C.entries.slice():[];ke(a);const W=we(j),{elementPath:M}=await import("@symbo.ls/element");l();const be=wt(j,M),Q=j?.context?.routerOptions?.contentElementKey||"content",F=j&&j[Q],Z=F&&typeof F=="object"&&F.__ref?F:void 0,ee=pe(e,t,j,j?.state,Z),B=[],I=c.head||c.querySelector("head");if(I)for(const y of I.querySelectorAll("style")){if(y.sheet&&y.sheet.cssRules)for(const k of y.sheet.cssRules)k.cssText&&B.push(k);if(!B.length){const k=y.textContent||"";k&&B.push({cssText:k})}}const J=B.map(y=>y.cssText),{globalCSS:Y,classRules:N}=Zt(B);let D=Pe(a.innerHTML);const $=j?.state?.root,te=re($,w),R=Nt(g,$);R&&(D=Oe(D,Ie(R,te,w)));const T=i&&!i.tainted?{failedRequests:i.failures.slice(),rawLabelKeys:Wt(i.labelKeys,D,te,w,$)}:null;return{html:D,metadata:ee,registry:W,brRegistry:be,element:j,emotionCSS:J,globalCSS:Y,classRules:N,fetchSeed:q,document:c,window:p,ssrTranslations:R||void 0,activeLang:te,diagnostics:T,preparedDesignSystem:A.preparedDesignSystem||null,registryFormats:Array.isArray(b)?b.slice():["paths"]}}finally{for(const d of u)d()}},ie=(e,t)=>{const o=Object.getOwnPropertyDescriptor(globalThis,e);return o&&!o.configurable?!o.writable&&!o.set?()=>{}:(globalThis[e]=t,()=>{}):(Object.defineProperty(globalThis,e,{value:t,writable:!0,configurable:!0,enumerable:!0}),()=>{o?Object.defineProperty(globalThis,e,o):delete globalThis[e]})},Gt=async(e,t)=>{if(!t||!t.fetch||!e||typeof e.call!="function")return!1;const o=e.state&&e.state.root;if(!o)return!1;const n=re(o,t),s=o.translations&&o.translations[n];if(s&&typeof s=="object"&&Object.keys(s).length||t.translations&&t.translations[n])return!1;try{await e.call("loadTranslations",n,{inFlight:!0})}catch{}return!0},he=/\{\{\s*([^|{}]+?)\s*\|\s*polyglot\s*\}\}/g,ye=e=>e&&typeof e.parse=="function"?e.parse():e,Nt=(e,t)=>{const o=ye(t?.translations),n={};for(const s of[e,o])if(!(!s||typeof s!="object"))for(const r in s){const i=ye(s[r]);i&&typeof i=="object"&&(n[r]={...n[r]||{},...i})}return Object.keys(n).length?n:null},Ie=(e,t,o)=>e[t]||e[oe(void 0,o)]||Object.values(e)[0]||{},Oe=(e,t)=>e.replace(he,(o,n)=>se(t,n.trim())??o),Ht=/<script\b[^>]*\btype\s*=\s*["']?application\/json["']?[^>]*>[\s\S]*?<\/script\s*>/gi,Ut=(e,t)=>new RegExp(`(?:^|[^\\w.-])${lt(t)}(?![\\w-]|\\.\\w)`).test(e),Wt=(e,t,o,n,s)=>{const r=new Set,i=t.replace(Ht,"");for(const f of e)/\s/.test(f)||xe(f,o,n,s)===void 0&&Ut(i,f)&&r.add(f);for(const f of i.matchAll(he))r.add(f[1].trim());return[...r]},Io=async(e,t={})=>{const{context:o={}}=t,{window:n,document:s}=Se(),r=s.body,{create:i}=await import("@symbo.ls/element"),f=await import("@symbo.ls/utils"),l={...kt,...o.components||{}},g={...f,...o.utils||{},...o.functions||{}};Re();let p;try{p=i(e,{node:r},"root",{context:{document:s,window:n,...o,components:l,utils:g}})}catch{}ke(r);const c=p?we(p):{};return{html:Pe(r.innerHTML),registry:c,element:p}},Pe=e=>e.replace(/(<svg\b[^>]*>)([\s\S]*?)(<\/svg>)/gi,(t,o,n,s)=>{if(n.includes("<")){const r=n.replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&").replace(/"/g,'"').replace(/'/g,"'");return o+r+s}return t}),Jt=["globalTheme","themeStorageKey","themeRoot","useReset","useVariable","useFontImport","useIconSprite","useSvgSprite","useDocumentTheme","useDefaultConfig","useDefaultIcons","useThemeSuffixedVars","verbose","semanticIcons"],Yt=new Set(["auto","system"]),Fe=e=>{if(!e||typeof e!="object")return null;const t=e.config&&typeof e.config=="object"?e.config:{};if((t.themeRoot!=null?t.themeRoot:e.themeRoot)!=null)return null;const n=t.globalTheme!=null?t.globalTheme:e.globalTheme;if(typeof n!="string")return null;const s=n.trim();return!s||Yt.has(s)?null:s},zt=e=>String(e).replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<"),Vt=/\.[A-Za-z_\\-]/,Xt=e=>{if(typeof e!="string"||!e)return!1;const t=e.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g,'""').replace(/\[[^\]]*\]/g,"[]");return!Vt.test(t)},Qt=/^\s*(:root|\[data-theme|\[data-skin)/,Be=e=>{const t=e&&e.cssText;if(typeof t!="string")return null;if(/^@(-webkit-)?keyframes\b/.test(t))return"keyframes";if(t.startsWith("@font-face"))return null;if(typeof e.selectorText=="string")return Xt(e.selectorText)?Qt.test(e.selectorText)?"root":"reset":null;const o=e.cssRules&&Array.from(e.cssRules);if(o&&o.length&&/^@(media|supports|container)\b/.test(t)){const n=new Set(o.map(Be));return n.has(null)||n.size!==1?n.has(null)?null:"reset":[...n][0]}return null},Zt=e=>{const t={root:[],reset:[],keyframes:[]},o=[];for(const n of e||[]){const s=Be(n);s?t[s].push(n.cssText):n&&n.cssText&&o.push(n.cssText)}return{globalCSS:{rootRule:t.root.join(`
|
|
3
3
|
`),resetRules:t.reset.join(`
|
|
4
4
|
`),keyframeRules:t.keyframes.join(`
|
|
5
|
-
`),fontFaceCSS:""},classRules:o}};let
|
|
6
|
-
`),
|
|
5
|
+
`),fontFaceCSS:""},classRules:o}};let V=new Set;const Oo=()=>{V=new Set},Po=()=>Array.from(V).join(`
|
|
6
|
+
`),Fo=(e,t)=>e.replace(/<style data-emotion="smbls">[\s\S]*?<\/style>/,t?`<style data-emotion="smbls">
|
|
7
7
|
${t}
|
|
8
|
-
</style>`:""),
|
|
9
|
-
`),classRules:i.classRules.slice(),globalCSS:l,resetCss:l.resetRules,fontLinks:
|
|
10
|
-
`)
|
|
11
|
-
|
|
12
|
-
${
|
|
13
|
-
${
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
`:""
|
|
8
|
+
</style>`:""),Bo=async(e,t={})=>{const{route:o="/",pathname:n,prefetch:s=!0,timeout:r}=t,i=await Me(e,{route:o,pathname:n,prefetch:s,timeout:r});if(!i)return null;const f=e.designSystem||{},l=i.globalCSS;let g=null;try{const c=eo(i.element);Object.keys(c).length&&(g=c)}catch{}const p=i.activeLang;return{html:i.html,css:i.classRules.join(`
|
|
9
|
+
`),classRules:i.classRules.slice(),globalCSS:l,resetCss:l.resetRules,fontLinks:Ge(f),metadata:i.metadata||pe(e,o),brKeyCount:i.registry?Object.keys(i.registry).length:0,brRegistry:i.brRegistry||{},fetchSeed:i.fetchSeed||[],ssrTranslations:i.ssrTranslations,prefetchedState:g,activeLang:p,theme:Fe(e),diagnostics:i.diagnostics,preparedDesignSystem:i.preparedDesignSystem||null}},eo=e=>{const t={};return ve(e,o=>{const n=o.fetch;if(!(!n||typeof n!="object"||!o.state))for(const s of Array.isArray(n)?n:[n]){const r=s&&typeof s=="object"&&typeof s.as=="string"?s.as:null;if(!r)continue;const i=r.startsWith("~/"),f=i?r.slice(2):r,l=i?o.state.root:o.state,g=ye(l&&l[f]);f&&g!=null&&typeof g!="function"&&(t[f]=g)}}),t},Ko=async(e,t="/",o={})=>{const{lang:n,themeColor:s,isr:r,hydrate:i=!0,prefetch:f=!0,shell:l,adoptDom:g=!1,pathname:p,eagerImages:c=Ke,preloadScripts:a=!0,nonce:u,timeout:d,stamp:b,time:E,spriteIcons:x="all",cssClasses:w="all",cssVariables:X="all",registryFormat:v="paths"}=o,P=co(u),A=n||e.state?.lang||e.app?.metadata?.lang||"en",G=Fe(e),S=await Me(e,{route:t,pathname:p,prefetch:f,timeout:d});if(!S)return null;const C={...S.metadata};if(s&&(C["theme-color"]=s),typeof l=="string"&&!e.name){const R="\0brender-undeclared-title\0";if(pe({...e,name:R},t,S.element,S.element?.state).title===R)for(const y of["title","og:title","twitter:title"])C[y]===S.metadata.title&&delete C[y]}const j=Xe(C);for(const R of S.classRules)R&&V.add(R);let q=no(S.html,c);x==="page"&&(q=Ze(q,typeof l=="string"?l:"").html);const W=w==="page"?et(Array.from(V),tt(q,typeof l=="string"?l:"")).join(`
|
|
10
|
+
`):Array.from(V).join(`
|
|
11
|
+
`),M=S.globalCSS,Q=`<style data-brender>
|
|
12
|
+
${(X==="page"?ot(M.rootRule||"",M.resetRules,M.keyframeRules,W,q,typeof l=="string"?l:"").css:M.rootRule)||""}
|
|
13
|
+
${M.resetRules||""}
|
|
14
|
+
${M.keyframeRules||""}
|
|
15
|
+
</style>`,F=W?`<style data-emotion="smbls">
|
|
16
|
+
${W}
|
|
17
|
+
</style>`:"",Z=Ge(e.designSystem||{}),ee=Object.keys(S.registry).length,B=v==="tree"||v==="auto"&&(S.registryFormats||[]).includes("tree"),I=so({brRegistry:S.brRegistry,fetchSeed:S.fetchSeed,adoptDom:g,stamp:b,time:E,registryFormat:B?"tree":"paths"});let J="";if(r&&r.clientScript){const R=Number.isInteger(o.depth)?o.depth:t==="/"?0:t.replace(/^\/|\/$/g,"").split("/").length,T=R>0?"../".repeat(R):"./";if(i){const y=mt({polyglot:e.polyglot||e.config?.polyglot,translations:S.ssrTranslations,lang:S.activeLang,pathname:p||t,attrs:P}),k=y?y+`
|
|
18
|
+
`:"",K=I.blocks?I.blocks+`
|
|
19
|
+
`:"";J=`${k}${K}<script type="module" src="${T}${r.clientScript}"${P}><\/script>`}else J=`<script type="module"${P}>
|
|
19
20
|
{
|
|
20
21
|
const brEls = document.querySelectorAll('body > :not(script):not(style)')
|
|
21
22
|
const observer = new MutationObserver((mutations) => {
|
|
@@ -32,23 +33,23 @@ ${K}
|
|
|
32
33
|
observer.observe(document.body, { childList: true })
|
|
33
34
|
}
|
|
34
35
|
<\/script>
|
|
35
|
-
<script type="module" src="${
|
|
36
|
-
${
|
|
37
|
-
`),body:
|
|
38
|
-
<html lang="${
|
|
36
|
+
<script type="module" src="${T}${r.clientScript}"${P}><\/script>`}const Y={...e.config||{}};e.polyglot&&!Y.polyglot&&(Y.polyglot=e.polyglot);const N=Y.polyglot;let D=j;if(N){const R={...N.translations||{}};for(const T in S.ssrTranslations||{})R[T]={...R[T]||{},...S.ssrTranslations[T]};D=Oe(j,Ie(R,S.activeLang,N))}const $=S.diagnostics;if($)for(const R of D.matchAll(he)){const T=R[1].trim();$.rawLabelKeys.includes(T)||$.rawLabelKeys.push(T)}return typeof l=="string"?{html:Qe(l,{headTags:`${D}
|
|
37
|
+
${I.meta}`,headEnd:[Z,Q,F].filter(Boolean).join(`
|
|
38
|
+
`),body:q,depth:Number.isInteger(o.depth)?o.depth:0,bootScripts:I.blocks,lang:n||(N?S.activeLang:void 0),theme:G,preloadScripts:a}),route:t,brKeyCount:ee,shell:!0,diagnostics:$,preparedDesignSystem:S.preparedDesignSystem||null}:{html:`<!DOCTYPE html>
|
|
39
|
+
<html lang="${A}"${G?` data-theme="${zt(G)}"`:""}>
|
|
39
40
|
<head>
|
|
40
|
-
${
|
|
41
|
-
${
|
|
42
|
-
${
|
|
41
|
+
${D}${r&&r.clientScript&&i?`
|
|
42
|
+
${I.meta}`:""}
|
|
43
|
+
${Z}
|
|
43
44
|
|
|
44
|
-
${
|
|
45
|
-
${
|
|
45
|
+
${Q}
|
|
46
|
+
${F}
|
|
46
47
|
</head>
|
|
47
48
|
<body>
|
|
48
|
-
${
|
|
49
|
-
${
|
|
49
|
+
${q}
|
|
50
|
+
${J}
|
|
50
51
|
</body>
|
|
51
|
-
</html>`,route:t,brKeyCount:
|
|
52
|
-
`):""},
|
|
53
|
-
`+
|
|
54
|
-
`)}},
|
|
52
|
+
</html>`,route:t,brKeyCount:ee,diagnostics:$,preparedDesignSystem:S.preparedDesignSystem||null}},Ke=2,to=/<img\b(?:[^>"']|"[^"]*"|'[^']*')*>/gi,oo=/\sloading\s*=/i,no=(e,t=Ke)=>{if(t===!1||t==null||typeof e!="string")return e;const o=Math.max(0,Number(t)||0);let n=0;return e.replace(to,s=>n++<o||oo.test(s)?s:s.replace(/^<img\b/i,'<img loading="lazy"'))},Ge=e=>{if(!e)return"";const t=e.font_family||e.fontFamily||{},o=new Set;for(const s of Object.values(t)){if(typeof s!="string")continue;const r=s.match(/'([^']+)'/);r&&o.add(r[1])}return o.size?['<link rel="preconnect" href="https://fonts.googleapis.com">','<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>',`<link href="https://fonts.googleapis.com/css2?${[...o].map(s=>`family=${s.replace(/\s+/g,"+")}:wght@300;400;500;600;700`).join("&")}&display=swap" rel="stylesheet">`].join(`
|
|
53
|
+
`):""},so=({brRegistry:e,fetchSeed:t,adoptDom:o=!1,stamp:n,time:s,registryFormat:r="paths"}={})=>{const f=o&&e&&Object.keys(e).length?r==="tree"&&it(e)||ct(e):"",l=gt(t);return{meta:`<meta name="brender" content="${f?"hydrate":"replace"}">
|
|
54
|
+
`+at(ro(n,s)),blocks:[f,l].filter(Boolean).join(`
|
|
55
|
+
`)}},ro=(e,t)=>{const o=typeof t=="number"&&isFinite(t)?Math.round(t):Date.now();return{stamp:e!=null&&e!==""?String(e):new Date(o).toISOString(),time:o}},co=e=>{if(e==null||e==="")return"";const t=String(e);if(!/^[A-Za-z0-9+/=_-]+$/.test(t))throw new Error("brender: a nonce is base64 or base64url text");return` nonce="${t}"`};export{Ke as EAGER_IMAGES_DEFAULT,Te as SMBLS_SSR_SPECIFIER,Mo as adoptionScripts,ro as buildStamp,Fe as fixedThemeOf,Po as getAccumulatedEmotionCSS,no as markLazyImages,so as prerenderParts,Me as render,Io as renderElement,Ko as renderPage,Bo as renderRoute,Fo as replaceEmotionCSS,Oo as resetGlobalCSSCache,Zt as splitCapturedCSS};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbo.ls/brender",
|
|
3
|
-
"version": "3.14.
|
|
3
|
+
"version": "3.14.671",
|
|
4
4
|
"license": "CC-BY-NC-4.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -48,16 +48,16 @@
|
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@symbo.ls/css": "^3.14.782",
|
|
50
50
|
"@symbo.ls/default-config": "^3.14.789",
|
|
51
|
-
"@symbo.ls/element": "^3.14.
|
|
51
|
+
"@symbo.ls/element": "^3.14.813",
|
|
52
52
|
"@symbo.ls/fetch": "^3.14.669",
|
|
53
53
|
"@symbo.ls/helmet": "^3.14.671",
|
|
54
|
-
"@symbo.ls/scratch": "^3.14.
|
|
55
|
-
"@symbo.ls/utils": "^3.14.
|
|
54
|
+
"@symbo.ls/scratch": "^3.14.795",
|
|
55
|
+
"@symbo.ls/utils": "^3.14.848",
|
|
56
56
|
"esbuild": "^0.28.1",
|
|
57
57
|
"linkedom": "^0.16.8"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
|
-
"smbls": "^3.14.
|
|
60
|
+
"smbls": "^3.14.848"
|
|
61
61
|
},
|
|
62
62
|
"optionalDependencies": {
|
|
63
63
|
"@symbo.ls/funcql": "^3.14.0"
|
package/pageWeight.js
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
// ── The weight of a page built ahead (XMA round 8) ─────────────────────────
|
|
2
|
+
// Every page `smbls build` writes carried the WHOLE project's share of three
|
|
3
|
+
// things the page itself never reads before the app boots: the icon sprite
|
|
4
|
+
// (every icon of the design system — 66 on XMA, 10 on its home), the atomic
|
|
5
|
+
// rules of every page rendered before it in the build, and the design
|
|
6
|
+
// system's every CSS variable. The client needs none of them from the page:
|
|
7
|
+
// its design-system init fills the sprite with every icon (smbls init.js
|
|
8
|
+
// applyDesignSystem → scratch appendSvgIconsSprite, which adds the symbols a
|
|
9
|
+
// sprite lacks), its atomic engine inserts the rules of every element it
|
|
10
|
+
// creates into its own sheets, and it injects every variable itself — the
|
|
11
|
+
// server's styles go once the hydration window closes (smbls prerender.js
|
|
12
|
+
// removeServerStyles). So what a page must carry is what it paints before
|
|
13
|
+
// the boot: the icons its markup uses, the rules of the classes in its
|
|
14
|
+
// markup, the variables its CSS reads. Each trim below keeps that and drops
|
|
15
|
+
// the rest. Pure string work on the page's own serialized output; anything
|
|
16
|
+
// the parser does not recognise is left as it is (over-keeping costs bytes,
|
|
17
|
+
// under-keeping would cost a page).
|
|
18
|
+
|
|
19
|
+
// ── The icon sprite (E6) ────────────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
// scratch createSVGSpriteElement: `<svg … id="svgSprite" …>` holding one
|
|
22
|
+
// `<symbol id>` per icon. Symbols never nest, so each runs to its own
|
|
23
|
+
// `</symbol>`.
|
|
24
|
+
const SPRITE_OPEN = /<svg\b[^>]*\sid="svgSprite"[^>]*>/
|
|
25
|
+
const SYMBOL_AT = /\s*<symbol\b[^>]*>[\s\S]*?<\/symbol>/y
|
|
26
|
+
const SPRITE_CLOSE_AT = /\s*<\/svg>/y
|
|
27
|
+
const SYMBOL_ID = /^\s*<symbol\b[^>]*?\sid="([^"]+)"/
|
|
28
|
+
// A fragment reference — `href="#x"`, `xlink:href="#x"`, `url(#x)` — or any
|
|
29
|
+
// `#token`: a hex colour that happens to spell an icon's name keeps it, which
|
|
30
|
+
// is the safe direction.
|
|
31
|
+
const FRAGMENT = /#([^\s"'()<>&,;#]+)/g
|
|
32
|
+
|
|
33
|
+
const fragmentsIn = (text, into) => {
|
|
34
|
+
if (typeof text !== 'string' || !text) return into
|
|
35
|
+
FRAGMENT.lastIndex = 0
|
|
36
|
+
let m
|
|
37
|
+
while ((m = FRAGMENT.exec(text))) into.add(m[1])
|
|
38
|
+
return into
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The page's icon sprite with only the symbols the page references (and the
|
|
43
|
+
* symbols those reference). The client's design-system init adds every other
|
|
44
|
+
* icon of the design system to the same sprite before the app is created, so
|
|
45
|
+
* an icon the page shows later (after a click, on new data) is there when it
|
|
46
|
+
* renders. Returns `html` unchanged when it has no sprite or the sprite holds
|
|
47
|
+
* anything but symbols.
|
|
48
|
+
* @param {string} html - the page's body markup
|
|
49
|
+
* @param {string} [context] - other markup of the same document (the shell)
|
|
50
|
+
* @returns {{ html: string, kept: number, dropped: number }}
|
|
51
|
+
*/
|
|
52
|
+
export const trimSpriteToPage = (html, context = '') => {
|
|
53
|
+
const none = { html, kept: 0, dropped: 0 }
|
|
54
|
+
if (typeof html !== 'string') return none
|
|
55
|
+
const open = SPRITE_OPEN.exec(html)
|
|
56
|
+
if (!open) return none
|
|
57
|
+
const start = open.index
|
|
58
|
+
let at = start + open[0].length
|
|
59
|
+
const symbols = []
|
|
60
|
+
for (;;) {
|
|
61
|
+
SYMBOL_AT.lastIndex = at
|
|
62
|
+
const m = SYMBOL_AT.exec(html)
|
|
63
|
+
if (!m) break
|
|
64
|
+
const id = SYMBOL_ID.exec(m[0])
|
|
65
|
+
symbols.push({ text: m[0], id: id ? id[1] : null })
|
|
66
|
+
at = SYMBOL_AT.lastIndex
|
|
67
|
+
}
|
|
68
|
+
SPRITE_CLOSE_AT.lastIndex = at
|
|
69
|
+
const close = SPRITE_CLOSE_AT.exec(html)
|
|
70
|
+
// Something other than a symbol inside the sprite: left alone.
|
|
71
|
+
if (!close) return none
|
|
72
|
+
const end = SPRITE_CLOSE_AT.lastIndex
|
|
73
|
+
|
|
74
|
+
const outside = html.slice(0, start) + html.slice(end)
|
|
75
|
+
const wanted = fragmentsIn(context, fragmentsIn(outside, new Set()))
|
|
76
|
+
// A kept symbol can use another one: keep what it references too.
|
|
77
|
+
const keep = new Set()
|
|
78
|
+
const byId = new Map()
|
|
79
|
+
for (const s of symbols) if (s.id) byId.set(s.id, s)
|
|
80
|
+
const queue = [...wanted]
|
|
81
|
+
while (queue.length) {
|
|
82
|
+
const id = queue.pop()
|
|
83
|
+
const s = byId.get(id)
|
|
84
|
+
if (!s || keep.has(s)) continue
|
|
85
|
+
keep.add(s)
|
|
86
|
+
for (const ref of fragmentsIn(s.text, new Set())) if (byId.has(ref)) queue.push(ref)
|
|
87
|
+
}
|
|
88
|
+
// An anonymous symbol is kept: nothing can name it, but nothing proves it
|
|
89
|
+
// unused either.
|
|
90
|
+
const kept = symbols.filter((s) => !s.id || keep.has(s))
|
|
91
|
+
if (kept.length === symbols.length) return { html, kept: kept.length, dropped: 0 }
|
|
92
|
+
const sprite = open[0] + kept.map((s) => s.text).join('') + html.slice(at, end)
|
|
93
|
+
return { html: html.slice(0, start) + sprite + html.slice(end), kept: kept.length, dropped: symbols.length - kept.length }
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ── The atomic rules (E12) ──────────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
// Quoted strings and attribute brackets, masked before a selector is read:
|
|
99
|
+
// a dot inside `[href$=".pdf"]` is not a class (render.js isGlobalSelector).
|
|
100
|
+
const maskSelector = (text) => text
|
|
101
|
+
.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g, '""')
|
|
102
|
+
.replace(/\[[^\]]*\]/g, '[]')
|
|
103
|
+
const CLASS_TOKEN = /\.(-?(?:[_A-Za-z -]|\\.)(?:[\w --]|\\.)*)/g
|
|
104
|
+
const unescapeClass = (name) => name.replace(/\\(?:([0-9a-fA-F]{1,6})\s?|(.))/g, (m, hex, ch) => (hex ? String.fromCodePoint(parseInt(hex, 16)) : ch))
|
|
105
|
+
|
|
106
|
+
// The preludes of a CSS text — every selector list and at-rule prelude in
|
|
107
|
+
// front of a `{` — at any depth; declaration blocks are skipped.
|
|
108
|
+
const preludesOf = (css) => {
|
|
109
|
+
const out = []
|
|
110
|
+
let start = 0
|
|
111
|
+
let quote = null
|
|
112
|
+
for (let i = 0; i < css.length; i++) {
|
|
113
|
+
const ch = css[i]
|
|
114
|
+
if (quote) {
|
|
115
|
+
if (ch === '\\') i++
|
|
116
|
+
else if (ch === quote) quote = null
|
|
117
|
+
continue
|
|
118
|
+
}
|
|
119
|
+
if (ch === '"' || ch === "'") quote = ch
|
|
120
|
+
else if (ch === '{') {
|
|
121
|
+
out.push(css.slice(start, i).trim())
|
|
122
|
+
start = i + 1
|
|
123
|
+
} else if (ch === '}' || ch === ';') start = i + 1
|
|
124
|
+
}
|
|
125
|
+
return out
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* The class names a CSS rule's selectors name (at-rule preludes aside).
|
|
130
|
+
* @param {string} cssText
|
|
131
|
+
* @returns {string[]}
|
|
132
|
+
*/
|
|
133
|
+
export const ruleClasses = (cssText) => {
|
|
134
|
+
const names = []
|
|
135
|
+
for (const prelude of preludesOf(String(cssText || ''))) {
|
|
136
|
+
if (!prelude || prelude[0] === '@') continue
|
|
137
|
+
CLASS_TOKEN.lastIndex = 0
|
|
138
|
+
const masked = maskSelector(prelude)
|
|
139
|
+
let m
|
|
140
|
+
while ((m = CLASS_TOKEN.exec(masked))) names.push(unescapeClass(m[1]))
|
|
141
|
+
}
|
|
142
|
+
return names
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const CLASS_ATTR = /\sclass\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+))/gi
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Every class name the markup's `class` attributes carry.
|
|
149
|
+
* @param {...string} texts
|
|
150
|
+
* @returns {Set<string>}
|
|
151
|
+
*/
|
|
152
|
+
export const markupClasses = (...texts) => {
|
|
153
|
+
const out = new Set()
|
|
154
|
+
for (const text of texts) {
|
|
155
|
+
if (typeof text !== 'string' || !text) continue
|
|
156
|
+
CLASS_ATTR.lastIndex = 0
|
|
157
|
+
let m
|
|
158
|
+
while ((m = CLASS_ATTR.exec(text))) {
|
|
159
|
+
const value = m[1] ?? m[2] ?? m[3] ?? ''
|
|
160
|
+
for (const name of value.split(/\s+/)) if (name) out.add(name.replace(/&/g, '&'))
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return out
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* The atomic rules a page's markup can match: each rule that names a class
|
|
168
|
+
* the page carries, and each rule that names none (an @font-face). The
|
|
169
|
+
* client's atomic engine writes the rules of every element it creates into
|
|
170
|
+
* its own sheets (an element created after the boot — a click, new data —
|
|
171
|
+
* gets its rules there), and the server's sheet goes when the hydration
|
|
172
|
+
* window closes, so the page only needs what styles its own markup until
|
|
173
|
+
* then. Order is kept: the cascade between kept rules does not change.
|
|
174
|
+
* @param {string[]} rules - cssText of each rule (renderPage's accumulated set)
|
|
175
|
+
* @param {Set<string>} classes - markupClasses of the page
|
|
176
|
+
* @returns {string[]}
|
|
177
|
+
*/
|
|
178
|
+
export const classRulesForPage = (rules, classes) => {
|
|
179
|
+
const out = []
|
|
180
|
+
for (const rule of rules || []) {
|
|
181
|
+
if (!rule) continue
|
|
182
|
+
const names = ruleClasses(rule)
|
|
183
|
+
if (!names.length || names.some((name) => classes.has(name))) out.push(rule)
|
|
184
|
+
}
|
|
185
|
+
return out
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ── The CSS variables (E7) ──────────────────────────────────────────────────
|
|
189
|
+
|
|
190
|
+
const VAR_REF = /var\(\s*(--[\w-]+)/g
|
|
191
|
+
const CUSTOM_DECLARATION = /^\s*(--[\w-]+)\s*:([\s\S]*)$/
|
|
192
|
+
|
|
193
|
+
const varRefsIn = (text, into) => {
|
|
194
|
+
if (typeof text !== 'string' || !text) return into
|
|
195
|
+
VAR_REF.lastIndex = 0
|
|
196
|
+
let m
|
|
197
|
+
while ((m = VAR_REF.exec(text))) into.add(m[1])
|
|
198
|
+
return into
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Walk a CSS text and hand each declaration (the text between `{`/`;` and
|
|
202
|
+
// `;`/`}` inside a block) to `onDeclaration`, which returns what to write in
|
|
203
|
+
// its place. Preludes, braces and everything else are copied as they are.
|
|
204
|
+
// Strings and parentheses (a `;` inside `url(data:…;base64,…)`) are skipped.
|
|
205
|
+
const mapDeclarations = (css, onDeclaration) => {
|
|
206
|
+
let out = ''
|
|
207
|
+
let start = 0
|
|
208
|
+
let quote = null
|
|
209
|
+
let parens = 0
|
|
210
|
+
for (let i = 0; i < css.length; i++) {
|
|
211
|
+
const ch = css[i]
|
|
212
|
+
if (quote) {
|
|
213
|
+
if (ch === '\\') i++
|
|
214
|
+
else if (ch === quote) quote = null
|
|
215
|
+
continue
|
|
216
|
+
}
|
|
217
|
+
if (ch === '"' || ch === "'") quote = ch
|
|
218
|
+
else if (ch === '(') parens++
|
|
219
|
+
else if (ch === ')') parens = Math.max(0, parens - 1)
|
|
220
|
+
else if (parens) continue
|
|
221
|
+
else if (ch === '{') {
|
|
222
|
+
out += css.slice(start, i + 1)
|
|
223
|
+
start = i + 1
|
|
224
|
+
} else if (ch === ';') {
|
|
225
|
+
out += onDeclaration(css.slice(start, i), ';')
|
|
226
|
+
start = i + 1
|
|
227
|
+
} else if (ch === '}') {
|
|
228
|
+
out += onDeclaration(css.slice(start, i), '') + '}'
|
|
229
|
+
start = i + 1
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return out + css.slice(start)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* The page's variable blocks (`:root`, the `[data-theme]` / skin blocks, the
|
|
237
|
+
* `prefers-color-scheme` fallbacks) with only the custom properties the page
|
|
238
|
+
* reads: the ones its CSS and markup name in `var(--…)`, and the ones those
|
|
239
|
+
* name in turn, in every block that defines them. Every other declaration
|
|
240
|
+
* stays. The client injects every variable of the design system as it boots,
|
|
241
|
+
* before the server's styles go (smbls prerender.js), so an element created
|
|
242
|
+
* later still resolves the ones dropped here — but a stylesheet the page
|
|
243
|
+
* links (public CSS, a CDN) is not seen, which is why `smbls build` only
|
|
244
|
+
* does this when the project asks (`brender.cssVariables: 'page'`).
|
|
245
|
+
* @param {string} rootCss - the variable blocks (globalCSS.rootRule)
|
|
246
|
+
* @param {...string} readers - every other text of the page: its other CSS,
|
|
247
|
+
* its markup, the shell
|
|
248
|
+
* @returns {{ css: string, kept: number, dropped: number }}
|
|
249
|
+
*/
|
|
250
|
+
export const trimVariablesToPage = (rootCss, ...readers) => {
|
|
251
|
+
if (typeof rootCss !== 'string' || !rootCss) return { css: rootCss, kept: 0, dropped: 0 }
|
|
252
|
+
const values = new Map()
|
|
253
|
+
const wanted = new Set()
|
|
254
|
+
mapDeclarations(rootCss, (text) => {
|
|
255
|
+
const m = CUSTOM_DECLARATION.exec(text)
|
|
256
|
+
if (m) {
|
|
257
|
+
const list = values.get(m[1]) || []
|
|
258
|
+
list.push(m[2])
|
|
259
|
+
values.set(m[1], list)
|
|
260
|
+
} else varRefsIn(text, wanted)
|
|
261
|
+
return ''
|
|
262
|
+
})
|
|
263
|
+
for (const text of readers) varRefsIn(text, wanted)
|
|
264
|
+
const keep = new Set()
|
|
265
|
+
const queue = [...wanted]
|
|
266
|
+
while (queue.length) {
|
|
267
|
+
const name = queue.pop()
|
|
268
|
+
if (keep.has(name) || !values.has(name)) continue
|
|
269
|
+
keep.add(name)
|
|
270
|
+
for (const value of values.get(name)) for (const ref of varRefsIn(value, new Set())) queue.push(ref)
|
|
271
|
+
}
|
|
272
|
+
let kept = 0
|
|
273
|
+
let dropped = 0
|
|
274
|
+
const css = mapDeclarations(rootCss, (text, end) => {
|
|
275
|
+
const m = CUSTOM_DECLARATION.exec(text)
|
|
276
|
+
if (!m || keep.has(m[1])) {
|
|
277
|
+
if (m) kept++
|
|
278
|
+
return text + end
|
|
279
|
+
}
|
|
280
|
+
dropped++
|
|
281
|
+
return ''
|
|
282
|
+
})
|
|
283
|
+
return { css, kept, dropped }
|
|
284
|
+
}
|
package/render.js
CHANGED
|
@@ -10,10 +10,11 @@ import { resetKeys, assignKeys, mapKeysToElements } from './keys.js'
|
|
|
10
10
|
import { extractMetadata, generateHeadHtml } from './metadata.js'
|
|
11
11
|
import { hydrate } from './hydrate.js'
|
|
12
12
|
import { composeIntoShell } from './shell.js'
|
|
13
|
+
import { trimSpriteToPage, classRulesForPage, markupClasses, trimVariablesToPage } from './pageWeight.js'
|
|
13
14
|
import { fetchSSRTranslations } from './prefetch.js'
|
|
14
15
|
import { createEarlySeedScript } from '@symbo.ls/fetch'
|
|
15
16
|
import { headerEntries } from '@symbo.ls/fetch/rest'
|
|
16
|
-
import { brenderRegistryBlock, brenderStampMeta, escapeRegExp, jsonForScript, polyglotFallbackLang, polyglotLangStorageKey, polyglotAddressLang, polyglotStartupScript } from '@symbo.ls/utils'
|
|
17
|
+
import { brenderRegistryBlock, brenderRegistryTreeBlock, brenderStampMeta, escapeRegExp, jsonForScript, polyglotFallbackLang, polyglotLangStorageKey, polyglotAddressLang, polyglotStartupScript } from '@symbo.ls/utils'
|
|
17
18
|
|
|
18
19
|
// funcql plugin — enables evaluation of funcql schemas as property values
|
|
19
20
|
// during SSR. Async-imported to avoid polluting non-funcql codepaths.
|
|
@@ -1141,7 +1142,7 @@ const renderWithDiagnostics = async (data, { route, locationPath, stateOverrides
|
|
|
1141
1142
|
// Import createDomqlElement via bundled smbls source.
|
|
1142
1143
|
// The smbls monorepo uses extensionless/directory imports that Node.js ESM
|
|
1143
1144
|
// can't resolve natively, so we bundle it with esbuild first.
|
|
1144
|
-
const { createDomqlElement } = await bundleCreateDomql()
|
|
1145
|
+
const { createDomqlElement, PRERENDER_REGISTRY_FORMATS } = await bundleCreateDomql()
|
|
1145
1146
|
live()
|
|
1146
1147
|
|
|
1147
1148
|
const app = structuredCloneDeep(data.app || {})
|
|
@@ -1403,7 +1404,10 @@ const renderWithDiagnostics = async (data, { route, locationPath, stateOverrides
|
|
|
1403
1404
|
}
|
|
1404
1405
|
: null
|
|
1405
1406
|
|
|
1406
|
-
return { html, metadata, registry, brRegistry, element, emotionCSS, globalCSS, classRules, fetchSeed, document, window, ssrTranslations: labels || undefined, activeLang, diagnostics, preparedDesignSystem: ctx.preparedDesignSystem || null
|
|
1407
|
+
return { html, metadata, registry, brRegistry, element, emotionCSS, globalCSS, classRules, fetchSeed, document, window, ssrTranslations: labels || undefined, activeLang, diagnostics, preparedDesignSystem: ctx.preparedDesignSystem || null,
|
|
1408
|
+
// the registry encodings the client of this smbls reads (smbls
|
|
1409
|
+
// prerender.js PRERENDER_REGISTRY_FORMATS); an older smbls reads paths
|
|
1410
|
+
registryFormats: Array.isArray(PRERENDER_REGISTRY_FORMATS) ? PRERENDER_REGISTRY_FORMATS.slice() : ['paths'] }
|
|
1407
1411
|
} finally {
|
|
1408
1412
|
for (const restore of restoreGlobals) restore()
|
|
1409
1413
|
}
|
|
@@ -1869,10 +1873,26 @@ const collectFetchedState = (element) => {
|
|
|
1869
1873
|
* @param {number} [options.depth] - Directory depth of the output file: rebases
|
|
1870
1874
|
* the shell's relative asset URLs (with `shell`, default 0) and the ISR
|
|
1871
1875
|
* client script path (default: derived from the route).
|
|
1876
|
+
* @param {'all'|'page'} [options.spriteIcons='all'] - 'page': the icon sprite
|
|
1877
|
+
* keeps only the icons the page references (pageWeight.js
|
|
1878
|
+
* trimSpriteToPage) — for a page whose client boots with the design
|
|
1879
|
+
* system's icons (`smbls build`); 'all' keeps every icon
|
|
1880
|
+
* @param {'all'|'page'} [options.cssClasses='all'] - 'page': the atomic rules
|
|
1881
|
+
* are the ones the page's markup can match (pageWeight.js
|
|
1882
|
+
* classRulesForPage) instead of every rule the pages rendered so far in
|
|
1883
|
+
* this process needed
|
|
1884
|
+
* @param {'all'|'page'} [options.cssVariables='all'] - 'page': the variable
|
|
1885
|
+
* blocks keep the custom properties the page's CSS and markup read
|
|
1886
|
+
* (pageWeight.js trimVariablesToPage) — a stylesheet the page links is
|
|
1887
|
+
* not read, so it is the project's choice (`brender.cssVariables`)
|
|
1888
|
+
* @param {'paths'|'tree'|'auto'} [options.registryFormat='paths'] - with
|
|
1889
|
+
* `adoptDom`: the element-path registry as paths, as a tree (the same data
|
|
1890
|
+
* in a third of the bytes — @symbo.ls/utils encodeBrenderRegistry), or the
|
|
1891
|
+
* tree when the smbls the page renders with reads it
|
|
1872
1892
|
* @returns {Promise<{ html: string, route: string, brKeyCount: number, shell?: true }>}
|
|
1873
1893
|
*/
|
|
1874
1894
|
export const renderPage = async (data, route = '/', options = {}) => {
|
|
1875
|
-
const { lang, themeColor, isr, hydrate = true, prefetch = true, shell, adoptDom = false, pathname, eagerImages = EAGER_IMAGES_DEFAULT, preloadScripts = true, nonce, timeout, stamp, time } = options
|
|
1895
|
+
const { lang, themeColor, isr, hydrate = true, prefetch = true, shell, adoptDom = false, pathname, eagerImages = EAGER_IMAGES_DEFAULT, preloadScripts = true, nonce, timeout, stamp, time, spriteIcons = 'all', cssClasses = 'all', cssVariables = 'all', registryFormat = 'paths' } = options
|
|
1876
1896
|
const nonceAttr = nonceAttribute(nonce)
|
|
1877
1897
|
|
|
1878
1898
|
// Detect lang from project config, app metadata, or default
|
|
@@ -1917,12 +1937,32 @@ export const renderPage = async (data, route = '/', options = {}) => {
|
|
|
1917
1937
|
for (const rule of result.classRules) {
|
|
1918
1938
|
if (rule) _accumulatedEmotionCSS.add(rule)
|
|
1919
1939
|
}
|
|
1920
|
-
|
|
1940
|
+
|
|
1941
|
+
// Images past the first `eagerImages` load lazily unless they say how to
|
|
1942
|
+
// load (see markLazyImages).
|
|
1943
|
+
let bodyHtml = markLazyImages(result.html, eagerImages)
|
|
1944
|
+
// `spriteIcons: 'page'` — the page's own icons only (pageWeight.js, XMA
|
|
1945
|
+
// round 8, E6): the client adds the rest of the design system's icons to
|
|
1946
|
+
// the same sprite when it boots, before any of them can be rendered.
|
|
1947
|
+
if (spriteIcons === 'page') bodyHtml = trimSpriteToPage(bodyHtml, typeof shell === 'string' ? shell : '').html
|
|
1948
|
+
|
|
1949
|
+
// `cssClasses: 'page'` — of the rules every page so far needed, the ones
|
|
1950
|
+
// this page's markup can match (pageWeight.js classRulesForPage, XMA round
|
|
1951
|
+
// 8, E12): the client writes the rules of each element it creates itself.
|
|
1952
|
+
const emotionCSS = cssClasses === 'page'
|
|
1953
|
+
? classRulesForPage(Array.from(_accumulatedEmotionCSS), markupClasses(bodyHtml, typeof shell === 'string' ? shell : '')).join('\n')
|
|
1954
|
+
: Array.from(_accumulatedEmotionCSS).join('\n')
|
|
1921
1955
|
|
|
1922
1956
|
// Global CSS (variables, reset, keyframes): this render's own init output.
|
|
1923
1957
|
// The style tags, built once for both documents below.
|
|
1924
1958
|
const globalCSS = result.globalCSS
|
|
1925
|
-
|
|
1959
|
+
// `cssVariables: 'page'` — the custom properties this page's CSS and
|
|
1960
|
+
// markup read (pageWeight.js trimVariablesToPage, XMA round 8, E7); the
|
|
1961
|
+
// client injects every variable itself as it boots.
|
|
1962
|
+
const rootRule = cssVariables === 'page'
|
|
1963
|
+
? trimVariablesToPage(globalCSS.rootRule || '', globalCSS.resetRules, globalCSS.keyframeRules, emotionCSS, bodyHtml, typeof shell === 'string' ? shell : '').css
|
|
1964
|
+
: globalCSS.rootRule
|
|
1965
|
+
const brenderStyle = `<style data-brender>\n${rootRule || ''}\n${globalCSS.resetRules || ''}\n${globalCSS.keyframeRules || ''}\n</style>`
|
|
1926
1966
|
const emotionStyle = emotionCSS ? `<style data-emotion="smbls">\n${emotionCSS}\n</style>` : ''
|
|
1927
1967
|
|
|
1928
1968
|
// Generate font links from design system
|
|
@@ -1934,7 +1974,10 @@ export const renderPage = async (data, route = '/', options = {}) => {
|
|
|
1934
1974
|
// and the data blocks after the markup — the registry under `adoptDom`,
|
|
1935
1975
|
// and the recorded anonymous answers, so the client renders from the data
|
|
1936
1976
|
// the server used instead of asking for all of it again.
|
|
1937
|
-
|
|
1977
|
+
// `registryFormat: 'auto'` — the tree when the smbls this page renders
|
|
1978
|
+
// with (the page's own client) reads it, else paths (XMA round 8, E13).
|
|
1979
|
+
const treeRegistry = registryFormat === 'tree' || (registryFormat === 'auto' && (result.registryFormats || []).includes('tree'))
|
|
1980
|
+
const prerender = prerenderParts({ brRegistry: result.brRegistry, fetchSeed: result.fetchSeed, adoptDom, stamp, time, registryFormat: treeRegistry ? 'tree' : 'paths' })
|
|
1938
1981
|
|
|
1939
1982
|
// ISR: include client SPA bundle for hydration + data fetching
|
|
1940
1983
|
let isrBody = ''
|
|
@@ -2021,9 +2064,6 @@ export const renderPage = async (data, route = '/', options = {}) => {
|
|
|
2021
2064
|
}
|
|
2022
2065
|
}
|
|
2023
2066
|
|
|
2024
|
-
// Images past the first `eagerImages` load lazily unless they say how to
|
|
2025
|
-
// load (see markLazyImages).
|
|
2026
|
-
const bodyHtml = markLazyImages(result.html, eagerImages)
|
|
2027
2067
|
|
|
2028
2068
|
// Build path: render INTO the app's own built document (shell.js) — the
|
|
2029
2069
|
// standalone document below carries no app code unless `isr` adds a
|
|
@@ -2138,9 +2178,13 @@ const generateFontLinks = (ds) => {
|
|
|
2138
2178
|
// (@symbo.ls/fetch early.js "Stale pages"), by app code
|
|
2139
2179
|
// (`el.context.prerender`, smbls prerender.js) and by a host that compares
|
|
2140
2180
|
// it with its data's last change.
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2181
|
+
// `registryFormat: 'tree'` writes the registry as a tree (@symbo.ls/utils
|
|
2182
|
+
// encodeBrenderRegistry, XMA round 8, E13) — the same data, a third of the
|
|
2183
|
+
// bytes — in its own block; a registry that cannot be one stays paths.
|
|
2184
|
+
export const prerenderParts = ({ brRegistry, fetchSeed, adoptDom = false, stamp, time, registryFormat = 'paths' } = {}) => {
|
|
2185
|
+
const has = adoptDom && brRegistry && Object.keys(brRegistry).length
|
|
2186
|
+
const registry = has
|
|
2187
|
+
? (registryFormat === 'tree' && brenderRegistryTreeBlock(brRegistry)) || brenderRegistryBlock(brRegistry)
|
|
2144
2188
|
: ''
|
|
2145
2189
|
const seed = createEarlySeedBlock(fetchSeed)
|
|
2146
2190
|
return {
|