hartmut-co-uk / zhead

Fully-typed utilities for defining, validating and building your document <head>. Powers unhead

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

zhead

NPM version NPM Downloads GitHub stars

Typed utilities for defining, validating and building best-practice document <head>'s. Powering unhead.


Status: Pre-release
Please report any issues πŸ›
Made possible by my Sponsor Program πŸ’–
Follow me @harlan_zw 🐦 β€’ Join Discord for help

Types

Functions

  • πŸ’Ž Validation and schema parsing provided by Zod
  • ✨ Bunch of utils: normaliseTag, sortTags, tagDedupeKey, titleTemplate, inferSeoMetaTags, ensureCriticalTags
  • πŸ§™ Resolve flat meta tags and back again unpackMeta packMeta
  • ✍️ Output to HTML generateHtml
  • 🌳 Composable, tree-shakable and tiny (< 1kb, see export-size-report)

Packages

Schema

Typescript base schema for document <head>. Only ships types for easy access to type augmentation.

export interface Head<E extends MergeHead = MergeHead> {
  title?: string
  titleTemplate?: string | ((title?: string) => string)
  base?: Partial<Merge<E['base'], Base>>
  link?: (Link & UnsafeKeys & Default<E['link']>)[]
  meta?: (Meta & UnsafeKeys & Default<E['meta']>)[]
  style?: (Style & UnsafeKeys & Default<E['style']>)[]
  script?: (Script & UnsafeKeys & Default<E['script']>)[]
  noscript?: (Noscript & UnsafeKeys & Default<E['noscript']>)[]
  htmlAttrs?: (HtmlAttributes & UnsafeKeys & Default<E['htmlAttrs']>)
  bodyAttrs?: (BodyAttributes & UnsafeKeys & Default<E['bodyAttrs']>)
}

@zhead/schema

Vue Schema

Typescript schema for document <head> with Vue reactivity.

export interface ReactiveHead<E extends MergeHead = MergeHead> {
  title?: MaybeRef<Head<E>['title']>
  titleTemplate?: Head<E>['titleTemplate'] | Ref<string>
  base?: Head<E>['base'] | MaybeRef<MaybeRefObject<Head<E>['base']>>
  link?: Head<E>['link'] | ReffableArrayEntries<Head<E>['link']>
  meta?: Head<E>['meta'] | ReffableArrayEntries<Head<E>['meta']>
  style?: Head<E>['style'] | ReffableArrayEntries<Head<E>['style']>
  script?: Head<E>['script'] | ReffableArrayEntries<Head<E>['script']>
  noscript?: Head<E>['noscript'] | ReffableArrayEntries<Head<E>['noscript']>
  htmlAttrs?: MaybeRef<MaybeRefObject<Head<E>['htmlAttrs']>>
  bodyAttrs?: MaybeRef<MaybeRefObject<Head<E>['bodyAttrs']>>
}

@zhead/schema-vue

Validation and parsing

Zod schema for validating and parsing head tags.

@zhead/validation

Core

See below

Core Installation

npm install --save-dev zhead

# Using yarn
yarn add --dev zhead

Core API

defineHead

Use this decorator for a simple fully-typed head schema.

import { defineHead } from 'zhead'

const head = defineHead({
  title: 'My Page',
})

// {
//    title: 'My Page',
// }

unpackMeta

Define your meta tags in a simple object with full type-safety.

import { defineHead, resolveMetaFlat } from 'zhead'

const meta = unpackMeta({
  contentSecurityPolicy: {
    contentSrc: 'none'
  },
  viewport: {
    width: 'device-width',
    initialScale: 1,
    userScalable: 'yes',
  }
})

//  [
//    { 'http-equiv': 'content-security-policy', content: 'content-src none' },
//    { 'name': 'viewport', content: 'width=device-width, user-scalable=yes, initial-scale=1' }
//  ]

packMeta

Turn array meta tags into a flat packed object.

import { defineHead, resolveMetaFlat } from 'zhead'

const meta = packMeta([
  {
    'content': 'default-src \'self\' https://example.com; content-src none',
    'http-equiv': 'content-security-policy',
  },
  {
    name: 'description',
    content: 'desc',
  },
  {
    content: '1234567890',
    property: 'fb:app_id',
  },
])

// {
//   "description": "desc",
//   "fbAppId": "1234567890",
//   "contentSecurityPolicy": "default-src 'self' https://example.com; content-src none"
// }

resolveSeoHead

Generate a minimal SEO head with maximum SEO.

Internally this function uses the withDefaults and inferSocialShare utilities.

  • Adds utf-8 charset
  • Sets default best practice viewport
  • Infers social share tags from title and description
  • Sets twitter card to summary_large_image
  • Sets robots best practice
import { resolveSeoHead, resolveMetaFlat } from 'zhead'

const head = resolveSeoHead({
  title: 'Learn about zHead - zHead',
  description: 'Describing the basic usage of zHead.',
})

// {
//   "title": "My Title",
//   "meta": [
//     {
//       "content": "Some description",
//       "name": "description",
//     },
//     {
//       "charset": "utf-8",
//     },
//     {
//       "content": "initial-scale=1, width=device-width",
//       "name": "viewport",
//     },
//     {
//       "content": "My Title",
//       "property": "og:title",
//     },
//     {
//       "content": "Some description",
//       "property": "og:description",
//     },
//     {
//       "content": "max-snippet:-1, max-image-preview:large, max-video-preview:-1",
//       "name": "robots",
//     },
//   ],
// }

Generate API

generateHtml

import { generateHtml } from 'zhead'

const html = generateHtml({
  title: 'test',
  script: [
    { src: 'https://example.com/script.js' },
  ],
  meta: [
    { name: 'description', content: 'test' },
  ]
})

// <title>test</title>
// <meta content="test" name="description">
// <script src="https://example.com/script.js"></script>

generateTags

import { generateTags } from 'zhead'

const tags = generateTags({
  title: 'test',
  script: [
    { src: 'https://example.com/script.js' },
  ],
  meta: [
    { name: 'description', content: 'test' },
  ]
})

// [
//   {
//     "props": {
//       "children": "test",
//     },
//     "tag": "title",
//   },
//   {
//     "props": {
//       "content": "test",
//       "name": "description",
//     },
//     "tag": "meta",
//   },
//   {
//     "props": {
//       "src": "https://example.com/script.js",
//     },
//     "tag": "script",
//   },
// ]

Sponsors

License

MIT License Β© 2022-PRESENT Harlan Wilton

About

Fully-typed utilities for defining, validating and building your document <head>. Powers unhead


Languages

Language:TypeScript 100.0%