@webtypen/webframez-react 0.0.37 → 0.0.39
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/dist/client.cjs +1 -1
- package/dist/client.js +1 -1
- package/dist/http.cjs +55 -14
- package/dist/http.js +55 -14
- package/dist/index.cjs +55 -14
- package/dist/index.js +55 -14
- package/dist/router.cjs +3 -0
- package/dist/router.js +3 -0
- package/dist/types.d.ts +3 -0
- package/dist/webframez-core.cjs +55 -14
- package/dist/webframez-core.js +55 -14
- package/package.json +1 -1
package/dist/client.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var ce=Object.create;var E=Object.defineProperty;var de=Object.getOwnPropertyDescriptor;var ue=Object.getOwnPropertyNames;var le=Object.getPrototypeOf,fe=Object.prototype.hasOwnProperty;var pe=(e,t)=>{for(var n in t)E(e,n,{get:t[n],enumerable:!0})},U=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of ue(t))!fe.call(e,r)&&r!==n&&E(e,r,{get:()=>t[r],enumerable:!(o=de(t,r))||o.enumerable});return e};var H=(e,t,n)=>(n=e!=null?ce(le(e)):{},U(t||!e||!e.__esModule?E(n,"default",{value:e,enumerable:!0}):n,e)),me=e=>U(E({},"__esModule",{value:!0}),e);var ke={};pe(ke,{mountWebframezClient:()=>Oe,useCookie:()=>Ne,useRouter:()=>ve});module.exports=me(ke);var s=H(require("react"),1),K=require("react-dom/client"),w=require("react-server-dom-webpack/client"),V=require("@webtypen/webframez-react/route-slot");var Re=/^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;function u(e){if(typeof e!="string")return;let t=e.trim();return!t||t==="/"?"":t.replace(/\/+$/,"")}function z(e,t){let n=e.trim(),o=u(t);return!n||!o||Re.test(n)||n.startsWith("/")||o!=="/"&&(n===o||n.startsWith(`${o}/`))?n:o==="/"?n.startsWith("/")?n:`/${n}`:n.startsWith("/")?`${o}${n}`:`${o}/${n}`}function S(e,t){if(!e)return;let n=u(e.basename)??u(t),o=u(e.routeBasePath),r=u(e.transportBasePath),a={...e,...n!==void 0?{basename:n}:{},...o!==void 0?{routeBasePath:o}:{},...r!==void 0?{transportBasePath:r}:{}};return a.favicon&&(a.favicon=z(a.favicon,n)),a.links&&(a.links=a.links.map(c=>({...c,href:z(c.href,n)}))),a}var m=H(require("react"),1),D="webframez-route-children",W="__webframezRouteChildren",F="WebframezRouteChildren",N=()=>m.default.createElement(D);N.displayName=F;N[W]=!0;var we=N;function M(e){if(e===D||e===we)return!0;if(!e||typeof e!="function"&&typeof e!="object")return!1;try{let t=e;return t[W]===!0||t.displayName===F||t.name==="RouteChildren"}catch{return!1}}function $(e){if(!e||typeof e!="object")return!1;try{return"type"in e&&"props"in e}catch{return!1}}function A(e,t){if(e==null||typeof e=="boolean")return e;if(Array.isArray(e)){let l=!1,_=e.map(p=>{let h=A(p,t);return h!==p&&(l=!0),h});return l?_:e}if($(e)&&M(e.type))return t;let n=m.default.isValidElement(e);if(!n&&!$(e))return e;if(n&&M(e.type))return t;let o=e.props??{};if(!("children"in o))return e;let r=A(o.children,t);if(r===o.children)return e;if(n)return Array.isArray(r)?m.default.cloneElement(e,void 0,...r):m.default.cloneElement(e,void 0,r);let a=e,c={...a.props??{},children:r,...a.key!==void 0&&a.key!==null?{key:a.key}:{}};return m.default.createElement(a.type,c)}var d=require("react/jsx-runtime"),_e={push:()=>{},replace:()=>{},refresh:()=>{},refreshContext:()=>{}},T=typeof s.default.createContext=="function"?s.default.createContext(null):null,X="__WEBFRAMEZ_ROUTER__",he="__WEBFRAMEZ_REACT_BUILD_ID",ge="x-webframez-react-build",Ce="[data-webframez-head='true']";function j(){if(typeof window>"u"||typeof document>"u")return;let e=()=>{window.scrollTo({top:0,left:0}),document.scrollingElement&&(document.scrollingElement.scrollTop=0),document.documentElement.scrollTop=0,document.body&&(document.body.scrollTop=0)};if(typeof window.requestAnimationFrame=="function"){window.requestAnimationFrame(e);return}window.setTimeout(e,0)}function I(e){return u(e)??""}function ye(e,t){return t?e===t?"/":e.startsWith(`${t}/`)?e.slice(t.length)||"/":e||"/":e||"/"}function J(e,t){let n=!t||t==="/"?"/":t.startsWith("/")?t:`/${t}`;return e?n==="/"?e:`${e}${n}`:n}function Ee(){return I(typeof window>"u"?globalThis.__RSC_ROUTE_BASE_PATH:window.__RSC_ROUTE_BASE_PATH)}function Q(e){if(typeof window>"u")return e||"/";let t=I(window.__RSC_BASENAME),n=Ee(),o=ye(e||"/",t);return J(n,o)}function ee(e){if(typeof window>"u")return e;let t=window.__RSC_ENDPOINT;return typeof t=="string"&&t.trim()!==""?t:e}function Ae(){if(typeof window>"u")return"";let e=window[he];return typeof e=="string"?e:""}function Te(e){let t=Ae();return!!t&&!!e&&t!==e}function v(e){typeof window>"u"||window.location.assign(`${e.pathname}${e.search}${e.hash}`)}function Pe(){return typeof window>"u"?null:window[X]??null}function Se(e){typeof window>"u"||(window[X]=e)}function G(){let e={},t=typeof document>"u"?"":document.cookie;if(!t||t.trim()==="")return e;for(let n of t.split(";")){let o=n.trim();if(!o)continue;let r=o.indexOf("="),a=r>=0?o.slice(0,r).trim():o,c=r>=0?o.slice(r+1):"";a&&(e[a]=decodeURIComponent(c))}return e}function q(e,t,n={}){let o=[`${e}=${encodeURIComponent(t)}`];return n.path&&o.push(`Path=${n.path}`),n.domain&&o.push(`Domain=${n.domain}`),typeof n.maxAge=="number"&&o.push(`Max-Age=${Math.floor(n.maxAge)}`),n.expires&&o.push(`Expires=${n.expires.toUTCString()}`),n.sameSite&&o.push(`SameSite=${n.sameSite}`),n.secure&&o.push("Secure"),o.join("; ")}function Ne(){return s.default.useMemo(()=>({all:()=>G(),get:e=>G()[e],set:(e,t,n)=>{typeof document>"u"||(document.cookie=q(e,t,n))},remove:(e,t)=>{typeof document>"u"||(document.cookie=q(e,"",{...t??{},maxAge:0}))}}),[])}function ve(){let e=T?s.default.useContext(T):null;if(!e){let t=Pe();if(t)return t;if(typeof window>"u")return _e;throw new Error("useRouter must be used inside mountWebframezClient()")}return e}function xe({active:e}){return(0,d.jsx)("div",{style:{position:"fixed",top:0,left:0,width:"100%",height:3,zIndex:9999,transformOrigin:"left",transform:e?"scaleX(1)":"scaleX(0)",transition:"transform 180ms ease",background:"linear-gradient(90deg, #0ea5e9, #22c55e)"}})}function Y(e){let t=document.createElement("meta");t.setAttribute("data-webframez-head","true");let n=Object.entries(e).filter(([,o])=>!!o);for(let[o,r]of n)t.setAttribute(o,String(r));document.head.appendChild(t)}function Z(e){let t=document.createElement("link");t.setAttribute("data-webframez-head","true");let n=Object.entries(e).filter(([,o])=>!!o);for(let[o,r]of n)t.setAttribute(o,String(r));document.head.appendChild(t)}function x(e){if(typeof document>"u")return;let t=S(e)??e;te(t),document.body.className=t.bodyClassName||"",document.title=t.title||"Webframez React";for(let n of document.head.querySelectorAll(Ce))n.remove();t.description&&Y({name:"description",content:t.description}),t.favicon&&Z({rel:"icon",href:t.favicon});for(let n of t.meta??[])Y(n);for(let n of t.links??[])Z(n)}function te(e){if(typeof window>"u")return;let t=S(e)??e,n=u(t.basename),o=u(t.routeBasePath),r=u(t.transportBasePath);window.__RSC_BASENAME=n??"",window.__RSC_ROUTE_BASE_PATH=o??"",r!==void 0&&(window.__RSC_ENDPOINT=J(r,"/rsc"))}function Ie(e){let t=new TextEncoder;return new ReadableStream({start(n){n.enqueue(t.encode(e)),n.close()}})}function Be(){if(typeof window>"u")return null;let e=window.__RSC_INITIAL_PAYLOAD;return typeof e!="string"||e===""?null:(delete window.__RSC_INITIAL_PAYLOAD,(0,w.createFromReadableStream)(Ie(e)))}function be(e){let t=ee(e),n=Q(window.location.pathname);return Be()??(0,w.createFromFetch)(fetch(`${t}?path=${encodeURIComponent(n)}&search=${encodeURIComponent(window.location.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}}))}function Le(e,t){return function(){let o=s.default.use(e),r=typeof o.contextModel<"u"&&typeof o.pageModel<"u",[a,c]=(0,s.useState)(o.model),[l,_]=(0,s.useState)(o.contextModel),[p,h]=(0,s.useState)(o.pageModel),[B,b]=(0,s.useState)(o.head),[ne,g]=(0,s.useState)(!1),[oe,re]=(0,s.useState)(!1),[ie,P]=(0,s.useState)(r);async function L(i){let y=ee(t),f=Q(i.pathname),R=await fetch(`${y}?path=${encodeURIComponent(f)}&search=${encodeURIComponent(i.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}});return Te(R.headers.get(ge))?(v(i),await new Promise(()=>{})):await(0,w.createFromFetch)(Promise.resolve(R))}async function C(i,y="push"){g(!0);try{let f=await L(i);x(f.head),b(f.head),c(f.model),_(f.contextModel),h(f.pageModel),P(!0);let R=`${i.pathname}${i.search}${i.hash}`;y==="replace"?(history.replaceState(null,"",R),j()):y==="push"&&(history.pushState(null,"",R),j())}catch(f){console.error("[webframez-react] Failed to render route",f),v(i),c((0,d.jsx)("p",{children:"Failed to load route."}))}finally{g(!1)}}async function ae(){g(!0);try{let i=await L(new URL(window.location.href));if(x(i.head),b(i.head),Object.prototype.hasOwnProperty.call(i,"contextModel")){_(i.contextModel),P(!0);return}c(i.model),P(!1)}catch(i){console.error("[webframez-react] Failed to refresh route context",i),v(new URL(window.location.href))}finally{g(!1)}}(0,s.useEffect)(()=>{x(B)},[B]),(0,s.useEffect)(()=>{re(!0);let i=()=>{C(new URL(window.location.href),"none")};return window.addEventListener("popstate",i),()=>{window.removeEventListener("popstate",i)}},[]);let O=s.default.useMemo(()=>({push:i=>{C(new URL(i,window.location.origin),"push")},replace:i=>{C(new URL(i,window.location.origin),"replace")},refresh:()=>{C(new URL(window.location.href),"none")},refreshContext:()=>{ae()}}),[]);Se(O);let se=ie&&typeof p<"u"?l?(0,d.jsx)(V.RouteChildrenSlotProvider,{page:p,children:A(l,p)}):p:a,k=(0,d.jsxs)(d.Fragment,{children:[oe?(0,d.jsx)(xe,{active:ne}):null,se??(0,d.jsx)("p",{style:{padding:24},children:"Loading..."})]});return T?(0,d.jsx)(T.Provider,{value:O,children:k}):k}}function Oe(e={}){let t=e.rootId??"root",n=document.getElementById(t);if(!n)throw new Error(`Missing #${t} element`);let o=typeof window<"u"&&window.__RSC_ENDPOINT,r=e.rscEndpoint??o??"/rsc",a=Promise.resolve(be(r)).then(l=>(l?.head&&te(l.head),l)),c=Le(a,r);return(0,K.hydrateRoot)(n,(0,d.jsx)(c,{}))}
|
package/dist/client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import m,{useEffect as
|
|
1
|
+
import m,{useEffect as D,useState as f}from"react";import{hydrateRoot as se}from"react-dom/client";import{createFromFetch as Y,createFromReadableStream as ce}from"react-server-dom-webpack/client";import{RouteChildrenSlotProvider as de}from"@webtypen/webframez-react/route-slot";var ie=/^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;function c(e){if(typeof e!="string")return;let t=e.trim();return!t||t==="/"?"":t.replace(/\/+$/,"")}function k(e,t){let n=e.trim(),o=c(t);return!n||!o||ie.test(n)||n.startsWith("/")||o!=="/"&&(n===o||n.startsWith(`${o}/`))?n:o==="/"?n.startsWith("/")?n:`/${n}`:n.startsWith("/")?`${o}${n}`:`${o}/${n}`}function P(e,t){if(!e)return;let n=c(e.basename)??c(t),o=c(e.routeBasePath),r=c(e.transportBasePath),a={...e,...n!==void 0?{basename:n}:{},...o!==void 0?{routeBasePath:o}:{},...r!==void 0?{transportBasePath:r}:{}};return a.favicon&&(a.favicon=k(a.favicon,n)),a.links&&(a.links=a.links.map(s=>({...s,href:k(s.href,n)}))),a}import w from"react";var z="webframez-route-children",M="__webframezRouteChildren",$="WebframezRouteChildren",S=()=>w.createElement(z);S.displayName=$;S[M]=!0;var ae=S;function U(e){if(e===z||e===ae)return!0;if(!e||typeof e!="function"&&typeof e!="object")return!1;try{let t=e;return t[M]===!0||t.displayName===$||t.name==="RouteChildren"}catch{return!1}}function H(e){if(!e||typeof e!="object")return!1;try{return"type"in e&&"props"in e}catch{return!1}}function E(e,t){if(e==null||typeof e=="boolean")return e;if(Array.isArray(e)){let d=!1,_=e.map(l=>{let h=E(l,t);return h!==l&&(d=!0),h});return d?_:e}if(H(e)&&U(e.type))return t;let n=w.isValidElement(e);if(!n&&!H(e))return e;if(n&&U(e.type))return t;let o=e.props??{};if(!("children"in o))return e;let r=E(o.children,t);if(r===o.children)return e;if(n)return Array.isArray(r)?w.cloneElement(e,void 0,...r):w.cloneElement(e,void 0,r);let a=e,s={...a.props??{},children:r,...a.key!==void 0&&a.key!==null?{key:a.key}:{}};return w.createElement(a.type,s)}import{Fragment as Pe,jsx as p,jsxs as Se}from"react/jsx-runtime";var ue={push:()=>{},replace:()=>{},refresh:()=>{},refreshContext:()=>{}},A=typeof m.createContext=="function"?m.createContext(null):null,Z="__WEBFRAMEZ_ROUTER__",le="__WEBFRAMEZ_REACT_BUILD_ID",fe="x-webframez-react-build",pe="[data-webframez-head='true']";function W(){if(typeof window>"u"||typeof document>"u")return;let e=()=>{window.scrollTo({top:0,left:0}),document.scrollingElement&&(document.scrollingElement.scrollTop=0),document.documentElement.scrollTop=0,document.body&&(document.body.scrollTop=0)};if(typeof window.requestAnimationFrame=="function"){window.requestAnimationFrame(e);return}window.setTimeout(e,0)}function x(e){return c(e)??""}function me(e,t){return t?e===t?"/":e.startsWith(`${t}/`)?e.slice(t.length)||"/":e||"/":e||"/"}function K(e,t){let n=!t||t==="/"?"/":t.startsWith("/")?t:`/${t}`;return e?n==="/"?e:`${e}${n}`:n}function Re(){return x(typeof window>"u"?globalThis.__RSC_ROUTE_BASE_PATH:window.__RSC_ROUTE_BASE_PATH)}function V(e){if(typeof window>"u")return e||"/";let t=x(window.__RSC_BASENAME),n=Re(),o=me(e||"/",t);return K(n,o)}function X(e){if(typeof window>"u")return e;let t=window.__RSC_ENDPOINT;return typeof t=="string"&&t.trim()!==""?t:e}function we(){if(typeof window>"u")return"";let e=window[le];return typeof e=="string"?e:""}function _e(e){let t=we();return!!t&&!!e&&t!==e}function N(e){typeof window>"u"||window.location.assign(`${e.pathname}${e.search}${e.hash}`)}function he(){return typeof window>"u"?null:window[Z]??null}function ge(e){typeof window>"u"||(window[Z]=e)}function F(){let e={},t=typeof document>"u"?"":document.cookie;if(!t||t.trim()==="")return e;for(let n of t.split(";")){let o=n.trim();if(!o)continue;let r=o.indexOf("="),a=r>=0?o.slice(0,r).trim():o,s=r>=0?o.slice(r+1):"";a&&(e[a]=decodeURIComponent(s))}return e}function j(e,t,n={}){let o=[`${e}=${encodeURIComponent(t)}`];return n.path&&o.push(`Path=${n.path}`),n.domain&&o.push(`Domain=${n.domain}`),typeof n.maxAge=="number"&&o.push(`Max-Age=${Math.floor(n.maxAge)}`),n.expires&&o.push(`Expires=${n.expires.toUTCString()}`),n.sameSite&&o.push(`SameSite=${n.sameSite}`),n.secure&&o.push("Secure"),o.join("; ")}function He(){return m.useMemo(()=>({all:()=>F(),get:e=>F()[e],set:(e,t,n)=>{typeof document>"u"||(document.cookie=j(e,t,n))},remove:(e,t)=>{typeof document>"u"||(document.cookie=j(e,"",{...t??{},maxAge:0}))}}),[])}function ze(){let e=A?m.useContext(A):null;if(!e){let t=he();if(t)return t;if(typeof window>"u")return ue;throw new Error("useRouter must be used inside mountWebframezClient()")}return e}function Ce({active:e}){return p("div",{style:{position:"fixed",top:0,left:0,width:"100%",height:3,zIndex:9999,transformOrigin:"left",transform:e?"scaleX(1)":"scaleX(0)",transition:"transform 180ms ease",background:"linear-gradient(90deg, #0ea5e9, #22c55e)"}})}function G(e){let t=document.createElement("meta");t.setAttribute("data-webframez-head","true");let n=Object.entries(e).filter(([,o])=>!!o);for(let[o,r]of n)t.setAttribute(o,String(r));document.head.appendChild(t)}function q(e){let t=document.createElement("link");t.setAttribute("data-webframez-head","true");let n=Object.entries(e).filter(([,o])=>!!o);for(let[o,r]of n)t.setAttribute(o,String(r));document.head.appendChild(t)}function v(e){if(typeof document>"u")return;let t=P(e)??e;J(t),document.body.className=t.bodyClassName||"",document.title=t.title||"Webframez React";for(let n of document.head.querySelectorAll(pe))n.remove();t.description&&G({name:"description",content:t.description}),t.favicon&&q({rel:"icon",href:t.favicon});for(let n of t.meta??[])G(n);for(let n of t.links??[])q(n)}function J(e){if(typeof window>"u")return;let t=P(e)??e,n=c(t.basename),o=c(t.routeBasePath),r=c(t.transportBasePath);window.__RSC_BASENAME=n??"",window.__RSC_ROUTE_BASE_PATH=o??"",r!==void 0&&(window.__RSC_ENDPOINT=K(r,"/rsc"))}function ye(e){let t=new TextEncoder;return new ReadableStream({start(n){n.enqueue(t.encode(e)),n.close()}})}function Ee(){if(typeof window>"u")return null;let e=window.__RSC_INITIAL_PAYLOAD;return typeof e!="string"||e===""?null:(delete window.__RSC_INITIAL_PAYLOAD,ce(ye(e)))}function Ae(e){let t=X(e),n=V(window.location.pathname);return Ee()??Y(fetch(`${t}?path=${encodeURIComponent(n)}&search=${encodeURIComponent(window.location.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}}))}function Te(e,t){return function(){let o=m.use(e),r=typeof o.contextModel<"u"&&typeof o.pageModel<"u",[a,s]=f(o.model),[d,_]=f(o.contextModel),[l,h]=f(o.pageModel),[I,B]=f(o.head),[Q,g]=f(!1),[ee,te]=f(!1),[ne,T]=f(r);async function b(i){let y=X(t),u=V(i.pathname),R=await fetch(`${y}?path=${encodeURIComponent(u)}&search=${encodeURIComponent(i.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}});return _e(R.headers.get(fe))?(N(i),await new Promise(()=>{})):await Y(Promise.resolve(R))}async function C(i,y="push"){g(!0);try{let u=await b(i);v(u.head),B(u.head),s(u.model),_(u.contextModel),h(u.pageModel),T(!0);let R=`${i.pathname}${i.search}${i.hash}`;y==="replace"?(history.replaceState(null,"",R),W()):y==="push"&&(history.pushState(null,"",R),W())}catch(u){console.error("[webframez-react] Failed to render route",u),N(i),s(p("p",{children:"Failed to load route."}))}finally{g(!1)}}async function oe(){g(!0);try{let i=await b(new URL(window.location.href));if(v(i.head),B(i.head),Object.prototype.hasOwnProperty.call(i,"contextModel")){_(i.contextModel),T(!0);return}s(i.model),T(!1)}catch(i){console.error("[webframez-react] Failed to refresh route context",i),N(new URL(window.location.href))}finally{g(!1)}}D(()=>{v(I)},[I]),D(()=>{te(!0);let i=()=>{C(new URL(window.location.href),"none")};return window.addEventListener("popstate",i),()=>{window.removeEventListener("popstate",i)}},[]);let L=m.useMemo(()=>({push:i=>{C(new URL(i,window.location.origin),"push")},replace:i=>{C(new URL(i,window.location.origin),"replace")},refresh:()=>{C(new URL(window.location.href),"none")},refreshContext:()=>{oe()}}),[]);ge(L);let re=ne&&typeof l<"u"?d?p(de,{page:l,children:E(d,l)}):l:a,O=Se(Pe,{children:[ee?p(Ce,{active:Q}):null,re??p("p",{style:{padding:24},children:"Loading..."})]});return A?p(A.Provider,{value:L,children:O}):O}}function Me(e={}){let t=e.rootId??"root",n=document.getElementById(t);if(!n)throw new Error(`Missing #${t} element`);let o=typeof window<"u"&&window.__RSC_ENDPOINT,r=e.rscEndpoint??o??"/rsc",a=Promise.resolve(Ae(r)).then(d=>(d?.head&&J(d.head),d)),s=Te(a,r);return se(n,p(s,{}))}export{Me as mountWebframezClient,He as useCookie,ze as useRouter};
|
package/dist/http.cjs
CHANGED
|
@@ -52,7 +52,9 @@ function createHTMLShell(options = {}) {
|
|
|
52
52
|
title = "RSC App",
|
|
53
53
|
rscEndpoint = "/rsc",
|
|
54
54
|
clientScriptUrl = "/client.js",
|
|
55
|
+
buildId = "",
|
|
55
56
|
headTags = "",
|
|
57
|
+
bodyClassName = "",
|
|
56
58
|
rootHtml = "",
|
|
57
59
|
initialFlightData = "",
|
|
58
60
|
basename = "",
|
|
@@ -101,11 +103,12 @@ function createHTMLShell(options = {}) {
|
|
|
101
103
|
<title>${title}</title>
|
|
102
104
|
${headTags}
|
|
103
105
|
</head>
|
|
104
|
-
<body>
|
|
106
|
+
<body${bodyClassName ? ` class="${bodyClassName.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">")}"` : ""}>
|
|
105
107
|
<div id="root">${rootHtml}</div>
|
|
106
108
|
<script>window.__RSC_ENDPOINT = "${rscEndpoint}";</script>
|
|
107
109
|
<script>window.__RSC_BASENAME = "${basename}";</script>
|
|
108
110
|
<script>window.__RSC_ROUTE_BASE_PATH = "${routeBasePath}";</script>
|
|
111
|
+
<script>window.__WEBFRAMEZ_REACT_BUILD_ID = "${buildId}";</script>
|
|
109
112
|
<script>window.__RSC_INITIAL_PAYLOAD = ${escapedInitialFlightData};</script>
|
|
110
113
|
<script type="module" src="${clientScriptUrl}"></script>
|
|
111
114
|
${liveReloadScript}
|
|
@@ -470,6 +473,9 @@ function mergeHead(...configs) {
|
|
|
470
473
|
if (config.description) {
|
|
471
474
|
merged.description = config.description;
|
|
472
475
|
}
|
|
476
|
+
if (hasOwn("bodyClassName")) {
|
|
477
|
+
merged.bodyClassName = config.bodyClassName;
|
|
478
|
+
}
|
|
473
479
|
if (hasOwn("basename")) {
|
|
474
480
|
merged.basename = config.basename;
|
|
475
481
|
}
|
|
@@ -801,6 +807,15 @@ function createClientAssetVersion(distRootDir) {
|
|
|
801
807
|
return "";
|
|
802
808
|
}
|
|
803
809
|
}
|
|
810
|
+
function createBuildId(distRootDir, manifestPath) {
|
|
811
|
+
const clientVersion = createClientAssetVersion(distRootDir);
|
|
812
|
+
try {
|
|
813
|
+
const stat = import_node_fs2.default.statSync(manifestPath);
|
|
814
|
+
return `${clientVersion}:${Math.floor(stat.mtimeMs)}-${stat.size}`;
|
|
815
|
+
} catch {
|
|
816
|
+
return clientVersion;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
804
819
|
function appendAssetVersion(url, version) {
|
|
805
820
|
if (!version) {
|
|
806
821
|
return url;
|
|
@@ -1494,6 +1509,30 @@ function createServerConsumerManifest(manifest) {
|
|
|
1494
1509
|
}
|
|
1495
1510
|
return consumerManifest;
|
|
1496
1511
|
}
|
|
1512
|
+
function createManifestLoader(options) {
|
|
1513
|
+
let cache = null;
|
|
1514
|
+
return () => {
|
|
1515
|
+
const stat = import_node_fs2.default.statSync(options.manifestPath);
|
|
1516
|
+
const cacheKey = `${Math.floor(stat.mtimeMs)}-${stat.size}`;
|
|
1517
|
+
if (cache && cache.cacheKey === cacheKey) {
|
|
1518
|
+
return cache;
|
|
1519
|
+
}
|
|
1520
|
+
const moduleMap = normalizeClientManifest(
|
|
1521
|
+
JSON.parse(import_node_fs2.default.readFileSync(options.manifestPath, "utf-8")),
|
|
1522
|
+
{
|
|
1523
|
+
distRootDir: options.distRootDir,
|
|
1524
|
+
cwd: options.cwd
|
|
1525
|
+
}
|
|
1526
|
+
);
|
|
1527
|
+
cache = {
|
|
1528
|
+
cacheKey,
|
|
1529
|
+
buildId: createBuildId(options.distRootDir, options.manifestPath),
|
|
1530
|
+
moduleMap,
|
|
1531
|
+
serverConsumerModuleMap: createServerConsumerManifest(moduleMap)
|
|
1532
|
+
};
|
|
1533
|
+
return cache;
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1497
1536
|
function createNodeRequestHandler(options) {
|
|
1498
1537
|
const devServerId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1499
1538
|
const distRootDir = import_node_path3.default.resolve(options.distRootDir);
|
|
@@ -1511,14 +1550,11 @@ function createNodeRequestHandler(options) {
|
|
|
1511
1550
|
const liveReloadPath = !liveReloadEnabled ? "" : options.liveReloadPath ?? `${basePath || ""}/__webframez_live_reload`;
|
|
1512
1551
|
const liveReloadClients = /* @__PURE__ */ new Set();
|
|
1513
1552
|
const router = createFileRouter({ pagesDir });
|
|
1514
|
-
const
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
}
|
|
1520
|
-
);
|
|
1521
|
-
const serverConsumerModuleMap = createServerConsumerManifest(moduleMap);
|
|
1553
|
+
const getManifestState = createManifestLoader({
|
|
1554
|
+
distRootDir,
|
|
1555
|
+
manifestPath,
|
|
1556
|
+
cwd: process.cwd()
|
|
1557
|
+
});
|
|
1522
1558
|
const initialHtmlWorker = createInitialHtmlWorker(pagesDir);
|
|
1523
1559
|
const disposeInitialHtmlWorker = () => {
|
|
1524
1560
|
initialHtmlWorker.dispose();
|
|
@@ -1573,6 +1609,7 @@ function createNodeRequestHandler(options) {
|
|
|
1573
1609
|
return;
|
|
1574
1610
|
}
|
|
1575
1611
|
if (url.pathname === rscPath) {
|
|
1612
|
+
const manifestState2 = getManifestState();
|
|
1576
1613
|
const pathname = stripBasePath(url.searchParams.get("path") || "/", basePath);
|
|
1577
1614
|
const requestContext = createRouteRequestContext(
|
|
1578
1615
|
req,
|
|
@@ -1595,8 +1632,9 @@ function createNodeRequestHandler(options) {
|
|
|
1595
1632
|
pageModel: resolved2.pageModel,
|
|
1596
1633
|
head: resolved2.head
|
|
1597
1634
|
};
|
|
1635
|
+
res.setHeader("X-Webframez-React-Build", manifestState2.buildId);
|
|
1598
1636
|
sendRSC(res, payload, {
|
|
1599
|
-
moduleMap,
|
|
1637
|
+
moduleMap: manifestState2.moduleMap,
|
|
1600
1638
|
statusCode: resolved2.statusCode
|
|
1601
1639
|
});
|
|
1602
1640
|
return;
|
|
@@ -1666,8 +1704,9 @@ function createNodeRequestHandler(options) {
|
|
|
1666
1704
|
model: resolved.model,
|
|
1667
1705
|
head: resolved.head
|
|
1668
1706
|
};
|
|
1707
|
+
const manifestState = getManifestState();
|
|
1669
1708
|
const initialFlightData = await renderRSCToString(initialPayload, {
|
|
1670
|
-
moduleMap
|
|
1709
|
+
moduleMap: manifestState.moduleMap
|
|
1671
1710
|
});
|
|
1672
1711
|
const transportBasePath = normalizeRuntimeBasePath(resolved.head.transportBasePath) ?? normalizeRuntimeBasePath(basePath) ?? "";
|
|
1673
1712
|
const shellClientScriptUrl = appendAssetVersion(
|
|
@@ -1684,7 +1723,7 @@ function createNodeRequestHandler(options) {
|
|
|
1684
1723
|
try {
|
|
1685
1724
|
rootHtml = await initialHtmlWorker.renderFromFlightData({
|
|
1686
1725
|
flightData: initialFlightData,
|
|
1687
|
-
moduleMap: serverConsumerModuleMap
|
|
1726
|
+
moduleMap: manifestState.serverConsumerModuleMap
|
|
1688
1727
|
});
|
|
1689
1728
|
} catch (error) {
|
|
1690
1729
|
console.error("[webframez-react] Failed to render initial HTML", error);
|
|
@@ -1692,7 +1731,7 @@ function createNodeRequestHandler(options) {
|
|
|
1692
1731
|
initialHtmlWorker.dispose();
|
|
1693
1732
|
rootHtml = await initialHtmlWorker.renderFromFlightData({
|
|
1694
1733
|
flightData: initialFlightData,
|
|
1695
|
-
moduleMap: serverConsumerModuleMap
|
|
1734
|
+
moduleMap: manifestState.serverConsumerModuleMap
|
|
1696
1735
|
});
|
|
1697
1736
|
} catch (retryError) {
|
|
1698
1737
|
console.error("[webframez-react] Retry for initial HTML failed", retryError);
|
|
@@ -1700,7 +1739,7 @@ function createNodeRequestHandler(options) {
|
|
|
1700
1739
|
initialHtmlWorker.dispose();
|
|
1701
1740
|
rootHtml = await initialHtmlWorker.renderFromFlightData({
|
|
1702
1741
|
flightData: initialFlightData,
|
|
1703
|
-
moduleMap: serverConsumerModuleMap
|
|
1742
|
+
moduleMap: manifestState.serverConsumerModuleMap
|
|
1704
1743
|
});
|
|
1705
1744
|
} catch (flightRenderError) {
|
|
1706
1745
|
console.error("[webframez-react] Flight-to-HTML render failed", flightRenderError);
|
|
@@ -1724,7 +1763,9 @@ function createNodeRequestHandler(options) {
|
|
|
1724
1763
|
createHTMLShell({
|
|
1725
1764
|
title: resolved.head.title || "Webframez React",
|
|
1726
1765
|
headTags: renderHeadToString(resolved.head),
|
|
1766
|
+
bodyClassName: resolved.head.bodyClassName || "",
|
|
1727
1767
|
clientScriptUrl: shellClientScriptUrl,
|
|
1768
|
+
buildId: manifestState.buildId,
|
|
1728
1769
|
rscEndpoint: shellRscEndpoint,
|
|
1729
1770
|
rootHtml,
|
|
1730
1771
|
initialFlightData,
|
package/dist/http.js
CHANGED
|
@@ -32,7 +32,9 @@ function createHTMLShell(options = {}) {
|
|
|
32
32
|
title = "RSC App",
|
|
33
33
|
rscEndpoint = "/rsc",
|
|
34
34
|
clientScriptUrl = "/client.js",
|
|
35
|
+
buildId = "",
|
|
35
36
|
headTags = "",
|
|
37
|
+
bodyClassName = "",
|
|
36
38
|
rootHtml = "",
|
|
37
39
|
initialFlightData = "",
|
|
38
40
|
basename = "",
|
|
@@ -81,11 +83,12 @@ function createHTMLShell(options = {}) {
|
|
|
81
83
|
<title>${title}</title>
|
|
82
84
|
${headTags}
|
|
83
85
|
</head>
|
|
84
|
-
<body>
|
|
86
|
+
<body${bodyClassName ? ` class="${bodyClassName.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">")}"` : ""}>
|
|
85
87
|
<div id="root">${rootHtml}</div>
|
|
86
88
|
<script>window.__RSC_ENDPOINT = "${rscEndpoint}";</script>
|
|
87
89
|
<script>window.__RSC_BASENAME = "${basename}";</script>
|
|
88
90
|
<script>window.__RSC_ROUTE_BASE_PATH = "${routeBasePath}";</script>
|
|
91
|
+
<script>window.__WEBFRAMEZ_REACT_BUILD_ID = "${buildId}";</script>
|
|
89
92
|
<script>window.__RSC_INITIAL_PAYLOAD = ${escapedInitialFlightData};</script>
|
|
90
93
|
<script type="module" src="${clientScriptUrl}"></script>
|
|
91
94
|
${liveReloadScript}
|
|
@@ -450,6 +453,9 @@ function mergeHead(...configs) {
|
|
|
450
453
|
if (config.description) {
|
|
451
454
|
merged.description = config.description;
|
|
452
455
|
}
|
|
456
|
+
if (hasOwn("bodyClassName")) {
|
|
457
|
+
merged.bodyClassName = config.bodyClassName;
|
|
458
|
+
}
|
|
453
459
|
if (hasOwn("basename")) {
|
|
454
460
|
merged.basename = config.basename;
|
|
455
461
|
}
|
|
@@ -781,6 +787,15 @@ function createClientAssetVersion(distRootDir) {
|
|
|
781
787
|
return "";
|
|
782
788
|
}
|
|
783
789
|
}
|
|
790
|
+
function createBuildId(distRootDir, manifestPath) {
|
|
791
|
+
const clientVersion = createClientAssetVersion(distRootDir);
|
|
792
|
+
try {
|
|
793
|
+
const stat = fs2.statSync(manifestPath);
|
|
794
|
+
return `${clientVersion}:${Math.floor(stat.mtimeMs)}-${stat.size}`;
|
|
795
|
+
} catch {
|
|
796
|
+
return clientVersion;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
784
799
|
function appendAssetVersion(url, version) {
|
|
785
800
|
if (!version) {
|
|
786
801
|
return url;
|
|
@@ -1474,6 +1489,30 @@ function createServerConsumerManifest(manifest) {
|
|
|
1474
1489
|
}
|
|
1475
1490
|
return consumerManifest;
|
|
1476
1491
|
}
|
|
1492
|
+
function createManifestLoader(options) {
|
|
1493
|
+
let cache = null;
|
|
1494
|
+
return () => {
|
|
1495
|
+
const stat = fs2.statSync(options.manifestPath);
|
|
1496
|
+
const cacheKey = `${Math.floor(stat.mtimeMs)}-${stat.size}`;
|
|
1497
|
+
if (cache && cache.cacheKey === cacheKey) {
|
|
1498
|
+
return cache;
|
|
1499
|
+
}
|
|
1500
|
+
const moduleMap = normalizeClientManifest(
|
|
1501
|
+
JSON.parse(fs2.readFileSync(options.manifestPath, "utf-8")),
|
|
1502
|
+
{
|
|
1503
|
+
distRootDir: options.distRootDir,
|
|
1504
|
+
cwd: options.cwd
|
|
1505
|
+
}
|
|
1506
|
+
);
|
|
1507
|
+
cache = {
|
|
1508
|
+
cacheKey,
|
|
1509
|
+
buildId: createBuildId(options.distRootDir, options.manifestPath),
|
|
1510
|
+
moduleMap,
|
|
1511
|
+
serverConsumerModuleMap: createServerConsumerManifest(moduleMap)
|
|
1512
|
+
};
|
|
1513
|
+
return cache;
|
|
1514
|
+
};
|
|
1515
|
+
}
|
|
1477
1516
|
function createNodeRequestHandler(options) {
|
|
1478
1517
|
const devServerId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1479
1518
|
const distRootDir = path3.resolve(options.distRootDir);
|
|
@@ -1491,14 +1530,11 @@ function createNodeRequestHandler(options) {
|
|
|
1491
1530
|
const liveReloadPath = !liveReloadEnabled ? "" : options.liveReloadPath ?? `${basePath || ""}/__webframez_live_reload`;
|
|
1492
1531
|
const liveReloadClients = /* @__PURE__ */ new Set();
|
|
1493
1532
|
const router = createFileRouter({ pagesDir });
|
|
1494
|
-
const
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
}
|
|
1500
|
-
);
|
|
1501
|
-
const serverConsumerModuleMap = createServerConsumerManifest(moduleMap);
|
|
1533
|
+
const getManifestState = createManifestLoader({
|
|
1534
|
+
distRootDir,
|
|
1535
|
+
manifestPath,
|
|
1536
|
+
cwd: process.cwd()
|
|
1537
|
+
});
|
|
1502
1538
|
const initialHtmlWorker = createInitialHtmlWorker(pagesDir);
|
|
1503
1539
|
const disposeInitialHtmlWorker = () => {
|
|
1504
1540
|
initialHtmlWorker.dispose();
|
|
@@ -1553,6 +1589,7 @@ function createNodeRequestHandler(options) {
|
|
|
1553
1589
|
return;
|
|
1554
1590
|
}
|
|
1555
1591
|
if (url.pathname === rscPath) {
|
|
1592
|
+
const manifestState2 = getManifestState();
|
|
1556
1593
|
const pathname = stripBasePath(url.searchParams.get("path") || "/", basePath);
|
|
1557
1594
|
const requestContext = createRouteRequestContext(
|
|
1558
1595
|
req,
|
|
@@ -1575,8 +1612,9 @@ function createNodeRequestHandler(options) {
|
|
|
1575
1612
|
pageModel: resolved2.pageModel,
|
|
1576
1613
|
head: resolved2.head
|
|
1577
1614
|
};
|
|
1615
|
+
res.setHeader("X-Webframez-React-Build", manifestState2.buildId);
|
|
1578
1616
|
sendRSC(res, payload, {
|
|
1579
|
-
moduleMap,
|
|
1617
|
+
moduleMap: manifestState2.moduleMap,
|
|
1580
1618
|
statusCode: resolved2.statusCode
|
|
1581
1619
|
});
|
|
1582
1620
|
return;
|
|
@@ -1646,8 +1684,9 @@ function createNodeRequestHandler(options) {
|
|
|
1646
1684
|
model: resolved.model,
|
|
1647
1685
|
head: resolved.head
|
|
1648
1686
|
};
|
|
1687
|
+
const manifestState = getManifestState();
|
|
1649
1688
|
const initialFlightData = await renderRSCToString(initialPayload, {
|
|
1650
|
-
moduleMap
|
|
1689
|
+
moduleMap: manifestState.moduleMap
|
|
1651
1690
|
});
|
|
1652
1691
|
const transportBasePath = normalizeRuntimeBasePath(resolved.head.transportBasePath) ?? normalizeRuntimeBasePath(basePath) ?? "";
|
|
1653
1692
|
const shellClientScriptUrl = appendAssetVersion(
|
|
@@ -1664,7 +1703,7 @@ function createNodeRequestHandler(options) {
|
|
|
1664
1703
|
try {
|
|
1665
1704
|
rootHtml = await initialHtmlWorker.renderFromFlightData({
|
|
1666
1705
|
flightData: initialFlightData,
|
|
1667
|
-
moduleMap: serverConsumerModuleMap
|
|
1706
|
+
moduleMap: manifestState.serverConsumerModuleMap
|
|
1668
1707
|
});
|
|
1669
1708
|
} catch (error) {
|
|
1670
1709
|
console.error("[webframez-react] Failed to render initial HTML", error);
|
|
@@ -1672,7 +1711,7 @@ function createNodeRequestHandler(options) {
|
|
|
1672
1711
|
initialHtmlWorker.dispose();
|
|
1673
1712
|
rootHtml = await initialHtmlWorker.renderFromFlightData({
|
|
1674
1713
|
flightData: initialFlightData,
|
|
1675
|
-
moduleMap: serverConsumerModuleMap
|
|
1714
|
+
moduleMap: manifestState.serverConsumerModuleMap
|
|
1676
1715
|
});
|
|
1677
1716
|
} catch (retryError) {
|
|
1678
1717
|
console.error("[webframez-react] Retry for initial HTML failed", retryError);
|
|
@@ -1680,7 +1719,7 @@ function createNodeRequestHandler(options) {
|
|
|
1680
1719
|
initialHtmlWorker.dispose();
|
|
1681
1720
|
rootHtml = await initialHtmlWorker.renderFromFlightData({
|
|
1682
1721
|
flightData: initialFlightData,
|
|
1683
|
-
moduleMap: serverConsumerModuleMap
|
|
1722
|
+
moduleMap: manifestState.serverConsumerModuleMap
|
|
1684
1723
|
});
|
|
1685
1724
|
} catch (flightRenderError) {
|
|
1686
1725
|
console.error("[webframez-react] Flight-to-HTML render failed", flightRenderError);
|
|
@@ -1704,7 +1743,9 @@ function createNodeRequestHandler(options) {
|
|
|
1704
1743
|
createHTMLShell({
|
|
1705
1744
|
title: resolved.head.title || "Webframez React",
|
|
1706
1745
|
headTags: renderHeadToString(resolved.head),
|
|
1746
|
+
bodyClassName: resolved.head.bodyClassName || "",
|
|
1707
1747
|
clientScriptUrl: shellClientScriptUrl,
|
|
1748
|
+
buildId: manifestState.buildId,
|
|
1708
1749
|
rscEndpoint: shellRscEndpoint,
|
|
1709
1750
|
rootHtml,
|
|
1710
1751
|
initialFlightData,
|
package/dist/index.cjs
CHANGED
|
@@ -59,7 +59,9 @@ function createHTMLShell(options = {}) {
|
|
|
59
59
|
title = "RSC App",
|
|
60
60
|
rscEndpoint = "/rsc",
|
|
61
61
|
clientScriptUrl = "/client.js",
|
|
62
|
+
buildId = "",
|
|
62
63
|
headTags = "",
|
|
64
|
+
bodyClassName = "",
|
|
63
65
|
rootHtml = "",
|
|
64
66
|
initialFlightData = "",
|
|
65
67
|
basename = "",
|
|
@@ -108,11 +110,12 @@ function createHTMLShell(options = {}) {
|
|
|
108
110
|
<title>${title}</title>
|
|
109
111
|
${headTags}
|
|
110
112
|
</head>
|
|
111
|
-
<body>
|
|
113
|
+
<body${bodyClassName ? ` class="${bodyClassName.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">")}"` : ""}>
|
|
112
114
|
<div id="root">${rootHtml}</div>
|
|
113
115
|
<script>window.__RSC_ENDPOINT = "${rscEndpoint}";</script>
|
|
114
116
|
<script>window.__RSC_BASENAME = "${basename}";</script>
|
|
115
117
|
<script>window.__RSC_ROUTE_BASE_PATH = "${routeBasePath}";</script>
|
|
118
|
+
<script>window.__WEBFRAMEZ_REACT_BUILD_ID = "${buildId}";</script>
|
|
116
119
|
<script>window.__RSC_INITIAL_PAYLOAD = ${escapedInitialFlightData};</script>
|
|
117
120
|
<script type="module" src="${clientScriptUrl}"></script>
|
|
118
121
|
${liveReloadScript}
|
|
@@ -505,6 +508,9 @@ function mergeHead(...configs) {
|
|
|
505
508
|
if (config.description) {
|
|
506
509
|
merged.description = config.description;
|
|
507
510
|
}
|
|
511
|
+
if (hasOwn("bodyClassName")) {
|
|
512
|
+
merged.bodyClassName = config.bodyClassName;
|
|
513
|
+
}
|
|
508
514
|
if (hasOwn("basename")) {
|
|
509
515
|
merged.basename = config.basename;
|
|
510
516
|
}
|
|
@@ -841,6 +847,15 @@ function createClientAssetVersion(distRootDir) {
|
|
|
841
847
|
return "";
|
|
842
848
|
}
|
|
843
849
|
}
|
|
850
|
+
function createBuildId(distRootDir, manifestPath) {
|
|
851
|
+
const clientVersion = createClientAssetVersion(distRootDir);
|
|
852
|
+
try {
|
|
853
|
+
const stat = import_node_fs2.default.statSync(manifestPath);
|
|
854
|
+
return `${clientVersion}:${Math.floor(stat.mtimeMs)}-${stat.size}`;
|
|
855
|
+
} catch {
|
|
856
|
+
return clientVersion;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
844
859
|
function appendAssetVersion(url, version) {
|
|
845
860
|
if (!version) {
|
|
846
861
|
return url;
|
|
@@ -1534,6 +1549,30 @@ function createServerConsumerManifest(manifest) {
|
|
|
1534
1549
|
}
|
|
1535
1550
|
return consumerManifest;
|
|
1536
1551
|
}
|
|
1552
|
+
function createManifestLoader(options) {
|
|
1553
|
+
let cache = null;
|
|
1554
|
+
return () => {
|
|
1555
|
+
const stat = import_node_fs2.default.statSync(options.manifestPath);
|
|
1556
|
+
const cacheKey = `${Math.floor(stat.mtimeMs)}-${stat.size}`;
|
|
1557
|
+
if (cache && cache.cacheKey === cacheKey) {
|
|
1558
|
+
return cache;
|
|
1559
|
+
}
|
|
1560
|
+
const moduleMap = normalizeClientManifest(
|
|
1561
|
+
JSON.parse(import_node_fs2.default.readFileSync(options.manifestPath, "utf-8")),
|
|
1562
|
+
{
|
|
1563
|
+
distRootDir: options.distRootDir,
|
|
1564
|
+
cwd: options.cwd
|
|
1565
|
+
}
|
|
1566
|
+
);
|
|
1567
|
+
cache = {
|
|
1568
|
+
cacheKey,
|
|
1569
|
+
buildId: createBuildId(options.distRootDir, options.manifestPath),
|
|
1570
|
+
moduleMap,
|
|
1571
|
+
serverConsumerModuleMap: createServerConsumerManifest(moduleMap)
|
|
1572
|
+
};
|
|
1573
|
+
return cache;
|
|
1574
|
+
};
|
|
1575
|
+
}
|
|
1537
1576
|
function createNodeRequestHandler(options) {
|
|
1538
1577
|
const devServerId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1539
1578
|
const distRootDir = import_node_path3.default.resolve(options.distRootDir);
|
|
@@ -1551,14 +1590,11 @@ function createNodeRequestHandler(options) {
|
|
|
1551
1590
|
const liveReloadPath = !liveReloadEnabled ? "" : options.liveReloadPath ?? `${basePath || ""}/__webframez_live_reload`;
|
|
1552
1591
|
const liveReloadClients = /* @__PURE__ */ new Set();
|
|
1553
1592
|
const router = createFileRouter({ pagesDir });
|
|
1554
|
-
const
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
}
|
|
1560
|
-
);
|
|
1561
|
-
const serverConsumerModuleMap = createServerConsumerManifest(moduleMap);
|
|
1593
|
+
const getManifestState = createManifestLoader({
|
|
1594
|
+
distRootDir,
|
|
1595
|
+
manifestPath,
|
|
1596
|
+
cwd: process.cwd()
|
|
1597
|
+
});
|
|
1562
1598
|
const initialHtmlWorker = createInitialHtmlWorker(pagesDir);
|
|
1563
1599
|
const disposeInitialHtmlWorker = () => {
|
|
1564
1600
|
initialHtmlWorker.dispose();
|
|
@@ -1613,6 +1649,7 @@ function createNodeRequestHandler(options) {
|
|
|
1613
1649
|
return;
|
|
1614
1650
|
}
|
|
1615
1651
|
if (url.pathname === rscPath) {
|
|
1652
|
+
const manifestState2 = getManifestState();
|
|
1616
1653
|
const pathname = stripBasePath(url.searchParams.get("path") || "/", basePath);
|
|
1617
1654
|
const requestContext = createRouteRequestContext(
|
|
1618
1655
|
req,
|
|
@@ -1635,8 +1672,9 @@ function createNodeRequestHandler(options) {
|
|
|
1635
1672
|
pageModel: resolved2.pageModel,
|
|
1636
1673
|
head: resolved2.head
|
|
1637
1674
|
};
|
|
1675
|
+
res.setHeader("X-Webframez-React-Build", manifestState2.buildId);
|
|
1638
1676
|
sendRSC(res, payload, {
|
|
1639
|
-
moduleMap,
|
|
1677
|
+
moduleMap: manifestState2.moduleMap,
|
|
1640
1678
|
statusCode: resolved2.statusCode
|
|
1641
1679
|
});
|
|
1642
1680
|
return;
|
|
@@ -1706,8 +1744,9 @@ function createNodeRequestHandler(options) {
|
|
|
1706
1744
|
model: resolved.model,
|
|
1707
1745
|
head: resolved.head
|
|
1708
1746
|
};
|
|
1747
|
+
const manifestState = getManifestState();
|
|
1709
1748
|
const initialFlightData = await renderRSCToString(initialPayload, {
|
|
1710
|
-
moduleMap
|
|
1749
|
+
moduleMap: manifestState.moduleMap
|
|
1711
1750
|
});
|
|
1712
1751
|
const transportBasePath = normalizeRuntimeBasePath(resolved.head.transportBasePath) ?? normalizeRuntimeBasePath(basePath) ?? "";
|
|
1713
1752
|
const shellClientScriptUrl = appendAssetVersion(
|
|
@@ -1724,7 +1763,7 @@ function createNodeRequestHandler(options) {
|
|
|
1724
1763
|
try {
|
|
1725
1764
|
rootHtml = await initialHtmlWorker.renderFromFlightData({
|
|
1726
1765
|
flightData: initialFlightData,
|
|
1727
|
-
moduleMap: serverConsumerModuleMap
|
|
1766
|
+
moduleMap: manifestState.serverConsumerModuleMap
|
|
1728
1767
|
});
|
|
1729
1768
|
} catch (error) {
|
|
1730
1769
|
console.error("[webframez-react] Failed to render initial HTML", error);
|
|
@@ -1732,7 +1771,7 @@ function createNodeRequestHandler(options) {
|
|
|
1732
1771
|
initialHtmlWorker.dispose();
|
|
1733
1772
|
rootHtml = await initialHtmlWorker.renderFromFlightData({
|
|
1734
1773
|
flightData: initialFlightData,
|
|
1735
|
-
moduleMap: serverConsumerModuleMap
|
|
1774
|
+
moduleMap: manifestState.serverConsumerModuleMap
|
|
1736
1775
|
});
|
|
1737
1776
|
} catch (retryError) {
|
|
1738
1777
|
console.error("[webframez-react] Retry for initial HTML failed", retryError);
|
|
@@ -1740,7 +1779,7 @@ function createNodeRequestHandler(options) {
|
|
|
1740
1779
|
initialHtmlWorker.dispose();
|
|
1741
1780
|
rootHtml = await initialHtmlWorker.renderFromFlightData({
|
|
1742
1781
|
flightData: initialFlightData,
|
|
1743
|
-
moduleMap: serverConsumerModuleMap
|
|
1782
|
+
moduleMap: manifestState.serverConsumerModuleMap
|
|
1744
1783
|
});
|
|
1745
1784
|
} catch (flightRenderError) {
|
|
1746
1785
|
console.error("[webframez-react] Flight-to-HTML render failed", flightRenderError);
|
|
@@ -1764,7 +1803,9 @@ function createNodeRequestHandler(options) {
|
|
|
1764
1803
|
createHTMLShell({
|
|
1765
1804
|
title: resolved.head.title || "Webframez React",
|
|
1766
1805
|
headTags: renderHeadToString(resolved.head),
|
|
1806
|
+
bodyClassName: resolved.head.bodyClassName || "",
|
|
1767
1807
|
clientScriptUrl: shellClientScriptUrl,
|
|
1808
|
+
buildId: manifestState.buildId,
|
|
1768
1809
|
rscEndpoint: shellRscEndpoint,
|
|
1769
1810
|
rootHtml,
|
|
1770
1811
|
initialFlightData,
|
package/dist/index.js
CHANGED
|
@@ -20,7 +20,9 @@ function createHTMLShell(options = {}) {
|
|
|
20
20
|
title = "RSC App",
|
|
21
21
|
rscEndpoint = "/rsc",
|
|
22
22
|
clientScriptUrl = "/client.js",
|
|
23
|
+
buildId = "",
|
|
23
24
|
headTags = "",
|
|
25
|
+
bodyClassName = "",
|
|
24
26
|
rootHtml = "",
|
|
25
27
|
initialFlightData = "",
|
|
26
28
|
basename = "",
|
|
@@ -69,11 +71,12 @@ function createHTMLShell(options = {}) {
|
|
|
69
71
|
<title>${title}</title>
|
|
70
72
|
${headTags}
|
|
71
73
|
</head>
|
|
72
|
-
<body>
|
|
74
|
+
<body${bodyClassName ? ` class="${bodyClassName.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">")}"` : ""}>
|
|
73
75
|
<div id="root">${rootHtml}</div>
|
|
74
76
|
<script>window.__RSC_ENDPOINT = "${rscEndpoint}";</script>
|
|
75
77
|
<script>window.__RSC_BASENAME = "${basename}";</script>
|
|
76
78
|
<script>window.__RSC_ROUTE_BASE_PATH = "${routeBasePath}";</script>
|
|
79
|
+
<script>window.__WEBFRAMEZ_REACT_BUILD_ID = "${buildId}";</script>
|
|
77
80
|
<script>window.__RSC_INITIAL_PAYLOAD = ${escapedInitialFlightData};</script>
|
|
78
81
|
<script type="module" src="${clientScriptUrl}"></script>
|
|
79
82
|
${liveReloadScript}
|
|
@@ -466,6 +469,9 @@ function mergeHead(...configs) {
|
|
|
466
469
|
if (config.description) {
|
|
467
470
|
merged.description = config.description;
|
|
468
471
|
}
|
|
472
|
+
if (hasOwn("bodyClassName")) {
|
|
473
|
+
merged.bodyClassName = config.bodyClassName;
|
|
474
|
+
}
|
|
469
475
|
if (hasOwn("basename")) {
|
|
470
476
|
merged.basename = config.basename;
|
|
471
477
|
}
|
|
@@ -807,6 +813,15 @@ function createClientAssetVersion(distRootDir) {
|
|
|
807
813
|
return "";
|
|
808
814
|
}
|
|
809
815
|
}
|
|
816
|
+
function createBuildId(distRootDir, manifestPath) {
|
|
817
|
+
const clientVersion = createClientAssetVersion(distRootDir);
|
|
818
|
+
try {
|
|
819
|
+
const stat = fs2.statSync(manifestPath);
|
|
820
|
+
return `${clientVersion}:${Math.floor(stat.mtimeMs)}-${stat.size}`;
|
|
821
|
+
} catch {
|
|
822
|
+
return clientVersion;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
810
825
|
function appendAssetVersion(url, version) {
|
|
811
826
|
if (!version) {
|
|
812
827
|
return url;
|
|
@@ -1500,6 +1515,30 @@ function createServerConsumerManifest(manifest) {
|
|
|
1500
1515
|
}
|
|
1501
1516
|
return consumerManifest;
|
|
1502
1517
|
}
|
|
1518
|
+
function createManifestLoader(options) {
|
|
1519
|
+
let cache = null;
|
|
1520
|
+
return () => {
|
|
1521
|
+
const stat = fs2.statSync(options.manifestPath);
|
|
1522
|
+
const cacheKey = `${Math.floor(stat.mtimeMs)}-${stat.size}`;
|
|
1523
|
+
if (cache && cache.cacheKey === cacheKey) {
|
|
1524
|
+
return cache;
|
|
1525
|
+
}
|
|
1526
|
+
const moduleMap = normalizeClientManifest(
|
|
1527
|
+
JSON.parse(fs2.readFileSync(options.manifestPath, "utf-8")),
|
|
1528
|
+
{
|
|
1529
|
+
distRootDir: options.distRootDir,
|
|
1530
|
+
cwd: options.cwd
|
|
1531
|
+
}
|
|
1532
|
+
);
|
|
1533
|
+
cache = {
|
|
1534
|
+
cacheKey,
|
|
1535
|
+
buildId: createBuildId(options.distRootDir, options.manifestPath),
|
|
1536
|
+
moduleMap,
|
|
1537
|
+
serverConsumerModuleMap: createServerConsumerManifest(moduleMap)
|
|
1538
|
+
};
|
|
1539
|
+
return cache;
|
|
1540
|
+
};
|
|
1541
|
+
}
|
|
1503
1542
|
function createNodeRequestHandler(options) {
|
|
1504
1543
|
const devServerId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1505
1544
|
const distRootDir = path3.resolve(options.distRootDir);
|
|
@@ -1517,14 +1556,11 @@ function createNodeRequestHandler(options) {
|
|
|
1517
1556
|
const liveReloadPath = !liveReloadEnabled ? "" : options.liveReloadPath ?? `${basePath || ""}/__webframez_live_reload`;
|
|
1518
1557
|
const liveReloadClients = /* @__PURE__ */ new Set();
|
|
1519
1558
|
const router = createFileRouter({ pagesDir });
|
|
1520
|
-
const
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
}
|
|
1526
|
-
);
|
|
1527
|
-
const serverConsumerModuleMap = createServerConsumerManifest(moduleMap);
|
|
1559
|
+
const getManifestState = createManifestLoader({
|
|
1560
|
+
distRootDir,
|
|
1561
|
+
manifestPath,
|
|
1562
|
+
cwd: process.cwd()
|
|
1563
|
+
});
|
|
1528
1564
|
const initialHtmlWorker = createInitialHtmlWorker(pagesDir);
|
|
1529
1565
|
const disposeInitialHtmlWorker = () => {
|
|
1530
1566
|
initialHtmlWorker.dispose();
|
|
@@ -1579,6 +1615,7 @@ function createNodeRequestHandler(options) {
|
|
|
1579
1615
|
return;
|
|
1580
1616
|
}
|
|
1581
1617
|
if (url.pathname === rscPath) {
|
|
1618
|
+
const manifestState2 = getManifestState();
|
|
1582
1619
|
const pathname = stripBasePath(url.searchParams.get("path") || "/", basePath);
|
|
1583
1620
|
const requestContext = createRouteRequestContext(
|
|
1584
1621
|
req,
|
|
@@ -1601,8 +1638,9 @@ function createNodeRequestHandler(options) {
|
|
|
1601
1638
|
pageModel: resolved2.pageModel,
|
|
1602
1639
|
head: resolved2.head
|
|
1603
1640
|
};
|
|
1641
|
+
res.setHeader("X-Webframez-React-Build", manifestState2.buildId);
|
|
1604
1642
|
sendRSC(res, payload, {
|
|
1605
|
-
moduleMap,
|
|
1643
|
+
moduleMap: manifestState2.moduleMap,
|
|
1606
1644
|
statusCode: resolved2.statusCode
|
|
1607
1645
|
});
|
|
1608
1646
|
return;
|
|
@@ -1672,8 +1710,9 @@ function createNodeRequestHandler(options) {
|
|
|
1672
1710
|
model: resolved.model,
|
|
1673
1711
|
head: resolved.head
|
|
1674
1712
|
};
|
|
1713
|
+
const manifestState = getManifestState();
|
|
1675
1714
|
const initialFlightData = await renderRSCToString(initialPayload, {
|
|
1676
|
-
moduleMap
|
|
1715
|
+
moduleMap: manifestState.moduleMap
|
|
1677
1716
|
});
|
|
1678
1717
|
const transportBasePath = normalizeRuntimeBasePath(resolved.head.transportBasePath) ?? normalizeRuntimeBasePath(basePath) ?? "";
|
|
1679
1718
|
const shellClientScriptUrl = appendAssetVersion(
|
|
@@ -1690,7 +1729,7 @@ function createNodeRequestHandler(options) {
|
|
|
1690
1729
|
try {
|
|
1691
1730
|
rootHtml = await initialHtmlWorker.renderFromFlightData({
|
|
1692
1731
|
flightData: initialFlightData,
|
|
1693
|
-
moduleMap: serverConsumerModuleMap
|
|
1732
|
+
moduleMap: manifestState.serverConsumerModuleMap
|
|
1694
1733
|
});
|
|
1695
1734
|
} catch (error) {
|
|
1696
1735
|
console.error("[webframez-react] Failed to render initial HTML", error);
|
|
@@ -1698,7 +1737,7 @@ function createNodeRequestHandler(options) {
|
|
|
1698
1737
|
initialHtmlWorker.dispose();
|
|
1699
1738
|
rootHtml = await initialHtmlWorker.renderFromFlightData({
|
|
1700
1739
|
flightData: initialFlightData,
|
|
1701
|
-
moduleMap: serverConsumerModuleMap
|
|
1740
|
+
moduleMap: manifestState.serverConsumerModuleMap
|
|
1702
1741
|
});
|
|
1703
1742
|
} catch (retryError) {
|
|
1704
1743
|
console.error("[webframez-react] Retry for initial HTML failed", retryError);
|
|
@@ -1706,7 +1745,7 @@ function createNodeRequestHandler(options) {
|
|
|
1706
1745
|
initialHtmlWorker.dispose();
|
|
1707
1746
|
rootHtml = await initialHtmlWorker.renderFromFlightData({
|
|
1708
1747
|
flightData: initialFlightData,
|
|
1709
|
-
moduleMap: serverConsumerModuleMap
|
|
1748
|
+
moduleMap: manifestState.serverConsumerModuleMap
|
|
1710
1749
|
});
|
|
1711
1750
|
} catch (flightRenderError) {
|
|
1712
1751
|
console.error("[webframez-react] Flight-to-HTML render failed", flightRenderError);
|
|
@@ -1730,7 +1769,9 @@ function createNodeRequestHandler(options) {
|
|
|
1730
1769
|
createHTMLShell({
|
|
1731
1770
|
title: resolved.head.title || "Webframez React",
|
|
1732
1771
|
headTags: renderHeadToString(resolved.head),
|
|
1772
|
+
bodyClassName: resolved.head.bodyClassName || "",
|
|
1733
1773
|
clientScriptUrl: shellClientScriptUrl,
|
|
1774
|
+
buildId: manifestState.buildId,
|
|
1734
1775
|
rscEndpoint: shellRscEndpoint,
|
|
1735
1776
|
rootHtml,
|
|
1736
1777
|
initialFlightData,
|
package/dist/router.cjs
CHANGED
|
@@ -357,6 +357,9 @@ function mergeHead(...configs) {
|
|
|
357
357
|
if (config.description) {
|
|
358
358
|
merged.description = config.description;
|
|
359
359
|
}
|
|
360
|
+
if (hasOwn("bodyClassName")) {
|
|
361
|
+
merged.bodyClassName = config.bodyClassName;
|
|
362
|
+
}
|
|
360
363
|
if (hasOwn("basename")) {
|
|
361
364
|
merged.basename = config.basename;
|
|
362
365
|
}
|
package/dist/router.js
CHANGED
|
@@ -327,6 +327,9 @@ function mergeHead(...configs) {
|
|
|
327
327
|
if (config.description) {
|
|
328
328
|
merged.description = config.description;
|
|
329
329
|
}
|
|
330
|
+
if (hasOwn("bodyClassName")) {
|
|
331
|
+
merged.bodyClassName = config.bodyClassName;
|
|
332
|
+
}
|
|
330
333
|
if (hasOwn("basename")) {
|
|
331
334
|
merged.basename = config.basename;
|
|
332
335
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -60,6 +60,7 @@ export type HeadLinkTag = {
|
|
|
60
60
|
export type HeadConfig = {
|
|
61
61
|
title?: string;
|
|
62
62
|
description?: string;
|
|
63
|
+
bodyClassName?: string;
|
|
63
64
|
basename?: string;
|
|
64
65
|
routeBasePath?: string;
|
|
65
66
|
transportBasePath?: string;
|
|
@@ -111,7 +112,9 @@ export type CreateHtmlShellOptions = {
|
|
|
111
112
|
title?: string;
|
|
112
113
|
rscEndpoint?: string;
|
|
113
114
|
clientScriptUrl?: string;
|
|
115
|
+
buildId?: string;
|
|
114
116
|
headTags?: string;
|
|
117
|
+
bodyClassName?: string;
|
|
115
118
|
rootHtml?: string;
|
|
116
119
|
initialFlightData?: string;
|
|
117
120
|
basename?: string;
|
package/dist/webframez-core.cjs
CHANGED
|
@@ -59,7 +59,9 @@ function createHTMLShell(options = {}) {
|
|
|
59
59
|
title = "RSC App",
|
|
60
60
|
rscEndpoint = "/rsc",
|
|
61
61
|
clientScriptUrl = "/client.js",
|
|
62
|
+
buildId = "",
|
|
62
63
|
headTags = "",
|
|
64
|
+
bodyClassName = "",
|
|
63
65
|
rootHtml = "",
|
|
64
66
|
initialFlightData = "",
|
|
65
67
|
basename = "",
|
|
@@ -108,11 +110,12 @@ function createHTMLShell(options = {}) {
|
|
|
108
110
|
<title>${title}</title>
|
|
109
111
|
${headTags}
|
|
110
112
|
</head>
|
|
111
|
-
<body>
|
|
113
|
+
<body${bodyClassName ? ` class="${bodyClassName.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">")}"` : ""}>
|
|
112
114
|
<div id="root">${rootHtml}</div>
|
|
113
115
|
<script>window.__RSC_ENDPOINT = "${rscEndpoint}";</script>
|
|
114
116
|
<script>window.__RSC_BASENAME = "${basename}";</script>
|
|
115
117
|
<script>window.__RSC_ROUTE_BASE_PATH = "${routeBasePath}";</script>
|
|
118
|
+
<script>window.__WEBFRAMEZ_REACT_BUILD_ID = "${buildId}";</script>
|
|
116
119
|
<script>window.__RSC_INITIAL_PAYLOAD = ${escapedInitialFlightData};</script>
|
|
117
120
|
<script type="module" src="${clientScriptUrl}"></script>
|
|
118
121
|
${liveReloadScript}
|
|
@@ -477,6 +480,9 @@ function mergeHead(...configs) {
|
|
|
477
480
|
if (config.description) {
|
|
478
481
|
merged.description = config.description;
|
|
479
482
|
}
|
|
483
|
+
if (hasOwn("bodyClassName")) {
|
|
484
|
+
merged.bodyClassName = config.bodyClassName;
|
|
485
|
+
}
|
|
480
486
|
if (hasOwn("basename")) {
|
|
481
487
|
merged.basename = config.basename;
|
|
482
488
|
}
|
|
@@ -808,6 +814,15 @@ function createClientAssetVersion(distRootDir) {
|
|
|
808
814
|
return "";
|
|
809
815
|
}
|
|
810
816
|
}
|
|
817
|
+
function createBuildId(distRootDir, manifestPath) {
|
|
818
|
+
const clientVersion = createClientAssetVersion(distRootDir);
|
|
819
|
+
try {
|
|
820
|
+
const stat = import_node_fs2.default.statSync(manifestPath);
|
|
821
|
+
return `${clientVersion}:${Math.floor(stat.mtimeMs)}-${stat.size}`;
|
|
822
|
+
} catch {
|
|
823
|
+
return clientVersion;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
811
826
|
function appendAssetVersion(url, version) {
|
|
812
827
|
if (!version) {
|
|
813
828
|
return url;
|
|
@@ -1501,6 +1516,30 @@ function createServerConsumerManifest(manifest) {
|
|
|
1501
1516
|
}
|
|
1502
1517
|
return consumerManifest;
|
|
1503
1518
|
}
|
|
1519
|
+
function createManifestLoader(options) {
|
|
1520
|
+
let cache = null;
|
|
1521
|
+
return () => {
|
|
1522
|
+
const stat = import_node_fs2.default.statSync(options.manifestPath);
|
|
1523
|
+
const cacheKey = `${Math.floor(stat.mtimeMs)}-${stat.size}`;
|
|
1524
|
+
if (cache && cache.cacheKey === cacheKey) {
|
|
1525
|
+
return cache;
|
|
1526
|
+
}
|
|
1527
|
+
const moduleMap = normalizeClientManifest(
|
|
1528
|
+
JSON.parse(import_node_fs2.default.readFileSync(options.manifestPath, "utf-8")),
|
|
1529
|
+
{
|
|
1530
|
+
distRootDir: options.distRootDir,
|
|
1531
|
+
cwd: options.cwd
|
|
1532
|
+
}
|
|
1533
|
+
);
|
|
1534
|
+
cache = {
|
|
1535
|
+
cacheKey,
|
|
1536
|
+
buildId: createBuildId(options.distRootDir, options.manifestPath),
|
|
1537
|
+
moduleMap,
|
|
1538
|
+
serverConsumerModuleMap: createServerConsumerManifest(moduleMap)
|
|
1539
|
+
};
|
|
1540
|
+
return cache;
|
|
1541
|
+
};
|
|
1542
|
+
}
|
|
1504
1543
|
function createNodeRequestHandler(options) {
|
|
1505
1544
|
const devServerId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1506
1545
|
const distRootDir = import_node_path3.default.resolve(options.distRootDir);
|
|
@@ -1518,14 +1557,11 @@ function createNodeRequestHandler(options) {
|
|
|
1518
1557
|
const liveReloadPath = !liveReloadEnabled ? "" : options.liveReloadPath ?? `${basePath || ""}/__webframez_live_reload`;
|
|
1519
1558
|
const liveReloadClients = /* @__PURE__ */ new Set();
|
|
1520
1559
|
const router = createFileRouter({ pagesDir });
|
|
1521
|
-
const
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
}
|
|
1527
|
-
);
|
|
1528
|
-
const serverConsumerModuleMap = createServerConsumerManifest(moduleMap);
|
|
1560
|
+
const getManifestState = createManifestLoader({
|
|
1561
|
+
distRootDir,
|
|
1562
|
+
manifestPath,
|
|
1563
|
+
cwd: process.cwd()
|
|
1564
|
+
});
|
|
1529
1565
|
const initialHtmlWorker = createInitialHtmlWorker(pagesDir);
|
|
1530
1566
|
const disposeInitialHtmlWorker = () => {
|
|
1531
1567
|
initialHtmlWorker.dispose();
|
|
@@ -1580,6 +1616,7 @@ function createNodeRequestHandler(options) {
|
|
|
1580
1616
|
return;
|
|
1581
1617
|
}
|
|
1582
1618
|
if (url.pathname === rscPath) {
|
|
1619
|
+
const manifestState2 = getManifestState();
|
|
1583
1620
|
const pathname = stripBasePath(url.searchParams.get("path") || "/", basePath);
|
|
1584
1621
|
const requestContext = createRouteRequestContext(
|
|
1585
1622
|
req,
|
|
@@ -1602,8 +1639,9 @@ function createNodeRequestHandler(options) {
|
|
|
1602
1639
|
pageModel: resolved2.pageModel,
|
|
1603
1640
|
head: resolved2.head
|
|
1604
1641
|
};
|
|
1642
|
+
res.setHeader("X-Webframez-React-Build", manifestState2.buildId);
|
|
1605
1643
|
sendRSC(res, payload, {
|
|
1606
|
-
moduleMap,
|
|
1644
|
+
moduleMap: manifestState2.moduleMap,
|
|
1607
1645
|
statusCode: resolved2.statusCode
|
|
1608
1646
|
});
|
|
1609
1647
|
return;
|
|
@@ -1673,8 +1711,9 @@ function createNodeRequestHandler(options) {
|
|
|
1673
1711
|
model: resolved.model,
|
|
1674
1712
|
head: resolved.head
|
|
1675
1713
|
};
|
|
1714
|
+
const manifestState = getManifestState();
|
|
1676
1715
|
const initialFlightData = await renderRSCToString(initialPayload, {
|
|
1677
|
-
moduleMap
|
|
1716
|
+
moduleMap: manifestState.moduleMap
|
|
1678
1717
|
});
|
|
1679
1718
|
const transportBasePath = normalizeRuntimeBasePath(resolved.head.transportBasePath) ?? normalizeRuntimeBasePath(basePath) ?? "";
|
|
1680
1719
|
const shellClientScriptUrl = appendAssetVersion(
|
|
@@ -1691,7 +1730,7 @@ function createNodeRequestHandler(options) {
|
|
|
1691
1730
|
try {
|
|
1692
1731
|
rootHtml = await initialHtmlWorker.renderFromFlightData({
|
|
1693
1732
|
flightData: initialFlightData,
|
|
1694
|
-
moduleMap: serverConsumerModuleMap
|
|
1733
|
+
moduleMap: manifestState.serverConsumerModuleMap
|
|
1695
1734
|
});
|
|
1696
1735
|
} catch (error) {
|
|
1697
1736
|
console.error("[webframez-react] Failed to render initial HTML", error);
|
|
@@ -1699,7 +1738,7 @@ function createNodeRequestHandler(options) {
|
|
|
1699
1738
|
initialHtmlWorker.dispose();
|
|
1700
1739
|
rootHtml = await initialHtmlWorker.renderFromFlightData({
|
|
1701
1740
|
flightData: initialFlightData,
|
|
1702
|
-
moduleMap: serverConsumerModuleMap
|
|
1741
|
+
moduleMap: manifestState.serverConsumerModuleMap
|
|
1703
1742
|
});
|
|
1704
1743
|
} catch (retryError) {
|
|
1705
1744
|
console.error("[webframez-react] Retry for initial HTML failed", retryError);
|
|
@@ -1707,7 +1746,7 @@ function createNodeRequestHandler(options) {
|
|
|
1707
1746
|
initialHtmlWorker.dispose();
|
|
1708
1747
|
rootHtml = await initialHtmlWorker.renderFromFlightData({
|
|
1709
1748
|
flightData: initialFlightData,
|
|
1710
|
-
moduleMap: serverConsumerModuleMap
|
|
1749
|
+
moduleMap: manifestState.serverConsumerModuleMap
|
|
1711
1750
|
});
|
|
1712
1751
|
} catch (flightRenderError) {
|
|
1713
1752
|
console.error("[webframez-react] Flight-to-HTML render failed", flightRenderError);
|
|
@@ -1731,7 +1770,9 @@ function createNodeRequestHandler(options) {
|
|
|
1731
1770
|
createHTMLShell({
|
|
1732
1771
|
title: resolved.head.title || "Webframez React",
|
|
1733
1772
|
headTags: renderHeadToString(resolved.head),
|
|
1773
|
+
bodyClassName: resolved.head.bodyClassName || "",
|
|
1734
1774
|
clientScriptUrl: shellClientScriptUrl,
|
|
1775
|
+
buildId: manifestState.buildId,
|
|
1735
1776
|
rscEndpoint: shellRscEndpoint,
|
|
1736
1777
|
rootHtml,
|
|
1737
1778
|
initialFlightData,
|
package/dist/webframez-core.js
CHANGED
|
@@ -35,7 +35,9 @@ function createHTMLShell(options = {}) {
|
|
|
35
35
|
title = "RSC App",
|
|
36
36
|
rscEndpoint = "/rsc",
|
|
37
37
|
clientScriptUrl = "/client.js",
|
|
38
|
+
buildId = "",
|
|
38
39
|
headTags = "",
|
|
40
|
+
bodyClassName = "",
|
|
39
41
|
rootHtml = "",
|
|
40
42
|
initialFlightData = "",
|
|
41
43
|
basename = "",
|
|
@@ -84,11 +86,12 @@ function createHTMLShell(options = {}) {
|
|
|
84
86
|
<title>${title}</title>
|
|
85
87
|
${headTags}
|
|
86
88
|
</head>
|
|
87
|
-
<body>
|
|
89
|
+
<body${bodyClassName ? ` class="${bodyClassName.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">")}"` : ""}>
|
|
88
90
|
<div id="root">${rootHtml}</div>
|
|
89
91
|
<script>window.__RSC_ENDPOINT = "${rscEndpoint}";</script>
|
|
90
92
|
<script>window.__RSC_BASENAME = "${basename}";</script>
|
|
91
93
|
<script>window.__RSC_ROUTE_BASE_PATH = "${routeBasePath}";</script>
|
|
94
|
+
<script>window.__WEBFRAMEZ_REACT_BUILD_ID = "${buildId}";</script>
|
|
92
95
|
<script>window.__RSC_INITIAL_PAYLOAD = ${escapedInitialFlightData};</script>
|
|
93
96
|
<script type="module" src="${clientScriptUrl}"></script>
|
|
94
97
|
${liveReloadScript}
|
|
@@ -453,6 +456,9 @@ function mergeHead(...configs) {
|
|
|
453
456
|
if (config.description) {
|
|
454
457
|
merged.description = config.description;
|
|
455
458
|
}
|
|
459
|
+
if (hasOwn("bodyClassName")) {
|
|
460
|
+
merged.bodyClassName = config.bodyClassName;
|
|
461
|
+
}
|
|
456
462
|
if (hasOwn("basename")) {
|
|
457
463
|
merged.basename = config.basename;
|
|
458
464
|
}
|
|
@@ -784,6 +790,15 @@ function createClientAssetVersion(distRootDir) {
|
|
|
784
790
|
return "";
|
|
785
791
|
}
|
|
786
792
|
}
|
|
793
|
+
function createBuildId(distRootDir, manifestPath) {
|
|
794
|
+
const clientVersion = createClientAssetVersion(distRootDir);
|
|
795
|
+
try {
|
|
796
|
+
const stat = fs2.statSync(manifestPath);
|
|
797
|
+
return `${clientVersion}:${Math.floor(stat.mtimeMs)}-${stat.size}`;
|
|
798
|
+
} catch {
|
|
799
|
+
return clientVersion;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
787
802
|
function appendAssetVersion(url, version) {
|
|
788
803
|
if (!version) {
|
|
789
804
|
return url;
|
|
@@ -1477,6 +1492,30 @@ function createServerConsumerManifest(manifest) {
|
|
|
1477
1492
|
}
|
|
1478
1493
|
return consumerManifest;
|
|
1479
1494
|
}
|
|
1495
|
+
function createManifestLoader(options) {
|
|
1496
|
+
let cache = null;
|
|
1497
|
+
return () => {
|
|
1498
|
+
const stat = fs2.statSync(options.manifestPath);
|
|
1499
|
+
const cacheKey = `${Math.floor(stat.mtimeMs)}-${stat.size}`;
|
|
1500
|
+
if (cache && cache.cacheKey === cacheKey) {
|
|
1501
|
+
return cache;
|
|
1502
|
+
}
|
|
1503
|
+
const moduleMap = normalizeClientManifest(
|
|
1504
|
+
JSON.parse(fs2.readFileSync(options.manifestPath, "utf-8")),
|
|
1505
|
+
{
|
|
1506
|
+
distRootDir: options.distRootDir,
|
|
1507
|
+
cwd: options.cwd
|
|
1508
|
+
}
|
|
1509
|
+
);
|
|
1510
|
+
cache = {
|
|
1511
|
+
cacheKey,
|
|
1512
|
+
buildId: createBuildId(options.distRootDir, options.manifestPath),
|
|
1513
|
+
moduleMap,
|
|
1514
|
+
serverConsumerModuleMap: createServerConsumerManifest(moduleMap)
|
|
1515
|
+
};
|
|
1516
|
+
return cache;
|
|
1517
|
+
};
|
|
1518
|
+
}
|
|
1480
1519
|
function createNodeRequestHandler(options) {
|
|
1481
1520
|
const devServerId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1482
1521
|
const distRootDir = path3.resolve(options.distRootDir);
|
|
@@ -1494,14 +1533,11 @@ function createNodeRequestHandler(options) {
|
|
|
1494
1533
|
const liveReloadPath = !liveReloadEnabled ? "" : options.liveReloadPath ?? `${basePath || ""}/__webframez_live_reload`;
|
|
1495
1534
|
const liveReloadClients = /* @__PURE__ */ new Set();
|
|
1496
1535
|
const router = createFileRouter({ pagesDir });
|
|
1497
|
-
const
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
}
|
|
1503
|
-
);
|
|
1504
|
-
const serverConsumerModuleMap = createServerConsumerManifest(moduleMap);
|
|
1536
|
+
const getManifestState = createManifestLoader({
|
|
1537
|
+
distRootDir,
|
|
1538
|
+
manifestPath,
|
|
1539
|
+
cwd: process.cwd()
|
|
1540
|
+
});
|
|
1505
1541
|
const initialHtmlWorker = createInitialHtmlWorker(pagesDir);
|
|
1506
1542
|
const disposeInitialHtmlWorker = () => {
|
|
1507
1543
|
initialHtmlWorker.dispose();
|
|
@@ -1556,6 +1592,7 @@ function createNodeRequestHandler(options) {
|
|
|
1556
1592
|
return;
|
|
1557
1593
|
}
|
|
1558
1594
|
if (url.pathname === rscPath) {
|
|
1595
|
+
const manifestState2 = getManifestState();
|
|
1559
1596
|
const pathname = stripBasePath(url.searchParams.get("path") || "/", basePath);
|
|
1560
1597
|
const requestContext = createRouteRequestContext(
|
|
1561
1598
|
req,
|
|
@@ -1578,8 +1615,9 @@ function createNodeRequestHandler(options) {
|
|
|
1578
1615
|
pageModel: resolved2.pageModel,
|
|
1579
1616
|
head: resolved2.head
|
|
1580
1617
|
};
|
|
1618
|
+
res.setHeader("X-Webframez-React-Build", manifestState2.buildId);
|
|
1581
1619
|
sendRSC(res, payload, {
|
|
1582
|
-
moduleMap,
|
|
1620
|
+
moduleMap: manifestState2.moduleMap,
|
|
1583
1621
|
statusCode: resolved2.statusCode
|
|
1584
1622
|
});
|
|
1585
1623
|
return;
|
|
@@ -1649,8 +1687,9 @@ function createNodeRequestHandler(options) {
|
|
|
1649
1687
|
model: resolved.model,
|
|
1650
1688
|
head: resolved.head
|
|
1651
1689
|
};
|
|
1690
|
+
const manifestState = getManifestState();
|
|
1652
1691
|
const initialFlightData = await renderRSCToString(initialPayload, {
|
|
1653
|
-
moduleMap
|
|
1692
|
+
moduleMap: manifestState.moduleMap
|
|
1654
1693
|
});
|
|
1655
1694
|
const transportBasePath = normalizeRuntimeBasePath(resolved.head.transportBasePath) ?? normalizeRuntimeBasePath(basePath) ?? "";
|
|
1656
1695
|
const shellClientScriptUrl = appendAssetVersion(
|
|
@@ -1667,7 +1706,7 @@ function createNodeRequestHandler(options) {
|
|
|
1667
1706
|
try {
|
|
1668
1707
|
rootHtml = await initialHtmlWorker.renderFromFlightData({
|
|
1669
1708
|
flightData: initialFlightData,
|
|
1670
|
-
moduleMap: serverConsumerModuleMap
|
|
1709
|
+
moduleMap: manifestState.serverConsumerModuleMap
|
|
1671
1710
|
});
|
|
1672
1711
|
} catch (error) {
|
|
1673
1712
|
console.error("[webframez-react] Failed to render initial HTML", error);
|
|
@@ -1675,7 +1714,7 @@ function createNodeRequestHandler(options) {
|
|
|
1675
1714
|
initialHtmlWorker.dispose();
|
|
1676
1715
|
rootHtml = await initialHtmlWorker.renderFromFlightData({
|
|
1677
1716
|
flightData: initialFlightData,
|
|
1678
|
-
moduleMap: serverConsumerModuleMap
|
|
1717
|
+
moduleMap: manifestState.serverConsumerModuleMap
|
|
1679
1718
|
});
|
|
1680
1719
|
} catch (retryError) {
|
|
1681
1720
|
console.error("[webframez-react] Retry for initial HTML failed", retryError);
|
|
@@ -1683,7 +1722,7 @@ function createNodeRequestHandler(options) {
|
|
|
1683
1722
|
initialHtmlWorker.dispose();
|
|
1684
1723
|
rootHtml = await initialHtmlWorker.renderFromFlightData({
|
|
1685
1724
|
flightData: initialFlightData,
|
|
1686
|
-
moduleMap: serverConsumerModuleMap
|
|
1725
|
+
moduleMap: manifestState.serverConsumerModuleMap
|
|
1687
1726
|
});
|
|
1688
1727
|
} catch (flightRenderError) {
|
|
1689
1728
|
console.error("[webframez-react] Flight-to-HTML render failed", flightRenderError);
|
|
@@ -1707,7 +1746,9 @@ function createNodeRequestHandler(options) {
|
|
|
1707
1746
|
createHTMLShell({
|
|
1708
1747
|
title: resolved.head.title || "Webframez React",
|
|
1709
1748
|
headTags: renderHeadToString(resolved.head),
|
|
1749
|
+
bodyClassName: resolved.head.bodyClassName || "",
|
|
1710
1750
|
clientScriptUrl: shellClientScriptUrl,
|
|
1751
|
+
buildId: manifestState.buildId,
|
|
1711
1752
|
rscEndpoint: shellRscEndpoint,
|
|
1712
1753
|
rootHtml,
|
|
1713
1754
|
initialFlightData,
|