unhead 0.4.1 → 0.4.2

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
@@ -301,8 +301,8 @@ const DedupesTagsPlugin = (options) => {
301
301
  },
302
302
  "tags:resolve": function(ctx) {
303
303
  const deduping = {};
304
- ctx.tags.forEach((tag, i) => {
305
- let dedupeKey = tag._d || tag._p || i;
304
+ ctx.tags.forEach((tag) => {
305
+ let dedupeKey = tag._d || tag._p;
306
306
  const dupedTag = deduping[dedupeKey];
307
307
  if (dupedTag) {
308
308
  let strategy = tag?.tagDuplicateStrategy;
@@ -323,13 +323,12 @@ const DedupesTagsPlugin = (options) => {
323
323
  };
324
324
  return;
325
325
  } else if (tag._e === dupedTag._e) {
326
- dedupeKey = `${dedupeKey}:entry(${tag._e}:${tag._p})`;
327
- if (dupedTag._s) {
326
+ dedupeKey = tag._d = `${dedupeKey}:${tag._p}`;
327
+ if (dupedTag._s && typeof dupedTag.props[dupedTag._s] !== "undefined") {
328
328
  delete tag.props[dupedTag._s];
329
- tag._s = dupedTag._s + tag._p;
329
+ tag._s = `${dupedTag._s}${tag._p}`;
330
330
  tag.props[tag._s] = "";
331
331
  }
332
- tag._d = dedupeKey;
333
332
  }
334
333
  if (Object.keys(tag.props).length === 0 && !tag.children) {
335
334
  delete deduping[dedupeKey];
@@ -397,18 +396,16 @@ function hashCode(s) {
397
396
  h = Math.imul(h ^ s.charCodeAt(i++), 9 ** 9);
398
397
  return ((h ^ h >>> 9) + 65536).toString(16).substring(1, 7).toLowerCase();
399
398
  }
400
-
401
- const HydratesStatePlugin = () => {
399
+ const HydrateStateFromSSRPlugin = () => {
402
400
  return defineHeadPlugin({
403
401
  hooks: {
404
402
  "tag:normalise": (ctx) => {
405
403
  const { tag, entry } = ctx;
406
- if (!HasElementTags.includes(tag.tag))
407
- return;
408
- if (typeof tag._d === "undefined" && entry._m === "server")
404
+ if (!HasElementTags.includes(tag.tag) || typeof tag._d === "undefined")
409
405
  return;
410
- tag._s = `data-h-${hashCode(tag._d || JSON.stringify({ tag: tag.tag, props: tag.props, children: tag.children }))}`;
411
- tag.props[tag._s] = "";
406
+ tag._s = `data-h-${hashCode(tag._d)}`;
407
+ if (entry._m === "server")
408
+ tag.props[tag._s] = "";
412
409
  }
413
410
  }
414
411
  });
@@ -481,16 +478,17 @@ function asArray(value) {
481
478
  return Array.isArray(value) ? value : [value];
482
479
  }
483
480
 
484
- const IsClient = typeof window !== "undefined";
481
+ const IsBrowser = typeof window !== "undefined";
485
482
 
486
483
  exports.activeHead = void 0;
487
484
  const setActiveHead = (head) => exports.activeHead = head;
488
485
  const getActiveHead = () => exports.activeHead;
489
486
 
490
487
  function useHead(input, options = {}) {
491
- if (options.mode === "server" && IsClient || options.mode === "client" && !IsClient)
492
- return;
493
488
  const head = getActiveHead();
489
+ const isBrowser = IsBrowser || head.resolvedOptions?.document;
490
+ if (options.mode === "server" && isBrowser || options.mode === "client" && !isBrowser)
491
+ return;
494
492
  head.push(input, options);
495
493
  }
496
494
  const useTagTitle = (title) => {
@@ -564,12 +562,14 @@ const useServerTitleTemplate = (titleTemplate) => {
564
562
  useServerHead({ titleTemplate });
565
563
  };
566
564
 
565
+ const TagEntityBits = 10;
566
+
567
567
  function normaliseEntryTags(e) {
568
568
  return Object.entries(e.input).filter(([k, v]) => typeof v !== "undefined" && ValidHeadTags.includes(k)).map(
569
569
  ([k, value]) => asArray(value).map((props) => asArray(normaliseTag(k, props)))
570
570
  ).flat(3).map((t, i) => {
571
571
  t._e = e._i;
572
- t._p = (e._i << 8) + i++;
572
+ t._p = (e._i << TagEntityBits) + i;
573
573
  return t;
574
574
  });
575
575
  }
@@ -577,22 +577,23 @@ function normaliseEntryTags(e) {
577
577
  function createHead(options = {}) {
578
578
  let entries = [];
579
579
  let _sde = {};
580
- let entryId = 0;
580
+ let _eid = 0;
581
581
  const hooks = hookable.createHooks();
582
582
  if (options?.hooks)
583
583
  hooks.addHooks(options.hooks);
584
- const plugins = [
584
+ options.plugins = [
585
585
  DeprecatedTagAttrPlugin(),
586
586
  DedupesTagsPlugin(),
587
587
  SortTagsPlugin(),
588
588
  TitleTemplatePlugin(),
589
589
  PatchDomOnEntryUpdatesPlugin({ document: options?.document, delayFn: options?.domDelayFn }),
590
- EventHandlersPlugin()
590
+ EventHandlersPlugin(),
591
+ ...options?.plugins || []
591
592
  ];
592
- plugins.push(...options.plugins || []);
593
- plugins.forEach((plugin) => hooks.addHooks(plugin.hooks || {}));
594
- const triggerUpdate = () => hooks.callHook("entries:updated", head);
593
+ options.plugins.forEach((p) => p.hooks && hooks.addHooks(p.hooks));
594
+ const triggerUpdateHook = () => hooks.callHook("entries:updated", head);
595
595
  const head = {
596
+ resolvedOptions: options,
596
597
  _popSideEffectQueue() {
597
598
  const sde = { ..._sde };
598
599
  _sde = {};
@@ -605,23 +606,24 @@ function createHead(options = {}) {
605
606
  return hooks;
606
607
  },
607
608
  push(input, options2) {
608
- const _i = entryId++;
609
- entries.push({
610
- _i,
609
+ const activeEntry = {
610
+ _i: _eid++,
611
611
  input,
612
- _sde: {},
613
- ...options2
614
- });
615
- triggerUpdate();
612
+ _sde: {}
613
+ };
614
+ if (options2?.mode)
615
+ activeEntry._m = options2?.mode;
616
+ entries.push(activeEntry);
617
+ triggerUpdateHook();
616
618
  const queueSideEffects = (e) => {
617
619
  _sde = { ..._sde, ...e._sde || {} };
618
620
  e._sde = {};
619
- triggerUpdate();
621
+ triggerUpdateHook();
620
622
  };
621
623
  return {
622
624
  dispose() {
623
625
  entries = entries.filter((e) => {
624
- if (e._i !== _i)
626
+ if (e._i !== activeEntry._i)
625
627
  return true;
626
628
  queueSideEffects(e);
627
629
  return false;
@@ -629,9 +631,10 @@ function createHead(options = {}) {
629
631
  },
630
632
  patch(input2) {
631
633
  entries = entries.map((e) => {
632
- if (e._i === _i) {
634
+ if (e._i === activeEntry._i) {
633
635
  queueSideEffects(e);
634
- e.input = e._i === _i ? input2 : e.input;
636
+ activeEntry.input = e.input = input2;
637
+ activeEntry._i = e._i = _eid++;
635
638
  }
636
639
  return e;
637
640
  });
@@ -664,7 +667,7 @@ function defineHeadPlugin(plugin) {
664
667
  exports.DedupesTagsPlugin = DedupesTagsPlugin;
665
668
  exports.DeprecatedTagAttrPlugin = DeprecatedTagAttrPlugin;
666
669
  exports.EventHandlersPlugin = EventHandlersPlugin;
667
- exports.HydratesStatePlugin = HydratesStatePlugin;
670
+ exports.HydrateStateFromSSRPlugin = HydrateStateFromSSRPlugin;
668
671
  exports.PatchDomOnEntryUpdatesPlugin = PatchDomOnEntryUpdatesPlugin;
669
672
  exports.SortTagsPlugin = SortTagsPlugin;
670
673
  exports.TitleTemplatePlugin = TitleTemplatePlugin;
@@ -672,6 +675,7 @@ exports.asArray = asArray;
672
675
  exports.createHead = createHead;
673
676
  exports.defineHeadPlugin = defineHeadPlugin;
674
677
  exports.getActiveHead = getActiveHead;
678
+ exports.hashCode = hashCode;
675
679
  exports.normaliseEntryTags = normaliseEntryTags;
676
680
  exports.setActiveHead = setActiveHead;
677
681
  exports.useBodyAttrs = useBodyAttrs;
package/dist/index.d.ts CHANGED
@@ -13,7 +13,8 @@ declare const TitleTemplatePlugin: () => _unhead_schema.HeadPlugin;
13
13
 
14
14
  declare const DeprecatedTagAttrPlugin: () => _unhead_schema.HeadPlugin;
15
15
 
16
- declare const HydratesStatePlugin: () => _unhead_schema.HeadPlugin;
16
+ declare function hashCode(s: string): string;
17
+ declare const HydrateStateFromSSRPlugin: () => _unhead_schema.HeadPlugin;
17
18
 
18
19
  interface TriggerDomPatchingOnUpdatesPluginOptions extends RenderDomHeadOptions {
19
20
  delayFn?: (fn: () => void) => void;
@@ -66,4 +67,4 @@ declare function defineHeadPlugin(plugin: HeadPlugin): HeadPlugin;
66
67
 
67
68
  declare function normaliseEntryTags<T extends {} = Head>(e: HeadEntry<T>): HeadTag[];
68
69
 
69
- export { Arrayable, DedupesTagsPlugin, DedupesTagsPluginOptions, DeprecatedTagAttrPlugin, EventHandlersPlugin, HydratesStatePlugin, PatchDomOnEntryUpdatesPlugin, 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 };
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 };
package/dist/index.mjs CHANGED
@@ -299,8 +299,8 @@ const DedupesTagsPlugin = (options) => {
299
299
  },
300
300
  "tags:resolve": function(ctx) {
301
301
  const deduping = {};
302
- ctx.tags.forEach((tag, i) => {
303
- let dedupeKey = tag._d || tag._p || i;
302
+ ctx.tags.forEach((tag) => {
303
+ let dedupeKey = tag._d || tag._p;
304
304
  const dupedTag = deduping[dedupeKey];
305
305
  if (dupedTag) {
306
306
  let strategy = tag?.tagDuplicateStrategy;
@@ -321,13 +321,12 @@ const DedupesTagsPlugin = (options) => {
321
321
  };
322
322
  return;
323
323
  } else if (tag._e === dupedTag._e) {
324
- dedupeKey = `${dedupeKey}:entry(${tag._e}:${tag._p})`;
325
- if (dupedTag._s) {
324
+ dedupeKey = tag._d = `${dedupeKey}:${tag._p}`;
325
+ if (dupedTag._s && typeof dupedTag.props[dupedTag._s] !== "undefined") {
326
326
  delete tag.props[dupedTag._s];
327
- tag._s = dupedTag._s + tag._p;
327
+ tag._s = `${dupedTag._s}${tag._p}`;
328
328
  tag.props[tag._s] = "";
329
329
  }
330
- tag._d = dedupeKey;
331
330
  }
332
331
  if (Object.keys(tag.props).length === 0 && !tag.children) {
333
332
  delete deduping[dedupeKey];
@@ -395,18 +394,16 @@ function hashCode(s) {
395
394
  h = Math.imul(h ^ s.charCodeAt(i++), 9 ** 9);
396
395
  return ((h ^ h >>> 9) + 65536).toString(16).substring(1, 7).toLowerCase();
397
396
  }
398
-
399
- const HydratesStatePlugin = () => {
397
+ const HydrateStateFromSSRPlugin = () => {
400
398
  return defineHeadPlugin({
401
399
  hooks: {
402
400
  "tag:normalise": (ctx) => {
403
401
  const { tag, entry } = ctx;
404
- if (!HasElementTags.includes(tag.tag))
405
- return;
406
- if (typeof tag._d === "undefined" && entry._m === "server")
402
+ if (!HasElementTags.includes(tag.tag) || typeof tag._d === "undefined")
407
403
  return;
408
- tag._s = `data-h-${hashCode(tag._d || JSON.stringify({ tag: tag.tag, props: tag.props, children: tag.children }))}`;
409
- tag.props[tag._s] = "";
404
+ tag._s = `data-h-${hashCode(tag._d)}`;
405
+ if (entry._m === "server")
406
+ tag.props[tag._s] = "";
410
407
  }
411
408
  }
412
409
  });
@@ -479,16 +476,17 @@ function asArray(value) {
479
476
  return Array.isArray(value) ? value : [value];
480
477
  }
481
478
 
482
- const IsClient = typeof window !== "undefined";
479
+ const IsBrowser = typeof window !== "undefined";
483
480
 
484
481
  let activeHead;
485
482
  const setActiveHead = (head) => activeHead = head;
486
483
  const getActiveHead = () => activeHead;
487
484
 
488
485
  function useHead(input, options = {}) {
489
- if (options.mode === "server" && IsClient || options.mode === "client" && !IsClient)
490
- return;
491
486
  const head = getActiveHead();
487
+ const isBrowser = IsBrowser || head.resolvedOptions?.document;
488
+ if (options.mode === "server" && isBrowser || options.mode === "client" && !isBrowser)
489
+ return;
492
490
  head.push(input, options);
493
491
  }
494
492
  const useTagTitle = (title) => {
@@ -562,12 +560,14 @@ const useServerTitleTemplate = (titleTemplate) => {
562
560
  useServerHead({ titleTemplate });
563
561
  };
564
562
 
563
+ const TagEntityBits = 10;
564
+
565
565
  function normaliseEntryTags(e) {
566
566
  return Object.entries(e.input).filter(([k, v]) => typeof v !== "undefined" && ValidHeadTags.includes(k)).map(
567
567
  ([k, value]) => asArray(value).map((props) => asArray(normaliseTag(k, props)))
568
568
  ).flat(3).map((t, i) => {
569
569
  t._e = e._i;
570
- t._p = (e._i << 8) + i++;
570
+ t._p = (e._i << TagEntityBits) + i;
571
571
  return t;
572
572
  });
573
573
  }
@@ -575,22 +575,23 @@ function normaliseEntryTags(e) {
575
575
  function createHead(options = {}) {
576
576
  let entries = [];
577
577
  let _sde = {};
578
- let entryId = 0;
578
+ let _eid = 0;
579
579
  const hooks = createHooks();
580
580
  if (options?.hooks)
581
581
  hooks.addHooks(options.hooks);
582
- const plugins = [
582
+ options.plugins = [
583
583
  DeprecatedTagAttrPlugin(),
584
584
  DedupesTagsPlugin(),
585
585
  SortTagsPlugin(),
586
586
  TitleTemplatePlugin(),
587
587
  PatchDomOnEntryUpdatesPlugin({ document: options?.document, delayFn: options?.domDelayFn }),
588
- EventHandlersPlugin()
588
+ EventHandlersPlugin(),
589
+ ...options?.plugins || []
589
590
  ];
590
- plugins.push(...options.plugins || []);
591
- plugins.forEach((plugin) => hooks.addHooks(plugin.hooks || {}));
592
- const triggerUpdate = () => hooks.callHook("entries:updated", head);
591
+ options.plugins.forEach((p) => p.hooks && hooks.addHooks(p.hooks));
592
+ const triggerUpdateHook = () => hooks.callHook("entries:updated", head);
593
593
  const head = {
594
+ resolvedOptions: options,
594
595
  _popSideEffectQueue() {
595
596
  const sde = { ..._sde };
596
597
  _sde = {};
@@ -603,23 +604,24 @@ function createHead(options = {}) {
603
604
  return hooks;
604
605
  },
605
606
  push(input, options2) {
606
- const _i = entryId++;
607
- entries.push({
608
- _i,
607
+ const activeEntry = {
608
+ _i: _eid++,
609
609
  input,
610
- _sde: {},
611
- ...options2
612
- });
613
- triggerUpdate();
610
+ _sde: {}
611
+ };
612
+ if (options2?.mode)
613
+ activeEntry._m = options2?.mode;
614
+ entries.push(activeEntry);
615
+ triggerUpdateHook();
614
616
  const queueSideEffects = (e) => {
615
617
  _sde = { ..._sde, ...e._sde || {} };
616
618
  e._sde = {};
617
- triggerUpdate();
619
+ triggerUpdateHook();
618
620
  };
619
621
  return {
620
622
  dispose() {
621
623
  entries = entries.filter((e) => {
622
- if (e._i !== _i)
624
+ if (e._i !== activeEntry._i)
623
625
  return true;
624
626
  queueSideEffects(e);
625
627
  return false;
@@ -627,9 +629,10 @@ function createHead(options = {}) {
627
629
  },
628
630
  patch(input2) {
629
631
  entries = entries.map((e) => {
630
- if (e._i === _i) {
632
+ if (e._i === activeEntry._i) {
631
633
  queueSideEffects(e);
632
- e.input = e._i === _i ? input2 : e.input;
634
+ activeEntry.input = e.input = input2;
635
+ activeEntry._i = e._i = _eid++;
633
636
  }
634
637
  return e;
635
638
  });
@@ -659,4 +662,4 @@ function defineHeadPlugin(plugin) {
659
662
  return plugin;
660
663
  }
661
664
 
662
- export { DedupesTagsPlugin, DeprecatedTagAttrPlugin, EventHandlersPlugin, HydratesStatePlugin, PatchDomOnEntryUpdatesPlugin, 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 };
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 };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "unhead",
3
3
  "type": "module",
4
- "version": "0.4.1",
4
+ "version": "0.4.2",
5
5
  "packageManager": "pnpm@7.14.0",
6
6
  "author": "Harlan Wilton <harlan@harlanzw.com>",
7
7
  "license": "MIT",
@@ -30,8 +30,8 @@
30
30
  "dist"
31
31
  ],
32
32
  "dependencies": {
33
- "@unhead/dom": "0.4.1",
34
- "@unhead/schema": "0.4.1",
33
+ "@unhead/dom": "0.4.2",
34
+ "@unhead/schema": "0.4.2",
35
35
  "hookable": "^5.4.1"
36
36
  },
37
37
  "devDependencies": {