unhead 0.4.5 → 0.4.6

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/index.cjs CHANGED
@@ -229,9 +229,26 @@ const sortTags = (aTag, bTag) => {
229
229
  return tagWeight(aTag) - tagWeight(bTag);
230
230
  };
231
231
 
232
+ const UniqueTags = ["base", "title", "titleTemplate", "bodyAttrs", "htmlAttrs"];
233
+ const ArrayMetaProperties = [
234
+ "og:image",
235
+ "og:video",
236
+ "og:audio",
237
+ "og:locale:alternate",
238
+ "video:actor",
239
+ "video:director",
240
+ "video:writer",
241
+ "video:tag",
242
+ "article:author",
243
+ "article:tag",
244
+ "book:tag",
245
+ "book:author",
246
+ "music:album",
247
+ "music:musician"
248
+ ];
232
249
  function tagDedupeKey(tag) {
233
250
  const { props, tag: tagName } = tag;
234
- if (["base", "title", "titleTemplate", "bodyAttrs", "htmlAttrs"].includes(tagName))
251
+ if (UniqueTags.includes(tagName))
235
252
  return tagName;
236
253
  if (tagName === "link" && props.rel === "canonical")
237
254
  return "canonical";
@@ -241,7 +258,7 @@ function tagDedupeKey(tag) {
241
258
  if (tagName === "meta")
242
259
  name.push(...["name", "property", "http-equiv"]);
243
260
  for (const n of name) {
244
- if (typeof props[n] !== "undefined") {
261
+ if (typeof props[n] !== "undefined" && !ArrayMetaProperties.findIndex((p) => !props[n].startsWith(p))) {
245
262
  return `${tagName}:${n}:${props[n]}`;
246
263
  }
247
264
  }
@@ -324,13 +341,9 @@ const DedupesTagsPlugin = (options) => {
324
341
  return;
325
342
  } else if (tag._e === dupedTag._e) {
326
343
  dedupeKey = tag._d = `${dedupeKey}:${tag._p}`;
327
- if (dupedTag._s && typeof dupedTag.props[dupedTag._s] !== "undefined") {
328
- delete tag.props[dupedTag._s];
329
- tag._s = `${dupedTag._s}${tag._p}`;
330
- tag.props[tag._s] = "";
331
- }
332
344
  }
333
- if (Object.keys(tag.props).length === 0 && !tag.children) {
345
+ const propCount = Object.keys(tag.props).length;
346
+ if ((propCount === 0 || propCount === 1 && typeof tag.props["data-h-key"] !== "undefined") && !tag.children) {
334
347
  delete deduping[dedupeKey];
335
348
  return;
336
349
  }
@@ -392,23 +405,16 @@ const DeprecatedTagAttrPlugin = () => {
392
405
 
393
406
  const IsBrowser = typeof window !== "undefined";
394
407
 
395
- function hashCode(s) {
396
- let h = 9;
397
- for (let i = 0; i < s.length; )
398
- h = Math.imul(h ^ s.charCodeAt(i++), 9 ** 9);
399
- return ((h ^ h >>> 9) + 65536).toString(16).substring(1, 7).toLowerCase();
400
- }
401
- const HydrateStateFromSSRPlugin = () => {
408
+ const ProvideTagHashPlugin = () => {
402
409
  return defineHeadPlugin({
403
410
  hooks: {
404
411
  "tag:normalise": (ctx) => {
405
412
  const { tag, entry } = ctx;
406
- if (!HasElementTags.includes(tag.tag) || typeof tag._d === "undefined")
413
+ if (!HasElementTags.includes(tag.tag))
407
414
  return;
408
- tag._s = `data-h-${hashCode(tag._d)}`;
409
415
  const isBrowser = IsBrowser || getActiveHead()?.resolvedOptions?.document;
410
- if (!isBrowser && (entry._m === "server" || tag.key))
411
- tag.props[tag._s] = "";
416
+ if (!isBrowser && entry._m === "server" && tag.key)
417
+ tag.props["data-h-key"] = tag._d;
412
418
  }
413
419
  }
414
420
  });
@@ -445,7 +451,7 @@ const EventHandlersPlugin = () => {
445
451
  };
446
452
  return defineHeadPlugin({
447
453
  hooks: {
448
- "ssr:beforeRender": function(ctx) {
454
+ "ssr:render": function(ctx) {
449
455
  ctx.tags = ctx.tags.map((tag) => {
450
456
  tag.props = stripEventHandlers(tag).props;
451
457
  return tag;
@@ -463,7 +469,7 @@ const EventHandlersPlugin = () => {
463
469
  if (!ctx.tag._eventHandlers || !$el)
464
470
  return;
465
471
  Object.entries(ctx.tag._eventHandlers).forEach(([k, value]) => {
466
- const sdeKey = `${ctx.tag._s || ctx.tag._p}:${k}`;
472
+ const sdeKey = `${ctx.tag._d || ctx.tag._p}:${k}`;
467
473
  const eventName = k.slice(2).toLowerCase();
468
474
  const handler = value;
469
475
  $el?.addEventListener(eventName, handler);
@@ -587,8 +593,9 @@ function createHead(options = {}) {
587
593
  DedupesTagsPlugin(),
588
594
  SortTagsPlugin(),
589
595
  TitleTemplatePlugin(),
590
- PatchDomOnEntryUpdatesPlugin({ document: options?.document, delayFn: options?.domDelayFn }),
591
596
  EventHandlersPlugin(),
597
+ ProvideTagHashPlugin(),
598
+ PatchDomOnEntryUpdatesPlugin({ document: options?.document, delayFn: options?.domDelayFn }),
592
599
  ...options?.plugins || []
593
600
  ];
594
601
  options.plugins.forEach((p) => p.hooks && hooks.addHooks(p.hooks));
@@ -668,15 +675,14 @@ function defineHeadPlugin(plugin) {
668
675
  exports.DedupesTagsPlugin = DedupesTagsPlugin;
669
676
  exports.DeprecatedTagAttrPlugin = DeprecatedTagAttrPlugin;
670
677
  exports.EventHandlersPlugin = EventHandlersPlugin;
671
- exports.HydrateStateFromSSRPlugin = HydrateStateFromSSRPlugin;
672
678
  exports.PatchDomOnEntryUpdatesPlugin = PatchDomOnEntryUpdatesPlugin;
679
+ exports.ProvideTagHashPlugin = ProvideTagHashPlugin;
673
680
  exports.SortTagsPlugin = SortTagsPlugin;
674
681
  exports.TitleTemplatePlugin = TitleTemplatePlugin;
675
682
  exports.asArray = asArray;
676
683
  exports.createHead = createHead;
677
684
  exports.defineHeadPlugin = defineHeadPlugin;
678
685
  exports.getActiveHead = getActiveHead;
679
- exports.hashCode = hashCode;
680
686
  exports.normaliseEntryTags = normaliseEntryTags;
681
687
  exports.setActiveHead = setActiveHead;
682
688
  exports.useBodyAttrs = useBodyAttrs;
package/dist/index.d.ts CHANGED
@@ -13,8 +13,7 @@ declare const TitleTemplatePlugin: () => _unhead_schema.HeadPlugin;
13
13
 
14
14
  declare const DeprecatedTagAttrPlugin: () => _unhead_schema.HeadPlugin;
15
15
 
16
- declare function hashCode(s: string): string;
17
- declare const HydrateStateFromSSRPlugin: () => _unhead_schema.HeadPlugin;
16
+ declare const ProvideTagHashPlugin: () => _unhead_schema.HeadPlugin;
18
17
 
19
18
  interface TriggerDomPatchingOnUpdatesPluginOptions extends RenderDomHeadOptions {
20
19
  delayFn?: (fn: () => void) => void;
@@ -67,4 +66,4 @@ declare function defineHeadPlugin(plugin: HeadPlugin): HeadPlugin;
67
66
 
68
67
  declare function normaliseEntryTags<T extends {} = Head>(e: HeadEntry<T>): HeadTag[];
69
68
 
70
- export { Arrayable, DedupesTagsPlugin, DedupesTagsPluginOptions, DeprecatedTagAttrPlugin, EventHandlersPlugin, HydrateStateFromSSRPlugin, PatchDomOnEntryUpdatesPlugin, SortTagsPlugin, TitleTemplatePlugin, activeHead, asArray, createHead, defineHeadPlugin, getActiveHead, hashCode, normaliseEntryTags, setActiveHead, useBodyAttrs, useHead, useHtmlAttrs, useServerBodyAttrs, useServerHead, useServerHtmlAttrs, useServerTagBase, useServerTagLink, useServerTagMeta, useServerTagMetaFlat, useServerTagNoscript, useServerTagScript, useServerTagStyle, useServerTagTitle, useServerTitleTemplate, useTagBase, useTagLink, useTagMeta, useTagMetaFlat, useTagNoscript, useTagScript, useTagStyle, useTagTitle, useTitleTemplate };
69
+ export { Arrayable, DedupesTagsPlugin, DedupesTagsPluginOptions, DeprecatedTagAttrPlugin, EventHandlersPlugin, PatchDomOnEntryUpdatesPlugin, ProvideTagHashPlugin, SortTagsPlugin, TitleTemplatePlugin, activeHead, asArray, createHead, defineHeadPlugin, getActiveHead, normaliseEntryTags, setActiveHead, useBodyAttrs, useHead, useHtmlAttrs, useServerBodyAttrs, useServerHead, useServerHtmlAttrs, useServerTagBase, useServerTagLink, useServerTagMeta, useServerTagMetaFlat, useServerTagNoscript, useServerTagScript, useServerTagStyle, useServerTagTitle, useServerTitleTemplate, useTagBase, useTagLink, useTagMeta, useTagMetaFlat, useTagNoscript, useTagScript, useTagStyle, useTagTitle, useTitleTemplate };
package/dist/index.mjs CHANGED
@@ -227,9 +227,26 @@ const sortTags = (aTag, bTag) => {
227
227
  return tagWeight(aTag) - tagWeight(bTag);
228
228
  };
229
229
 
230
+ const UniqueTags = ["base", "title", "titleTemplate", "bodyAttrs", "htmlAttrs"];
231
+ const ArrayMetaProperties = [
232
+ "og:image",
233
+ "og:video",
234
+ "og:audio",
235
+ "og:locale:alternate",
236
+ "video:actor",
237
+ "video:director",
238
+ "video:writer",
239
+ "video:tag",
240
+ "article:author",
241
+ "article:tag",
242
+ "book:tag",
243
+ "book:author",
244
+ "music:album",
245
+ "music:musician"
246
+ ];
230
247
  function tagDedupeKey(tag) {
231
248
  const { props, tag: tagName } = tag;
232
- if (["base", "title", "titleTemplate", "bodyAttrs", "htmlAttrs"].includes(tagName))
249
+ if (UniqueTags.includes(tagName))
233
250
  return tagName;
234
251
  if (tagName === "link" && props.rel === "canonical")
235
252
  return "canonical";
@@ -239,7 +256,7 @@ function tagDedupeKey(tag) {
239
256
  if (tagName === "meta")
240
257
  name.push(...["name", "property", "http-equiv"]);
241
258
  for (const n of name) {
242
- if (typeof props[n] !== "undefined") {
259
+ if (typeof props[n] !== "undefined" && !ArrayMetaProperties.findIndex((p) => !props[n].startsWith(p))) {
243
260
  return `${tagName}:${n}:${props[n]}`;
244
261
  }
245
262
  }
@@ -322,13 +339,9 @@ const DedupesTagsPlugin = (options) => {
322
339
  return;
323
340
  } else if (tag._e === dupedTag._e) {
324
341
  dedupeKey = tag._d = `${dedupeKey}:${tag._p}`;
325
- if (dupedTag._s && typeof dupedTag.props[dupedTag._s] !== "undefined") {
326
- delete tag.props[dupedTag._s];
327
- tag._s = `${dupedTag._s}${tag._p}`;
328
- tag.props[tag._s] = "";
329
- }
330
342
  }
331
- if (Object.keys(tag.props).length === 0 && !tag.children) {
343
+ const propCount = Object.keys(tag.props).length;
344
+ if ((propCount === 0 || propCount === 1 && typeof tag.props["data-h-key"] !== "undefined") && !tag.children) {
332
345
  delete deduping[dedupeKey];
333
346
  return;
334
347
  }
@@ -390,23 +403,16 @@ const DeprecatedTagAttrPlugin = () => {
390
403
 
391
404
  const IsBrowser = typeof window !== "undefined";
392
405
 
393
- function hashCode(s) {
394
- let h = 9;
395
- for (let i = 0; i < s.length; )
396
- h = Math.imul(h ^ s.charCodeAt(i++), 9 ** 9);
397
- return ((h ^ h >>> 9) + 65536).toString(16).substring(1, 7).toLowerCase();
398
- }
399
- const HydrateStateFromSSRPlugin = () => {
406
+ const ProvideTagHashPlugin = () => {
400
407
  return defineHeadPlugin({
401
408
  hooks: {
402
409
  "tag:normalise": (ctx) => {
403
410
  const { tag, entry } = ctx;
404
- if (!HasElementTags.includes(tag.tag) || typeof tag._d === "undefined")
411
+ if (!HasElementTags.includes(tag.tag))
405
412
  return;
406
- tag._s = `data-h-${hashCode(tag._d)}`;
407
413
  const isBrowser = IsBrowser || getActiveHead()?.resolvedOptions?.document;
408
- if (!isBrowser && (entry._m === "server" || tag.key))
409
- tag.props[tag._s] = "";
414
+ if (!isBrowser && entry._m === "server" && tag.key)
415
+ tag.props["data-h-key"] = tag._d;
410
416
  }
411
417
  }
412
418
  });
@@ -443,7 +449,7 @@ const EventHandlersPlugin = () => {
443
449
  };
444
450
  return defineHeadPlugin({
445
451
  hooks: {
446
- "ssr:beforeRender": function(ctx) {
452
+ "ssr:render": function(ctx) {
447
453
  ctx.tags = ctx.tags.map((tag) => {
448
454
  tag.props = stripEventHandlers(tag).props;
449
455
  return tag;
@@ -461,7 +467,7 @@ const EventHandlersPlugin = () => {
461
467
  if (!ctx.tag._eventHandlers || !$el)
462
468
  return;
463
469
  Object.entries(ctx.tag._eventHandlers).forEach(([k, value]) => {
464
- const sdeKey = `${ctx.tag._s || ctx.tag._p}:${k}`;
470
+ const sdeKey = `${ctx.tag._d || ctx.tag._p}:${k}`;
465
471
  const eventName = k.slice(2).toLowerCase();
466
472
  const handler = value;
467
473
  $el?.addEventListener(eventName, handler);
@@ -585,8 +591,9 @@ function createHead(options = {}) {
585
591
  DedupesTagsPlugin(),
586
592
  SortTagsPlugin(),
587
593
  TitleTemplatePlugin(),
588
- PatchDomOnEntryUpdatesPlugin({ document: options?.document, delayFn: options?.domDelayFn }),
589
594
  EventHandlersPlugin(),
595
+ ProvideTagHashPlugin(),
596
+ PatchDomOnEntryUpdatesPlugin({ document: options?.document, delayFn: options?.domDelayFn }),
590
597
  ...options?.plugins || []
591
598
  ];
592
599
  options.plugins.forEach((p) => p.hooks && hooks.addHooks(p.hooks));
@@ -663,4 +670,4 @@ function defineHeadPlugin(plugin) {
663
670
  return plugin;
664
671
  }
665
672
 
666
- export { DedupesTagsPlugin, DeprecatedTagAttrPlugin, EventHandlersPlugin, HydrateStateFromSSRPlugin, PatchDomOnEntryUpdatesPlugin, SortTagsPlugin, TitleTemplatePlugin, activeHead, asArray, createHead, defineHeadPlugin, getActiveHead, hashCode, normaliseEntryTags, setActiveHead, useBodyAttrs, useHead, useHtmlAttrs, useServerBodyAttrs, useServerHead, useServerHtmlAttrs, useServerTagBase, useServerTagLink, useServerTagMeta, useServerTagMetaFlat, useServerTagNoscript, useServerTagScript, useServerTagStyle, useServerTagTitle, useServerTitleTemplate, useTagBase, useTagLink, useTagMeta, useTagMetaFlat, useTagNoscript, useTagScript, useTagStyle, useTagTitle, useTitleTemplate };
673
+ export { DedupesTagsPlugin, DeprecatedTagAttrPlugin, EventHandlersPlugin, PatchDomOnEntryUpdatesPlugin, ProvideTagHashPlugin, SortTagsPlugin, TitleTemplatePlugin, activeHead, asArray, createHead, defineHeadPlugin, getActiveHead, normaliseEntryTags, setActiveHead, useBodyAttrs, useHead, useHtmlAttrs, useServerBodyAttrs, useServerHead, useServerHtmlAttrs, useServerTagBase, useServerTagLink, useServerTagMeta, useServerTagMetaFlat, useServerTagNoscript, useServerTagScript, useServerTagStyle, useServerTagTitle, useServerTitleTemplate, useTagBase, useTagLink, useTagMeta, useTagMetaFlat, useTagNoscript, useTagScript, useTagStyle, useTagTitle, useTitleTemplate };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "unhead",
3
3
  "type": "module",
4
- "version": "0.4.5",
4
+ "version": "0.4.6",
5
5
  "packageManager": "pnpm@7.14.0",
6
6
  "author": "Harlan Wilton <harlan@harlanzw.com>",
7
7
  "license": "MIT",
@@ -30,12 +30,12 @@
30
30
  "dist"
31
31
  ],
32
32
  "dependencies": {
33
- "@unhead/dom": "0.4.5",
34
- "@unhead/schema": "0.4.5",
33
+ "@unhead/dom": "0.4.6",
34
+ "@unhead/schema": "0.4.6",
35
35
  "hookable": "^5.4.1"
36
36
  },
37
37
  "devDependencies": {
38
- "zhead": "1.0.0-beta.11"
38
+ "zhead": "1.0.0-beta.12"
39
39
  },
40
40
  "scripts": {
41
41
  "build": "unbuild .",