@lomray/react-head-manager 2.2.0 → 2.2.1
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/README.md +4 -0
- package/package.json +2 -1
- package/server/index.js +1 -1
- package/server/index.js.map +1 -1
package/README.md
CHANGED
|
@@ -89,6 +89,10 @@ manager.setTagsDefinitions({
|
|
|
89
89
|
|
|
90
90
|
Explore [demo app](https://github.com/Lomray-Software/vite-template) to more understand.
|
|
91
91
|
|
|
92
|
+
## Workers and edge rendering
|
|
93
|
+
|
|
94
|
+
The `@lomray/react-head-manager/server` entry supports Cloudflare Workers and other non-DOM edge bundles, including Vite SSR with `ssr.target: 'webworker'`. `MetaServer.inject` and `MetaServer.getState` work without a `document` global or bundler aliases for `html-dom-parser`.
|
|
95
|
+
|
|
92
96
|
## Bundle size
|
|
93
97
|
|
|
94
98
|
The browser build reads the existing head from the DOM and ships no HTML parser. `html-react-parser` is used only by the server helper.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lomray/react-head-manager",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "React meta tags manager with SSR and Suspense support.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"lint:format": "eslint --fix \"src/**/*.{ts,tsx,*.ts,*tsx}\"",
|
|
39
39
|
"ts:check": "tsc --project ./tsconfig.json --skipLibCheck --noemit",
|
|
40
40
|
"test": "vitest run",
|
|
41
|
+
"test:worker": "node scripts/test-worker.mjs",
|
|
41
42
|
"test:package": "node scripts/test-package.mjs"
|
|
42
43
|
},
|
|
43
44
|
"dependencies": {
|
package/server/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import t from"html-
|
|
1
|
+
import t from"html-dom-parser/lib/server/html-to-dom";import e from"html-react-parser/lib/dom-to-react";import r from"react";import a from"react-dom/server";import o from"../manager.js";const m=r=>e(t(r,{lowerCaseAttributeNames:!1}));class s{static inject(t,e){const s=t.match(/<head[^/].+?>?(?<meta>.+)<\/head>/s),i=t.match(/<html[^>]*?>/s),d=t.match(/<body[^>]*?>/s),n=m(s?.groups?.meta.trim()??""),c=m(i?.[0]?`${i?.[0].trim()}</html>`:""),l=m(d?.[0]?`${d?.[0].trim()}</body>`:"");e.pushTags(c,o.rootContainerId,!1),e.pushTags(l,o.rootContainerId,!1),e.pushTags(n,o.rootContainerId,!1);const{meta:p,html:h,body:g}=e.getTags(),u=a.renderToString([...p.values()].map((({element:t})=>t))),[b]=a.renderToStaticMarkup(r.createElement("div",e.getRootTagProps(h))).replace(/^<div/,"<html").split("</div>"),[T]=a.renderToStaticMarkup(r.createElement("div",e.getRootTagProps(g))).replace(/^<div/,"<body").split("</div>");return t.replace(/<head[^/].+?>?(?<meta>.+)<\/head>/s,`<head>${u}</head>`).replace(/<html[^>]*?>/s,b).replace(/<body[^>]*?>/s,T)}static getState(t){const{html:e,body:r,containers:a}=t.getTags();return{html:[...e.entries()],body:[...r.entries()],containers:[...a]}}}export{s as default};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/server/index.ts"],"sourcesContent":["// noinspection HtmlRequiredTitleElement\n\nimport
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/server/index.ts"],"sourcesContent":["// noinspection HtmlRequiredTitleElement\n\nimport htmlToDOM from 'html-dom-parser/lib/server/html-to-dom';\nimport domToReact from 'html-react-parser/lib/dom-to-react';\nimport type { ReactElement } from 'react';\nimport React from 'react';\nimport ReactDOMServer from 'react-dom/server';\nimport Manager from '../manager';\n\ninterface IMetaManagerState {\n html: [string, Record<string, any>][];\n body: [string, Record<string, any>][];\n containers: string[];\n}\n\n/**\n * Parse markup without a DOM while preserving React attribute conversion.\n */\nconst htmlParser = (html: string): ReturnType<typeof domToReact> =>\n domToReact(htmlToDOM(html, { lowerCaseAttributeNames: false }));\n\n/**\n * Helpers for server side\n */\nclass ServerManager {\n /**\n * Parse existing head tags from html and merge with tags received at the render stage (from manager)\n *\n * @return new html with actual meta tags\n */\n public static inject(htmlStr: string, manager: Manager): string {\n const matchedMetaHtml = htmlStr.match(/<head[^/].+?>?(?<meta>.+)<\\/head>/s);\n const matchedHtmlAttr = htmlStr.match(/<html[^>]*?>/s);\n const matchedBodyAttr = htmlStr.match(/<body[^>]*?>/s);\n const rootTags = htmlParser(matchedMetaHtml?.groups?.meta.trim() ?? '');\n const htmlTag = htmlParser(matchedHtmlAttr?.[0] ? `${matchedHtmlAttr?.[0].trim()}</html>` : '');\n const bodyTag = htmlParser(matchedBodyAttr?.[0] ? `${matchedBodyAttr?.[0].trim()}</body>` : '');\n\n // add root html props\n manager.pushTags(htmlTag, Manager.rootContainerId, false);\n // add root body props\n manager.pushTags(bodyTag, Manager.rootContainerId, false);\n // add root meta tags to manager\n manager.pushTags(rootTags, Manager.rootContainerId, false);\n\n const { meta, html, body } = manager.getTags();\n const htmlMeta = ReactDOMServer.renderToString(\n [...meta.values()].map(({ element }) => element) as unknown as ReactElement,\n );\n // Render a neutral element so React 19 does not insert document structure.\n const [htmlTagWithProps] = ReactDOMServer.renderToStaticMarkup(\n React.createElement('div', manager.getRootTagProps(html)),\n )\n .replace(/^<div/, '<html')\n .split('</div>');\n const [bodyTagWithProps] = ReactDOMServer.renderToStaticMarkup(\n React.createElement('div', manager.getRootTagProps(body)),\n )\n .replace(/^<div/, '<body')\n .split('</div>');\n\n return htmlStr\n .replace(/<head[^/].+?>?(?<meta>.+)<\\/head>/s, `<head>${htmlMeta}</head>`)\n .replace(/<html[^>]*?>/s, htmlTagWithProps)\n .replace(/<body[^>]*?>/s, bodyTagWithProps);\n }\n\n /**\n * Get meta manager state to pass on client\n */\n public static getState(manager: Manager): IMetaManagerState {\n const { html, body, containers } = manager.getTags();\n\n return {\n html: [...html.entries()],\n body: [...body.entries()],\n containers: [...containers],\n };\n }\n}\n\nexport default ServerManager;\n"],"names":["htmlParser","html","domToReact","htmlToDOM","lowerCaseAttributeNames","ServerManager","static","htmlStr","manager","matchedMetaHtml","match","matchedHtmlAttr","matchedBodyAttr","rootTags","groups","meta","trim","htmlTag","bodyTag","pushTags","Manager","rootContainerId","body","getTags","htmlMeta","ReactDOMServer","renderToString","values","map","element","htmlTagWithProps","renderToStaticMarkup","React","createElement","getRootTagProps","replace","split","bodyTagWithProps","containers","entries"],"mappings":"0LAkBA,MAAMA,EAAcC,GAClBC,EAAWC,EAAUF,EAAM,CAAEG,yBAAyB,KAKxD,MAAMC,EAMGC,cAAcC,EAAiBC,GACpC,MAAMC,EAAkBF,EAAQG,MAAM,sCAChCC,EAAkBJ,EAAQG,MAAM,iBAChCE,EAAkBL,EAAQG,MAAM,iBAChCG,EAAWb,EAAWS,GAAiBK,QAAQC,KAAKC,QAAU,IAC9DC,EAAUjB,EAAWW,IAAkB,GAAK,GAAGA,IAAkB,GAAGK,gBAAkB,IACtFE,EAAUlB,EAAWY,IAAkB,GAAK,GAAGA,IAAkB,GAAGI,gBAAkB,IAG5FR,EAAQW,SAASF,EAASG,EAAQC,iBAAiB,GAEnDb,EAAQW,SAASD,EAASE,EAAQC,iBAAiB,GAEnDb,EAAQW,SAASN,EAAUO,EAAQC,iBAAiB,GAEpD,MAAMN,KAAEA,EAAId,KAAEA,EAAIqB,KAAEA,GAASd,EAAQe,UAC/BC,EAAWC,EAAeC,eAC9B,IAAIX,EAAKY,UAAUC,KAAI,EAAGC,aAAcA,MAGnCC,GAAoBL,EAAeM,qBACxCC,EAAMC,cAAc,MAAOzB,EAAQ0B,gBAAgBjC,KAElDkC,QAAQ,QAAS,SACjBC,MAAM,WACFC,GAAoBZ,EAAeM,qBACxCC,EAAMC,cAAc,MAAOzB,EAAQ0B,gBAAgBZ,KAElDa,QAAQ,QAAS,SACjBC,MAAM,UAET,OAAO7B,EACJ4B,QAAQ,qCAAsC,SAASX,YACvDW,QAAQ,gBAAiBL,GACzBK,QAAQ,gBAAiBE,EAC7B,CAKM/B,gBAAgBE,GACrB,MAAMP,KAAEA,EAAIqB,KAAEA,EAAIgB,WAAEA,GAAe9B,EAAQe,UAE3C,MAAO,CACLtB,KAAM,IAAIA,EAAKsC,WACfjB,KAAM,IAAIA,EAAKiB,WACfD,WAAY,IAAIA,GAEnB"}
|