unhead 0.4.4 → 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
  }
@@ -390,22 +403,18 @@ const DeprecatedTagAttrPlugin = () => {
390
403
  });
391
404
  };
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 IsBrowser = typeof window !== "undefined";
407
+
408
+ const ProvideTagHashPlugin = () => {
400
409
  return defineHeadPlugin({
401
410
  hooks: {
402
411
  "tag:normalise": (ctx) => {
403
412
  const { tag, entry } = ctx;
404
- if (!HasElementTags.includes(tag.tag) || typeof tag._d === "undefined")
413
+ if (!HasElementTags.includes(tag.tag))
405
414
  return;
406
- tag._s = `data-h-${hashCode(tag._d)}`;
407
- if (entry._m === "server" || tag.key)
408
- tag.props[tag._s] = "";
415
+ const isBrowser = IsBrowser || getActiveHead()?.resolvedOptions?.document;
416
+ if (!isBrowser && entry._m === "server" && tag.key)
417
+ tag.props["data-h-key"] = tag._d;
409
418
  }
410
419
  }
411
420
  });
@@ -442,7 +451,7 @@ const EventHandlersPlugin = () => {
442
451
  };
443
452
  return defineHeadPlugin({
444
453
  hooks: {
445
- "ssr:beforeRender": function(ctx) {
454
+ "ssr:render": function(ctx) {
446
455
  ctx.tags = ctx.tags.map((tag) => {
447
456
  tag.props = stripEventHandlers(tag).props;
448
457
  return tag;
@@ -460,7 +469,7 @@ const EventHandlersPlugin = () => {
460
469
  if (!ctx.tag._eventHandlers || !$el)
461
470
  return;
462
471
  Object.entries(ctx.tag._eventHandlers).forEach(([k, value]) => {
463
- const sdeKey = `${ctx.tag._s || ctx.tag._p}:${k}`;
472
+ const sdeKey = `${ctx.tag._d || ctx.tag._p}:${k}`;
464
473
  const eventName = k.slice(2).toLowerCase();
465
474
  const handler = value;
466
475
  $el?.addEventListener(eventName, handler);
@@ -478,8 +487,6 @@ function asArray(value) {
478
487
  return Array.isArray(value) ? value : [value];
479
488
  }
480
489
 
481
- const IsBrowser = typeof window !== "undefined";
482
-
483
490
  exports.activeHead = void 0;
484
491
  const setActiveHead = (head) => exports.activeHead = head;
485
492
  const getActiveHead = () => exports.activeHead;
@@ -586,8 +593,9 @@ function createHead(options = {}) {
586
593
  DedupesTagsPlugin(),
587
594
  SortTagsPlugin(),
588
595
  TitleTemplatePlugin(),
589
- PatchDomOnEntryUpdatesPlugin({ document: options?.document, delayFn: options?.domDelayFn }),
590
596
  EventHandlersPlugin(),
597
+ ProvideTagHashPlugin(),
598
+ PatchDomOnEntryUpdatesPlugin({ document: options?.document, delayFn: options?.domDelayFn }),
591
599
  ...options?.plugins || []
592
600
  ];
593
601
  options.plugins.forEach((p) => p.hooks && hooks.addHooks(p.hooks));
@@ -667,15 +675,14 @@ function defineHeadPlugin(plugin) {
667
675
  exports.DedupesTagsPlugin = DedupesTagsPlugin;
668
676
  exports.DeprecatedTagAttrPlugin = DeprecatedTagAttrPlugin;
669
677
  exports.EventHandlersPlugin = EventHandlersPlugin;
670
- exports.HydrateStateFromSSRPlugin = HydrateStateFromSSRPlugin;
671
678
  exports.PatchDomOnEntryUpdatesPlugin = PatchDomOnEntryUpdatesPlugin;
679
+ exports.ProvideTagHashPlugin = ProvideTagHashPlugin;
672
680
  exports.SortTagsPlugin = SortTagsPlugin;
673
681
  exports.TitleTemplatePlugin = TitleTemplatePlugin;
674
682
  exports.asArray = asArray;
675
683
  exports.createHead = createHead;
676
684
  exports.defineHeadPlugin = defineHeadPlugin;
677
685
  exports.getActiveHead = getActiveHead;
678
- exports.hashCode = hashCode;
679
686
  exports.normaliseEntryTags = normaliseEntryTags;
680
687
  exports.setActiveHead = setActiveHead;
681
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
  }
@@ -388,22 +401,18 @@ const DeprecatedTagAttrPlugin = () => {
388
401
  });
389
402
  };
390
403
 
391
- function hashCode(s) {
392
- let h = 9;
393
- for (let i = 0; i < s.length; )
394
- h = Math.imul(h ^ s.charCodeAt(i++), 9 ** 9);
395
- return ((h ^ h >>> 9) + 65536).toString(16).substring(1, 7).toLowerCase();
396
- }
397
- const HydrateStateFromSSRPlugin = () => {
404
+ const IsBrowser = typeof window !== "undefined";
405
+
406
+ const ProvideTagHashPlugin = () => {
398
407
  return defineHeadPlugin({
399
408
  hooks: {
400
409
  "tag:normalise": (ctx) => {
401
410
  const { tag, entry } = ctx;
402
- if (!HasElementTags.includes(tag.tag) || typeof tag._d === "undefined")
411
+ if (!HasElementTags.includes(tag.tag))
403
412
  return;
404
- tag._s = `data-h-${hashCode(tag._d)}`;
405
- if (entry._m === "server" || tag.key)
406
- tag.props[tag._s] = "";
413
+ const isBrowser = IsBrowser || getActiveHead()?.resolvedOptions?.document;
414
+ if (!isBrowser && entry._m === "server" && tag.key)
415
+ tag.props["data-h-key"] = tag._d;
407
416
  }
408
417
  }
409
418
  });
@@ -440,7 +449,7 @@ const EventHandlersPlugin = () => {
440
449
  };
441
450
  return defineHeadPlugin({
442
451
  hooks: {
443
- "ssr:beforeRender": function(ctx) {
452
+ "ssr:render": function(ctx) {
444
453
  ctx.tags = ctx.tags.map((tag) => {
445
454
  tag.props = stripEventHandlers(tag).props;
446
455
  return tag;
@@ -458,7 +467,7 @@ const EventHandlersPlugin = () => {
458
467
  if (!ctx.tag._eventHandlers || !$el)
459
468
  return;
460
469
  Object.entries(ctx.tag._eventHandlers).forEach(([k, value]) => {
461
- const sdeKey = `${ctx.tag._s || ctx.tag._p}:${k}`;
470
+ const sdeKey = `${ctx.tag._d || ctx.tag._p}:${k}`;
462
471
  const eventName = k.slice(2).toLowerCase();
463
472
  const handler = value;
464
473
  $el?.addEventListener(eventName, handler);
@@ -476,8 +485,6 @@ function asArray(value) {
476
485
  return Array.isArray(value) ? value : [value];
477
486
  }
478
487
 
479
- const IsBrowser = typeof window !== "undefined";
480
-
481
488
  let activeHead;
482
489
  const setActiveHead = (head) => activeHead = head;
483
490
  const getActiveHead = () => activeHead;
@@ -584,8 +591,9 @@ function createHead(options = {}) {
584
591
  DedupesTagsPlugin(),
585
592
  SortTagsPlugin(),
586
593
  TitleTemplatePlugin(),
587
- PatchDomOnEntryUpdatesPlugin({ document: options?.document, delayFn: options?.domDelayFn }),
588
594
  EventHandlersPlugin(),
595
+ ProvideTagHashPlugin(),
596
+ PatchDomOnEntryUpdatesPlugin({ document: options?.document, delayFn: options?.domDelayFn }),
589
597
  ...options?.plugins || []
590
598
  ];
591
599
  options.plugins.forEach((p) => p.hooks && hooks.addHooks(p.hooks));
@@ -662,4 +670,4 @@ function defineHeadPlugin(plugin) {
662
670
  return plugin;
663
671
  }
664
672
 
665
- 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.4",
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.4",
34
- "@unhead/schema": "0.4.4",
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 .",