unhead

repository·main·Indexed 22 days ago

https://github.com/unjs/unhead

A high-performance document head and template manager for modern reactive SSR JavaScript frameworks. Unhead enables management of SEO, meta tags, and scripts with support for streaming SSR and Vite integration. The ecosystem includes specialized packages such as @unhead/angular for Angular applications, @unhead/bundler for build-time optimizations, @unhead/cli for auditing and migration, and @unhead/eslint-plugin for source-level linting.

Tokens
195.9K
Snippets
574
Records
930
Agent score
79%

What's inside unhead

  1. Overview of @unhead/angular

    main
    @unhead/angular provides full-stack <head> management for Angular applications. It is optimized for Angular, supports Server-Side Rendering (SSR), and integrates with Angular's dependency injection system. It allows for reactive management of titles, meta tags, and other head elements using Angular Signals.
  2. Overview of Unhead features

    main

    Unhead is a document head and template manager designed to improve SEO, performance, and developer experience in reactive SSR JavaScript frameworks.

    Key features include:

    • Streaming SSR: Head tags are pushed to the DOM as suspense boundaries resolve.
    • Unified Vite plugin + DevTools: Provides tree-shaking, validation, and source tracing.
    • useHead(): Handles deduping, sorting, tag merging, and type narrowing.
    • useSeoMeta(): Provides flat SEO meta tags with compile-time transforms.
    • useScript(): A powerful and performant API for script loading.
    • Optimized Performance: Tiny footprint (4.4kb gz), tree-shaken, and utilizes Capo.js for tag sorting.
    • Framework Support: Works with Vue, React, Solid, Svelte, and Angular. It is used by Nuxt.
  3. Key features of Unhead

    main

    Unhead provides several specialized capabilities for managing document metadata:

    • Lazy DOM patching: Uses a small DOM diffing engine to ensure only changed tags are updated in the DOM.
    • Typed API: Provides TypeScript support with inline MDN documentation for tag and attribute types.
    • Flat SEO metadata: Allows managing over 100 meta tags without complex nested objects via useSeoMeta().
    • Schema.org support: Enables generating typed structured data using useSchemaOrg().
    • Script API: Provides proxied APIs, triggers, and resource hints for loading third-party scripts via useScript().
    • SSR and CSR support: Renders tags on the server and seamlessly adopts/updates them on the client.
  4. What is Unhead and what does it manage?

    main

    Unhead is a universal head manager designed for JavaScript applications to manage document metadata across both Server-Side Rendering (SSR) and Client-Side Rendering (CSR) environments.

    It manages:

    • Tags within the <head> element.
    • Attributes on the <html> and <body> elements (e.g., htmlAttrs, bodyAttrs).
    • Specific tag positions like bodyOpen and bodyClose to allow rendering content outside the main app entry point.

    Unhead is designed to be framework-agnostic, providing a core API that can be used with Vue, React, Svelte, Solid, Angular, or vanilla TypeScript.

  5. Understand the three layers of Unhead validation

    main

    Unhead validation is organized into three layers to provide different feedback loops:

    1. Source-level lint (audit / migrate): The fastest feedback loop. Runs on the AST. Catches typos, deprecated props, and structural issues (e.g., missing @ on Twitter handles). Best used in your editor via @unhead/eslint-plugin or in CI.
    2. HTML lint (validate-html / validate-url): Runs the ValidatePlugin over rendered HTML. Catches issues that depend on the resolved tag list, such as og:image dimensions, canonical mismatches, or charset position.
    3. Runtime ValidatePlugin: Runs live in your application during development, providing real-time warnings.
  6. Understand the scope of @unhead/eslint-plugin rules

    main

    The ESLint rules work by walking source-level calls into the following unhead APIs:

    • useHead
    • useHeadSafe
    • useServerHead
    • useServerHeadSafe
    • useSeoMeta
    • useServerSeoMeta
    • defineLink / defineScript (tag helpers)

    Rules automatically descend into tag arrays inside meta, link, script, noscript, and style, as well as object literals inside htmlAttrs and bodyAttrs.

    Note: Because rules are limited to what is expressible in the AST, they cannot perform cross-tag or rendered-output checks. For checks like canonical-og-url-mismatch, meta-beyond-1mb, charset-not-early, or too-many-preloads, you must use the runtime ValidatePlugin or the @unhead/cli commands unhead validate-url or unhead validate-html.

  7. Compare `useSeoMeta` and `useHead`

    main

    useSeoMeta()

    • Purpose: Specifically designed for SEO metadata.
    • API Style: Provides a flat, typed object for SEO fields.
    • Abstraction: Automatically handles name vs property attributes and converts camelCase keys to meta tags.

    useHead()

    • Purpose: General head management.
    • API Style: Accepts all supported head tags (scripts, styles, links, etc.) and entry options.
    • Flexibility: Use this when you need to manage more than just meta tags.
  8. Choose between Effect-based or Imperative patching in Angular

    main

    When updating head tags in Angular, you have two patterns depending on your state management:

    1. Track Signals in an Effect (Recommended): Use this when multiple code paths or components might update a signal. The effect() ensures the head is always in sync with the current signal value.

    2. Patch Imperatively: Use this when a specific method already owns the state change logic. This is useful for performance or simplicity if you don't need the overhead of an effect.

    Comparison:

    • Use Effects when: Several code paths update the signal.
    • Use Imperative when: Every state change goes through one specific method.
    // Pattern 1: Effect-based (Recommended)
    constructor() {
      effect(() => {
        this.head.patch({
          meta: [{ name: 'description', content: this.description() }]
        })
      })
    }
    
    // Pattern 2: Imperative
    setTitle(title: string) {
      this.title.set(title)
      this.head.patch({ title })
    }
  9. How Alias Sorting interacts with weight boundaries

    main

    Aliases adjust the registration order after Unhead has calculated each tag's weight. They do not recalculate the weight of the aliasing tag during the current resolution.

    • Use Aliases: When ordering tags that already share the same weight (e.g., two ordinary scripts or two stylesheets).
    • Use Numeric/Named Priorities: When a tag must move to a different weight group entirely.
  10. How JSON scripts are handled in useHeadSafe()

    main

    Executable scripts are rejected in safe mode. A <script> tag is only kept if it has textContent and its type ends in json (e.g., application/json or application/ld+json).

    When a JSON script is kept, the JSON is parsed or serialized again, and prototype-related keys are removed to prevent injection. Note that innerHTML is never allowed in safe mode.

    useHeadSafe({
      script: [{
        type: 'application/json',
        textContent: { theme: 'dark' },
      }],
    })