@lomray/react-head-manager 1.1.0 → 1.1.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/manager.d.ts +5 -0
- package/manager.js +1 -1
- package/manager.js.map +1 -1
- package/package.json +1 -1
package/manager.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
import { ReactElement, ReactNode } from 'react';
|
|
2
3
|
declare enum TagStatus {
|
|
3
4
|
init = "init",
|
|
@@ -48,6 +49,10 @@ declare class Manager {
|
|
|
48
49
|
protected reservedAttributes: {
|
|
49
50
|
order: string;
|
|
50
51
|
};
|
|
52
|
+
/**
|
|
53
|
+
* Scheduled synchronization
|
|
54
|
+
*/
|
|
55
|
+
protected syncTimerId: null | NodeJS.Timeout;
|
|
51
56
|
/**
|
|
52
57
|
* @constructor
|
|
53
58
|
*/
|
package/manager.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("@babel/runtime/helpers/defineProperty"),t=require("html-react-parser"),i=require("react");function r(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var n,s=r(e),o=r(t),a=r(i);!function(e){e.init="init",e.synced="synced",e.drain="drain"}(n||(n={}));class l{constructor(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};s.default(this,"isServer","undefined"==typeof window),s.default(this,"tags",void 0),s.default(this,"tagsDefinitions",{"meta[charset]":{order:10},"meta[name='viewport']":{order:20},title:{order:100},base:{order:110},meta:{order:200},link:{order:300},script:{order:400},noscript:{order:500},style:{order:600}}),s.default(this,"reservedAttributes",{order:"data-order"}),this.tags={html:new Map(null==e?void 0:e.html),body:new Map(null==e?void 0:e.body),meta:new Map(null==e?void 0:e.meta),containers:new Set(null==e?void 0:e.containers)}}setTagsDefinitions(e){this.tagsDefinitions={...this.tagsDefinitions,...e}}static cleanupElementProps(e){const{children:t,dangerouslySetInnerHTML:i,...r}=e;return r}getTags(){const{meta:e,body:t,html:i,containers:r}=this.tags;return{body:t,html:i,meta:new Map([...e.entries()].sort(((e,t)=>{let[,i]=e,[,r]=t;return i.order-r.order}))),containers:r}}replaceAttribute(e,t){return"meta"===e&&"httpequiv"===t.toLowerCase()?"http-equiv":t}createDomElement(e){if(this.isServer)return;const{type:t,props:i}=e,r=document.createElement(t);return this.applyDomElementAttributes(r,i),r}buildKeyByProps(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r="";for(const e of["id","name","href","src"])if(t[e]){r="[".concat(e,"='").concat(t[e],"']");break}if(r||i||(r=Object.entries(t).map((e=>{let[t,i]=e;return"string"==typeof i&&"[".concat(t,"]")})).filter(Boolean).join("")),r)return"".concat(e).concat(r)}getDefaultKey(e,t,i){return"".concat(e,"-").concat(t,"-").concat(i,"-not-unique")}isNotUniqueTag(e){return e.endsWith("-not-unique")}cloneElement(e){var t;const{type:i}=e,r={...null!==(t=null==e?void 0:e.props)&&void 0!==t?t:{}};return Object.values(this.reservedAttributes).forEach((e=>{r[e]&&delete r[e]})),"title"===i&&Array.isArray(r.children)&&(r.children=r.children.join("")),{element:a.default.createElement(i,r),elementProps:r}}pushElements(e,t){let r=!(arguments.length>2&&void 0!==arguments[2])||arguments[2],s=arguments.length>3&&void 0!==arguments[3]?arguments[3]:n.init;i.Children.forEach(e,((e,i)=>{var o,a,d,u,c,h,m;if(!e||"object"!=typeof e||!("type"in e)||!e.type)return;const{type:v}=e,{element:f,elementProps:g}=this.cloneElement(e),
|
|
1
|
+
"use strict";var e=require("@babel/runtime/helpers/defineProperty"),t=require("html-react-parser"),i=require("react");function r(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var n,s=r(e),o=r(t),a=r(i);!function(e){e.init="init",e.synced="synced",e.drain="drain"}(n||(n={}));class l{constructor(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};s.default(this,"isServer","undefined"==typeof window),s.default(this,"tags",void 0),s.default(this,"tagsDefinitions",{"meta[charset]":{order:10},"meta[name='viewport']":{order:20},title:{order:100},base:{order:110},meta:{order:200},link:{order:300},script:{order:400},noscript:{order:500},style:{order:600}}),s.default(this,"reservedAttributes",{order:"data-order"}),s.default(this,"syncTimerId",null),this.tags={html:new Map(null==e?void 0:e.html),body:new Map(null==e?void 0:e.body),meta:new Map(null==e?void 0:e.meta),containers:new Set(null==e?void 0:e.containers)}}setTagsDefinitions(e){this.tagsDefinitions={...this.tagsDefinitions,...e}}static cleanupElementProps(e){const{children:t,dangerouslySetInnerHTML:i,...r}=e;return r}getTags(){const{meta:e,body:t,html:i,containers:r}=this.tags;return{body:t,html:i,meta:new Map([...e.entries()].sort(((e,t)=>{let[,i]=e,[,r]=t;return i.order-r.order}))),containers:r}}replaceAttribute(e,t){return"meta"===e&&"httpequiv"===t.toLowerCase()?"http-equiv":t}createDomElement(e){if(this.isServer)return;const{type:t,props:i}=e,r=document.createElement(t);return this.applyDomElementAttributes(r,i),r}buildKeyByProps(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r="";for(const e of["id","name","href","src"])if(t[e]){r="[".concat(e,"='").concat(t[e],"']");break}if(r||i||(r=Object.entries(t).map((e=>{let[t,i]=e;return"string"==typeof i&&"[".concat(t,"]")})).filter(Boolean).join("")),r)return"".concat(e).concat(r)}getDefaultKey(e,t,i){return"".concat(e,"-").concat(t,"-").concat(i,"-not-unique")}isNotUniqueTag(e){return e.endsWith("-not-unique")}cloneElement(e){var t;const{type:i}=e,r={...null!==(t=null==e?void 0:e.props)&&void 0!==t?t:{}};return Object.values(this.reservedAttributes).forEach((e=>{r[e]&&delete r[e]})),"title"===i&&Array.isArray(r.children)&&(r.children=r.children.join("")),{element:a.default.createElement(i,r),elementProps:r}}pushElements(e,t){let r=!(arguments.length>2&&void 0!==arguments[2])||arguments[2],s=arguments.length>3&&void 0!==arguments[3]?arguments[3]:n.init;i.Children.forEach(e,((e,i)=>{var o,a,d,u,c,h,m;if(!e||"object"!=typeof e||!("type"in e)||!e.type)return;const{type:v}=e,{element:f,elementProps:g}=this.cloneElement(e),y=g[this.reservedAttributes.order]?Number(g[this.reservedAttributes.order]):void 0;let p=null!==(o=null!=y?y:null===(a=this.tagsDefinitions[v])||void 0===a?void 0:a.order)&&void 0!==o?o:1e3,b=null!==(d=null===(u=this.tagsDefinitions[v])||void 0===u?void 0:u.key)&&void 0!==d?d:v;switch(v){case"title":break;case"meta":const{charSet:e,httpEquiv:n}=g;b=e?"meta[charset]":n?"meta[httpEquiv]":this.buildKeyByProps(v,g);break;case"html":case"body":if(!r&&this.tags[v].has(b))return;return void this.tags[v].set(t,l.cleanupElementProps(g));default:b=null!==(c=this.buildKeyByProps(v,g,!0))&&void 0!==c?c:this.getDefaultKey(v,t,i)}if((r||!this.tags.meta.has(b))&&(!this.isNotUniqueTag(b)||(null===(h=this.tags.meta.get(b))||void 0===h?void 0:h.status)!==n.synced)){var E;if(null!==(m=this.tagsDefinitions[b])&&void 0!==m&&m.order)p=null===(E=this.tagsDefinitions[b])||void 0===E?void 0:E.order;this.tags.meta.set(b,{element:this.isServer?f:void 0,domElement:t===l.rootContainerId?void 0:this.createDomElement(f),order:p,containerId:t,status:s})}})),this.tags.containers.add(t)}getRootTagProps(e){return e.size?[...e.values()].reduce(((e,t)=>({...e,...t})),{}):{}}applyDomElementAttributes(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const i=e.tagName.toLowerCase(),r=Object.values(this.reservedAttributes);Object.entries(t).forEach((t=>{let[n,s]=t;switch(n){case"children":return void(e.innerHTML=s);case"style":return Object.entries(s).forEach((t=>{let[i,r]=t;e.style[i]=r}))}r[n]||e.setAttribute(this.replaceAttribute(i,n),s)}))}syncMeta(e){var t;const{meta:i,html:r,body:s}=this.getTags();this.syncTimerId&&clearTimeout(this.syncTimerId);for(const{name:e,value:t}of[{name:"html",value:r},{name:"body",value:s}]){var o;const i=this.getRootTagProps(t),r=document.querySelector(e);(null!==(o=null==r?void 0:r.getAttributeNames())&&void 0!==o?o:[]).forEach((e=>{i[e]||r.removeAttribute(e)})),Object.keys(i).length&&r&&this.applyDomElementAttributes(r,i)}if(!i.size||this.isServer)return;const a=null===(t=document.getElementsByTagName("head"))||void 0===t?void 0:t[0];let l;i.forEach(((t,r)=>{const{status:s,domElement:o}=t;if(s===n.synced||!o||e&&e!==t.containerId)return void(l=o);if(s===n.drain)return l=o.previousSibling,null==o||o.remove(),void i.delete(r);if(t.status=n.synced,!this.isNotUniqueTag(r)){const e=document.querySelector(r);if(e)return l=o,void e.replaceWith(o)}const d=l&&l.nextSibling;d?a.insertBefore(o,d):a.append(o),l=o}))}pushTags(e,t){let i=!(arguments.length>2&&void 0!==arguments[2])||arguments[2];const r=this.tags.containers.has(t);this.pushElements(e,t,i,r?n.synced:n.init),this.isServer||r||this.syncMeta()}removeTags(e){this.tags.meta.forEach(((t,i)=>{if(t.containerId===e&&t.containerId!==l.rootContainerId){var r;if(this.isNotUniqueTag(i))return null===(r=t.domElement)||void 0===r||r.remove(),void this.tags.meta.delete(i);t.status=n.drain}})),e!==l.rootContainerId&&(this.tags.body.delete(e),this.tags.html.delete(e),this.tags.containers.delete(e),this.syncTimerId=setTimeout((()=>this.syncMeta()),500))}analyzeClientHead(){var e,t;if(this.isServer)return;for(const e of["html","body"]){var i,r;const t=null===(i=document.getElementsByTagName(e))||void 0===i||null===(r=i[0].cloneNode(!1))||void 0===r?void 0:r.outerHTML;this.pushElements(o.default(t),l.rootContainerId,!1)}const s=null===(e=document.getElementsByTagName("head"))||void 0===e?void 0:e[0],a=o.default(null!==(t=null==s?void 0:s.innerHTML)&&void 0!==t?t:"");this.pushElements(a,l.rootContainerId,!1,n.synced);const d=[...this.tags.meta.values()];s.childNodes.forEach(((e,t)=>{const i=d[t];i&&(i.domElement=e)}))}}s.default(l,"rootContainerId","root"),module.exports=l;
|
|
2
2
|
//# sourceMappingURL=manager.js.map
|
package/manager.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","sources":["../src/manager.ts"],"sourcesContent":["import htmlParser from 'html-react-parser';\nimport type { ReactElement, ReactNode } from 'react';\nimport React, { Children } from 'react';\n\nenum TagStatus {\n init = 'init',\n synced = 'synced',\n drain = 'drain',\n}\n\nexport interface IMetaManagerTags {\n html: Map<string, Record<string, any>>; // containerId => styles\n body: Map<string, Record<string, any>>; // containerId => styles\n meta: Map<\n string,\n {\n element?: ReactElement;\n domElement?: HTMLElement;\n order: number;\n containerId: string;\n status: TagStatus;\n }\n >;\n containers: Set<string>;\n}\n\nexport interface IMetaManagerTagsDefinitions {\n [type: string]: {\n key?: string;\n order: number;\n };\n}\n\n/**\n * Meta tags manager\n */\nclass Manager {\n /**\n * Root container id\n */\n public static rootContainerId = 'root';\n\n /**\n * Detect server side\n */\n public isServer = typeof window === 'undefined';\n\n /**\n * Meta tags state\n */\n protected tags: IMetaManagerTags;\n\n /**\n * Tags definitions\n */\n protected tagsDefinitions: IMetaManagerTagsDefinitions = {\n 'meta[charset]': {\n order: 10,\n },\n \"meta[name='viewport']\": {\n order: 20,\n },\n title: {\n order: 100,\n },\n base: {\n order: 110,\n },\n meta: {\n order: 200,\n },\n link: {\n order: 300,\n },\n script: {\n order: 400,\n },\n noscript: {\n order: 500,\n },\n style: {\n order: 600,\n },\n };\n\n /**\n * System tag attributes\n */\n protected reservedAttributes = {\n order: 'data-order',\n };\n\n /**\n * @constructor\n */\n constructor(tags: Partial<Manager['tags']> = {}) {\n this.tags = {\n html: new Map(tags?.html),\n body: new Map(tags?.body),\n meta: new Map(tags?.meta),\n containers: new Set(tags?.containers),\n };\n }\n\n /**\n * Set tags definitions\n */\n public setTagsDefinitions(definitions: IMetaManagerTagsDefinitions): void {\n this.tagsDefinitions = { ...this.tagsDefinitions, ...definitions };\n }\n\n /**\n * Remove children, dangerouslySetInnerHTML etc.\n */\n public static cleanupElementProps(props: Record<string, any>): Record<string, any> {\n const { children: _, dangerouslySetInnerHTML: __, ...restProps } = props;\n\n return restProps;\n }\n\n /**\n * Get meta tags\n */\n public getTags(): IMetaManagerTags {\n const { meta, body, html, containers } = this.tags;\n const sortedTags = new Map(\n [...meta.entries()].sort(([, tagA], [, tagB]) => tagA.order - tagB.order),\n );\n\n return {\n body,\n html,\n meta: sortedTags,\n containers,\n };\n }\n\n /**\n * Replace react attribute to valid DOM attribute\n */\n protected replaceAttribute(tagName: string, attribute: string): string {\n if (tagName === 'meta' && attribute.toLowerCase() === 'httpequiv') {\n return 'http-equiv';\n }\n\n return attribute;\n }\n\n /**\n * Create DOM element from React element\n */\n protected createDomElement(element: ReactElement): HTMLElement | undefined {\n if (this.isServer) {\n return;\n }\n\n const { type, props } = element;\n const domElement = document.createElement(type as string);\n\n this.applyDomElementAttributes(domElement, props as Record<string, string>);\n\n return domElement;\n }\n\n /**\n * Make element key by element props\n */\n protected buildKeyByProps(\n type: string,\n props: Record<string, any> = {},\n isSkipProps = false,\n ): string | undefined {\n let key = '';\n\n // try to build unique key by unique props\n for (const uniqueAttr of ['id', 'name', 'href', 'src']) {\n if (props[uniqueAttr]) {\n key = `[${uniqueAttr}='${props[uniqueAttr] as string}']`;\n\n break;\n }\n }\n\n // try to build by props\n if (!key && !isSkipProps) {\n key = Object.entries(props)\n .map(([k, v]) => {\n if (typeof v === 'string') {\n return `[${k}]`;\n }\n\n return false;\n })\n .filter(Boolean)\n .join('');\n }\n\n if (!key) {\n return undefined;\n }\n\n return `${type}${key}`;\n }\n\n /**\n * Get default tag key for not unique elements\n */\n protected getDefaultKey(type: string, containerId: string, index: number): string {\n return `${type}-${containerId}-${index}-not-unique`;\n }\n\n /**\n * Check if tag is not unique\n */\n protected isNotUniqueTag(key: string): boolean {\n return key.endsWith('-not-unique');\n }\n\n /**\n * Clone react element\n */\n protected cloneElement(element: ReactElement): {\n element: ReactElement;\n elementProps: Record<string, any>;\n } {\n const { type } = element;\n const props = { ...(element?.props ?? {}) } as Record<string, any>;\n\n // remove system attributes\n Object.values(this.reservedAttributes).forEach((attrName) => {\n if (props[attrName]) {\n delete props[attrName];\n }\n });\n\n // fix multiple nodes for title\n if (type === 'title' && Array.isArray(props.children)) {\n props.children = props.children.join('');\n }\n\n return {\n element: React.createElement(type, props),\n elementProps: props,\n };\n }\n\n /**\n * Push react elements to meta state\n */\n protected pushElements(\n elements: ReactNode,\n containerId: string,\n isReplace = true,\n status = TagStatus.init,\n ): void {\n Children.forEach(elements, (child, index) => {\n // skip unsupported elements\n if (!child || typeof child !== 'object' || !('type' in child) || !child.type) {\n return;\n }\n\n const { type } = child;\n const { element, elementProps } = this.cloneElement(child);\n const elementOrder = elementProps[this.reservedAttributes.order]\n ? Number(elementProps[this.reservedAttributes.order])\n : undefined;\n\n let order = elementOrder ?? this.tagsDefinitions[type as string]?.order ?? 1000;\n let key = this.tagsDefinitions[type as string]?.key ?? (type as string);\n\n switch (type) {\n case 'title':\n break;\n\n case 'meta':\n const { charSet, httpEquiv } = elementProps;\n\n if (charSet) {\n key = `meta[charset]`;\n } else if (httpEquiv) {\n key = `meta[httpEquiv]`;\n } else {\n key = this.buildKeyByProps(type, elementProps)!;\n }\n\n break;\n\n case 'html':\n case 'body':\n if (!isReplace && this.tags[type].has(key)) {\n return;\n }\n\n this.tags[type].set(containerId, Manager.cleanupElementProps(elementProps));\n\n return;\n\n case 'link':\n case 'script':\n case 'noscript':\n case 'style':\n default:\n key =\n this.buildKeyByProps(type as string, elementProps, true) ??\n this.getDefaultKey(type as string, containerId, index);\n break;\n }\n\n // skip replace existed meta tag (e.g. for push existed tags from parsed html, @see ServerManager)\n if (!isReplace && this.tags.meta.has(key)) {\n return;\n }\n\n // skip push already existed in head not unique tags\n if (this.isNotUniqueTag(key) && this.tags.meta.get(key)?.status === TagStatus.synced) {\n return;\n }\n\n // custom order\n if (this.tagsDefinitions[key]?.order) {\n order = this.tagsDefinitions[key]?.order;\n }\n\n this.tags.meta.set(key, {\n element: this.isServer ? element : undefined, // keep element only for server render\n domElement:\n /**\n * create DOM element only for client side\n * generate DOM element for root container inside @see this.analyzeClientHead\n */\n containerId === Manager.rootContainerId ? undefined : this.createDomElement(element),\n order,\n containerId,\n status,\n });\n });\n\n this.tags.containers.add(containerId);\n }\n\n /**\n * Get html or body props\n */\n public getRootTagProps(props: Manager['tags']['html']): Record<string, any> {\n if (!props.size) {\n return {};\n }\n\n return [...props.values()].reduce(\n (res, val) => ({\n ...res,\n ...val,\n }),\n {},\n );\n }\n\n /**\n * Apply props to dom element\n */\n protected applyDomElementAttributes(element: Element, props: Record<string, any> = {}): void {\n const tagName = element.tagName.toLowerCase();\n const reservedAttributes = Object.values(this.reservedAttributes);\n\n // apply attributes\n Object.entries(props).forEach(([name, value]) => {\n switch (name) {\n case 'children':\n element.innerHTML = value;\n\n return;\n\n case 'style':\n return Object.entries(value as Record<string, string>).forEach(\n ([styleName, styleValue]) => {\n element['style'][styleName] = styleValue;\n },\n );\n }\n\n if (reservedAttributes[name]) {\n return;\n }\n\n element.setAttribute(this.replaceAttribute(tagName, name), value as string);\n });\n }\n\n /**\n * Synchronize local meta tags with head meta tags\n */\n protected syncMeta(containerId?: string): void {\n const { meta, html, body } = this.getTags();\n\n // apply html, body props\n for (const { name, value } of [\n { name: 'html', value: html },\n { name: 'body', value: body },\n ]) {\n const tagProps = this.getRootTagProps(value);\n const domElement = document.querySelector(name);\n const existAttributes = domElement?.getAttributeNames() ?? [];\n\n // remove drained props\n existAttributes.forEach((attrName) => {\n if (tagProps[attrName]) {\n return;\n }\n\n domElement!.removeAttribute(attrName);\n });\n\n if (!Object.keys(tagProps).length || !domElement) {\n continue;\n }\n\n this.applyDomElementAttributes(domElement, tagProps);\n }\n\n if (!meta.size || this.isServer) {\n return;\n }\n\n const head = document.getElementsByTagName('head')?.[0];\n let prevElement: HTMLElement | ChildNode | null | undefined;\n\n meta.forEach((metaTag, key) => {\n const { status, domElement } = metaTag;\n\n if (\n status === TagStatus.synced ||\n !domElement ||\n (containerId && containerId !== metaTag.containerId)\n ) {\n prevElement = domElement;\n\n return;\n }\n\n // remove tags\n if (status === TagStatus.drain) {\n prevElement = domElement.previousSibling;\n domElement?.remove();\n meta.delete(key);\n\n return;\n }\n\n metaTag.status = TagStatus.synced;\n\n if (!this.isNotUniqueTag(key)) {\n const exist = document.querySelector(key);\n\n if (exist) {\n prevElement = domElement;\n exist.replaceWith(domElement);\n\n return;\n }\n }\n\n const beforeElement = prevElement && prevElement.nextSibling;\n\n if (beforeElement) {\n head.insertBefore(domElement, beforeElement);\n } else {\n head.append(domElement);\n }\n\n prevElement = domElement;\n });\n }\n\n /**\n * Push new meta tags\n */\n public pushTags(elements: ReactNode, containerId: string, isReplace = true): void {\n const isAdded = this.tags.containers.has(containerId);\n\n this.pushElements(\n elements,\n containerId,\n isReplace,\n isAdded ? TagStatus.synced : TagStatus.init,\n );\n\n // skip sync already synced tags\n if (this.isServer || isAdded) {\n return;\n }\n\n this.syncMeta();\n }\n\n /**\n * Remove meta tags\n */\n public removeTags(containerId: string): void {\n this.tags.meta.forEach((metaTag, key) => {\n if (metaTag.containerId !== containerId || metaTag.containerId === Manager.rootContainerId) {\n return;\n }\n\n // remove immediately not unique tags\n if (this.isNotUniqueTag(key)) {\n metaTag.domElement?.remove();\n this.tags.meta.delete(key);\n\n return;\n }\n\n metaTag.status = TagStatus.drain;\n });\n\n if (containerId === Manager.rootContainerId) {\n return;\n }\n\n this.tags.body.delete(containerId);\n this.tags.html.delete(containerId);\n this.tags.containers.delete(containerId);\n }\n\n /**\n * Initial analyze client head meta tags\n */\n public analyzeClientHead(): void {\n if (this.isServer) {\n return;\n }\n\n // parse default attributes for root tags\n for (const tagName of ['html', 'body']) {\n const htmlTag = document.getElementsByTagName(tagName)?.[0].cloneNode(false)?.[\n 'outerHTML'\n ] as string;\n\n this.pushElements(htmlParser(htmlTag), Manager.rootContainerId, false);\n }\n\n // parse default meta tags\n const head = document.getElementsByTagName('head')?.[0];\n const reactElements = htmlParser(head?.innerHTML ?? '');\n\n this.pushElements(reactElements, Manager.rootContainerId, false, TagStatus.synced);\n\n const meta = [...this.tags.meta.values()];\n\n // attach real dom node to virtual tags\n head.childNodes.forEach((node, i) => {\n const existedElem = meta[i];\n\n if (!existedElem) {\n return;\n }\n\n existedElem.domElement = node as HTMLElement;\n });\n }\n}\n\nexport default Manager;\n"],"names":["TagStatus","Manager","constructor","tags","arguments","length","undefined","_defineProperty","this","window","order","title","base","meta","link","script","noscript","style","html","Map","body","containers","Set","setTagsDefinitions","definitions","tagsDefinitions","static","props","children","_","dangerouslySetInnerHTML","__","restProps","getTags","entries","sort","_ref","_ref2","tagA","tagB","replaceAttribute","tagName","attribute","toLowerCase","createDomElement","element","isServer","type","domElement","document","createElement","applyDomElementAttributes","buildKeyByProps","isSkipProps","key","uniqueAttr","concat","Object","map","_ref3","k","v","filter","Boolean","join","getDefaultKey","containerId","index","isNotUniqueTag","endsWith","cloneElement","_element$props","values","reservedAttributes","forEach","attrName","Array","isArray","React","elementProps","pushElements","elements","isReplace","status","init","Children","child","_ref4","_this$tagsDefinitions","_this$tagsDefinitions2","_this$tagsDefinitions3","_this$buildKeyByProps","_this$tags$meta$get","_this$tagsDefinitions4","elementOrder","Number","charSet","httpEquiv","has","set","cleanupElementProps","get","synced","_this$tagsDefinitions5","rootContainerId","add","getRootTagProps","size","reduce","res","val","_ref5","name","value","innerHTML","_ref6","styleName","styleValue","setAttribute","syncMeta","_document$getElements","_domElement$getAttrib","tagProps","querySelector","getAttributeNames","removeAttribute","keys","head","getElementsByTagName","prevElement","metaTag","drain","previousSibling","remove","delete","exist","replaceWith","beforeElement","nextSibling","insertBefore","append","pushTags","isAdded","removeTags","_metaTag$domElement","analyzeClientHead","_document$getElements4","_head$innerHTML","_document$getElements2","_document$getElements3","htmlTag","cloneNode","htmlParser","reactElements","childNodes","node","i","existedElem"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"manager.js","sources":["../src/manager.ts"],"sourcesContent":["import htmlParser from 'html-react-parser';\nimport type { ReactElement, ReactNode } from 'react';\nimport React, { Children } from 'react';\n\nenum TagStatus {\n init = 'init',\n synced = 'synced',\n drain = 'drain',\n}\n\nexport interface IMetaManagerTags {\n html: Map<string, Record<string, any>>; // containerId => styles\n body: Map<string, Record<string, any>>; // containerId => styles\n meta: Map<\n string,\n {\n element?: ReactElement;\n domElement?: HTMLElement;\n order: number;\n containerId: string;\n status: TagStatus;\n }\n >;\n containers: Set<string>;\n}\n\nexport interface IMetaManagerTagsDefinitions {\n [type: string]: {\n key?: string;\n order: number;\n };\n}\n\n/**\n * Meta tags manager\n */\nclass Manager {\n /**\n * Root container id\n */\n public static rootContainerId = 'root';\n\n /**\n * Detect server side\n */\n public isServer = typeof window === 'undefined';\n\n /**\n * Meta tags state\n */\n protected tags: IMetaManagerTags;\n\n /**\n * Tags definitions\n */\n protected tagsDefinitions: IMetaManagerTagsDefinitions = {\n 'meta[charset]': {\n order: 10,\n },\n \"meta[name='viewport']\": {\n order: 20,\n },\n title: {\n order: 100,\n },\n base: {\n order: 110,\n },\n meta: {\n order: 200,\n },\n link: {\n order: 300,\n },\n script: {\n order: 400,\n },\n noscript: {\n order: 500,\n },\n style: {\n order: 600,\n },\n };\n\n /**\n * System tag attributes\n */\n protected reservedAttributes = {\n order: 'data-order',\n };\n\n /**\n * Scheduled synchronization\n */\n protected syncTimerId: null | NodeJS.Timeout = null;\n\n /**\n * @constructor\n */\n constructor(tags: Partial<Manager['tags']> = {}) {\n this.tags = {\n html: new Map(tags?.html),\n body: new Map(tags?.body),\n meta: new Map(tags?.meta),\n containers: new Set(tags?.containers),\n };\n }\n\n /**\n * Set tags definitions\n */\n public setTagsDefinitions(definitions: IMetaManagerTagsDefinitions): void {\n this.tagsDefinitions = { ...this.tagsDefinitions, ...definitions };\n }\n\n /**\n * Remove children, dangerouslySetInnerHTML etc.\n */\n public static cleanupElementProps(props: Record<string, any>): Record<string, any> {\n const { children: _, dangerouslySetInnerHTML: __, ...restProps } = props;\n\n return restProps;\n }\n\n /**\n * Get meta tags\n */\n public getTags(): IMetaManagerTags {\n const { meta, body, html, containers } = this.tags;\n const sortedTags = new Map(\n [...meta.entries()].sort(([, tagA], [, tagB]) => tagA.order - tagB.order),\n );\n\n return {\n body,\n html,\n meta: sortedTags,\n containers,\n };\n }\n\n /**\n * Replace react attribute to valid DOM attribute\n */\n protected replaceAttribute(tagName: string, attribute: string): string {\n if (tagName === 'meta' && attribute.toLowerCase() === 'httpequiv') {\n return 'http-equiv';\n }\n\n return attribute;\n }\n\n /**\n * Create DOM element from React element\n */\n protected createDomElement(element: ReactElement): HTMLElement | undefined {\n if (this.isServer) {\n return;\n }\n\n const { type, props } = element;\n const domElement = document.createElement(type as string);\n\n this.applyDomElementAttributes(domElement, props as Record<string, string>);\n\n return domElement;\n }\n\n /**\n * Make element key by element props\n */\n protected buildKeyByProps(\n type: string,\n props: Record<string, any> = {},\n isSkipProps = false,\n ): string | undefined {\n let key = '';\n\n // try to build unique key by unique props\n for (const uniqueAttr of ['id', 'name', 'href', 'src']) {\n if (props[uniqueAttr]) {\n key = `[${uniqueAttr}='${props[uniqueAttr] as string}']`;\n\n break;\n }\n }\n\n // try to build by props\n if (!key && !isSkipProps) {\n key = Object.entries(props)\n .map(([k, v]) => {\n if (typeof v === 'string') {\n return `[${k}]`;\n }\n\n return false;\n })\n .filter(Boolean)\n .join('');\n }\n\n if (!key) {\n return undefined;\n }\n\n return `${type}${key}`;\n }\n\n /**\n * Get default tag key for not unique elements\n */\n protected getDefaultKey(type: string, containerId: string, index: number): string {\n return `${type}-${containerId}-${index}-not-unique`;\n }\n\n /**\n * Check if tag is not unique\n */\n protected isNotUniqueTag(key: string): boolean {\n return key.endsWith('-not-unique');\n }\n\n /**\n * Clone react element\n */\n protected cloneElement(element: ReactElement): {\n element: ReactElement;\n elementProps: Record<string, any>;\n } {\n const { type } = element;\n const props = { ...(element?.props ?? {}) } as Record<string, any>;\n\n // remove system attributes\n Object.values(this.reservedAttributes).forEach((attrName) => {\n if (props[attrName]) {\n delete props[attrName];\n }\n });\n\n // fix multiple nodes for title\n if (type === 'title' && Array.isArray(props.children)) {\n props.children = props.children.join('');\n }\n\n return {\n element: React.createElement(type, props),\n elementProps: props,\n };\n }\n\n /**\n * Push react elements to meta state\n */\n protected pushElements(\n elements: ReactNode,\n containerId: string,\n isReplace = true,\n status = TagStatus.init,\n ): void {\n Children.forEach(elements, (child, index) => {\n // skip unsupported elements\n if (!child || typeof child !== 'object' || !('type' in child) || !child.type) {\n return;\n }\n\n const { type } = child;\n const { element, elementProps } = this.cloneElement(child);\n const elementOrder = elementProps[this.reservedAttributes.order]\n ? Number(elementProps[this.reservedAttributes.order])\n : undefined;\n\n let order = elementOrder ?? this.tagsDefinitions[type as string]?.order ?? 1000;\n let key = this.tagsDefinitions[type as string]?.key ?? (type as string);\n\n switch (type) {\n case 'title':\n break;\n\n case 'meta':\n const { charSet, httpEquiv } = elementProps;\n\n if (charSet) {\n key = `meta[charset]`;\n } else if (httpEquiv) {\n key = `meta[httpEquiv]`;\n } else {\n key = this.buildKeyByProps(type, elementProps)!;\n }\n\n break;\n\n case 'html':\n case 'body':\n if (!isReplace && this.tags[type].has(key)) {\n return;\n }\n\n this.tags[type].set(containerId, Manager.cleanupElementProps(elementProps));\n\n return;\n\n case 'link':\n case 'script':\n case 'noscript':\n case 'style':\n default:\n key =\n this.buildKeyByProps(type as string, elementProps, true) ??\n this.getDefaultKey(type as string, containerId, index);\n break;\n }\n\n // skip replace existed meta tag (e.g. for push existed tags from parsed html, @see ServerManager)\n if (!isReplace && this.tags.meta.has(key)) {\n return;\n }\n\n // skip push already existed in head not unique tags\n if (this.isNotUniqueTag(key) && this.tags.meta.get(key)?.status === TagStatus.synced) {\n return;\n }\n\n // custom order\n if (this.tagsDefinitions[key]?.order) {\n order = this.tagsDefinitions[key]?.order;\n }\n\n this.tags.meta.set(key, {\n element: this.isServer ? element : undefined, // keep element only for server render\n domElement:\n /**\n * create DOM element only for client side\n * generate DOM element for root container inside @see this.analyzeClientHead\n */\n containerId === Manager.rootContainerId ? undefined : this.createDomElement(element),\n order,\n containerId,\n status,\n });\n });\n\n this.tags.containers.add(containerId);\n }\n\n /**\n * Get html or body props\n */\n public getRootTagProps(props: Manager['tags']['html']): Record<string, any> {\n if (!props.size) {\n return {};\n }\n\n return [...props.values()].reduce(\n (res, val) => ({\n ...res,\n ...val,\n }),\n {},\n );\n }\n\n /**\n * Apply props to dom element\n */\n protected applyDomElementAttributes(element: Element, props: Record<string, any> = {}): void {\n const tagName = element.tagName.toLowerCase();\n const reservedAttributes = Object.values(this.reservedAttributes);\n\n // apply attributes\n Object.entries(props).forEach(([name, value]) => {\n switch (name) {\n case 'children':\n element.innerHTML = value;\n\n return;\n\n case 'style':\n return Object.entries(value as Record<string, string>).forEach(\n ([styleName, styleValue]) => {\n element['style'][styleName] = styleValue;\n },\n );\n }\n\n if (reservedAttributes[name]) {\n return;\n }\n\n element.setAttribute(this.replaceAttribute(tagName, name), value as string);\n });\n }\n\n /**\n * Synchronize local meta tags with head meta tags\n */\n protected syncMeta(containerId?: string): void {\n const { meta, html, body } = this.getTags();\n\n if (this.syncTimerId) {\n clearTimeout(this.syncTimerId);\n }\n\n // apply html, body props\n for (const { name, value } of [\n { name: 'html', value: html },\n { name: 'body', value: body },\n ]) {\n const tagProps = this.getRootTagProps(value);\n const domElement = document.querySelector(name);\n const existAttributes = domElement?.getAttributeNames() ?? [];\n\n // remove drained props\n existAttributes.forEach((attrName) => {\n if (tagProps[attrName]) {\n return;\n }\n\n domElement!.removeAttribute(attrName);\n });\n\n if (!Object.keys(tagProps).length || !domElement) {\n continue;\n }\n\n this.applyDomElementAttributes(domElement, tagProps);\n }\n\n if (!meta.size || this.isServer) {\n return;\n }\n\n const head = document.getElementsByTagName('head')?.[0];\n let prevElement: HTMLElement | ChildNode | null | undefined;\n\n meta.forEach((metaTag, key) => {\n const { status, domElement } = metaTag;\n\n if (\n status === TagStatus.synced ||\n !domElement ||\n (containerId && containerId !== metaTag.containerId)\n ) {\n prevElement = domElement;\n\n return;\n }\n\n // remove tags\n if (status === TagStatus.drain) {\n prevElement = domElement.previousSibling;\n domElement?.remove();\n meta.delete(key);\n\n return;\n }\n\n metaTag.status = TagStatus.synced;\n\n if (!this.isNotUniqueTag(key)) {\n const exist = document.querySelector(key);\n\n if (exist) {\n prevElement = domElement;\n exist.replaceWith(domElement);\n\n return;\n }\n }\n\n const beforeElement = prevElement && prevElement.nextSibling;\n\n if (beforeElement) {\n head.insertBefore(domElement, beforeElement);\n } else {\n head.append(domElement);\n }\n\n prevElement = domElement;\n });\n }\n\n /**\n * Push new meta tags\n */\n public pushTags(elements: ReactNode, containerId: string, isReplace = true): void {\n const isAdded = this.tags.containers.has(containerId);\n\n this.pushElements(\n elements,\n containerId,\n isReplace,\n isAdded ? TagStatus.synced : TagStatus.init,\n );\n\n // skip sync already synced tags\n if (this.isServer || isAdded) {\n return;\n }\n\n this.syncMeta();\n }\n\n /**\n * Remove meta tags\n */\n public removeTags(containerId: string): void {\n this.tags.meta.forEach((metaTag, key) => {\n if (metaTag.containerId !== containerId || metaTag.containerId === Manager.rootContainerId) {\n return;\n }\n\n // remove immediately not unique tags\n if (this.isNotUniqueTag(key)) {\n metaTag.domElement?.remove();\n this.tags.meta.delete(key);\n\n return;\n }\n\n metaTag.status = TagStatus.drain;\n });\n\n if (containerId === Manager.rootContainerId) {\n return;\n }\n\n this.tags.body.delete(containerId);\n this.tags.html.delete(containerId);\n this.tags.containers.delete(containerId);\n this.syncTimerId = setTimeout(() => this.syncMeta(), 500);\n }\n\n /**\n * Initial analyze client head meta tags\n */\n public analyzeClientHead(): void {\n if (this.isServer) {\n return;\n }\n\n // parse default attributes for root tags\n for (const tagName of ['html', 'body']) {\n const htmlTag = document.getElementsByTagName(tagName)?.[0].cloneNode(false)?.[\n 'outerHTML'\n ] as string;\n\n this.pushElements(htmlParser(htmlTag), Manager.rootContainerId, false);\n }\n\n // parse default meta tags\n const head = document.getElementsByTagName('head')?.[0];\n const reactElements = htmlParser(head?.innerHTML ?? '');\n\n this.pushElements(reactElements, Manager.rootContainerId, false, TagStatus.synced);\n\n const meta = [...this.tags.meta.values()];\n\n // attach real dom node to virtual tags\n head.childNodes.forEach((node, i) => {\n const existedElem = meta[i];\n\n if (!existedElem) {\n return;\n }\n\n existedElem.domElement = node as HTMLElement;\n });\n }\n}\n\nexport default Manager;\n"],"names":["TagStatus","Manager","constructor","tags","arguments","length","undefined","_defineProperty","this","window","order","title","base","meta","link","script","noscript","style","html","Map","body","containers","Set","setTagsDefinitions","definitions","tagsDefinitions","static","props","children","_","dangerouslySetInnerHTML","__","restProps","getTags","entries","sort","_ref","_ref2","tagA","tagB","replaceAttribute","tagName","attribute","toLowerCase","createDomElement","element","isServer","type","domElement","document","createElement","applyDomElementAttributes","buildKeyByProps","isSkipProps","key","uniqueAttr","concat","Object","map","_ref3","k","v","filter","Boolean","join","getDefaultKey","containerId","index","isNotUniqueTag","endsWith","cloneElement","_element$props","values","reservedAttributes","forEach","attrName","Array","isArray","React","elementProps","pushElements","elements","isReplace","status","init","Children","child","_ref4","_this$tagsDefinitions","_this$tagsDefinitions2","_this$tagsDefinitions3","_this$buildKeyByProps","_this$tags$meta$get","_this$tagsDefinitions4","elementOrder","Number","charSet","httpEquiv","has","set","cleanupElementProps","get","synced","_this$tagsDefinitions5","rootContainerId","add","getRootTagProps","size","reduce","res","val","_ref5","name","value","innerHTML","_ref6","styleName","styleValue","setAttribute","syncMeta","_document$getElements","syncTimerId","clearTimeout","_domElement$getAttrib","tagProps","querySelector","getAttributeNames","removeAttribute","keys","head","getElementsByTagName","prevElement","metaTag","drain","previousSibling","remove","delete","exist","replaceWith","beforeElement","nextSibling","insertBefore","append","pushTags","isAdded","removeTags","_metaTag$domElement","setTimeout","analyzeClientHead","_document$getElements4","_head$innerHTML","_document$getElements2","_document$getElements3","htmlTag","cloneNode","htmlParser","reactElements","childNodes","node","i","existedElem"],"mappings":"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"}
|