micromorph

repository·main·Indexed 18 days ago

https://github.com/natemoo-re/micromorph

A tiny library for diffing live DOM nodes, designed to efficiently synchronize DOM nodes or entire documents. It provides tools to transform Multi-Page Applications (MPAs) into Single-Page Applications (SPAs) via the /nav and /spa entrypoints. The library includes a diff and patch API to compute minimal changes between objects or DOM nodes and apply those updates to reach a target state.

Tokens
1.7K
Snippets
9
Records
9
Agent score
62%

What's inside micromorph

  1. Convert an MPA to an SPA using the /nav entrypoint

    main

    The micromorph/nav entrypoint allows you to turn a Multi-Page Application (MPA) into a Single-Page Application (SPA). It automatically intercepts navigation and re-renders only the content that has changed. This entrypoint relies on the browser's Navigation API.

    import listen from 'micromorph/nav';
    
    listen();
  2. Convert an MPA to an SPA using the /spa entrypoint

    main

    For browsers that do not support the Navigation API, use the micromorph/spa entrypoint to achieve SPA-like behavior. Like the /nav version, it converts your MPA into an SPA by only re-rendering changed content.

    import listen from 'micromorph/spa';
    
    listen();
  3. Update the current document using DOMParser

    main

    You can update the entire active document to match a new document (for example, one parsed from an HTML string) using diff(). Micromorph is designed to handle full document diffing while avoiding Flash of Unstyled Content (FOUC).

    import diff from 'micromorph';
    const p = new DOMParser();
    
    const newDoc = p.parseFromString(`<h1>Hello world!</h1>`, 'text/html');
    
    diff(document, newDoc);
  4. Update one DOM node to match another with diff()

    main

    Use the diff(fromNode, toNode) function to efficiently synchronize two DOM nodes. Micromorph calculates the differences and only applies the necessary changes to fromNode so that it matches toNode.

    import diff from 'micromorph';
    
    diff(fromNode, toNode);
  5. Apply DOM updates with patch()

    main

    The patch function is used to apply incremental updates to the DOM based on a patch object. It supports several action types to create, remove, replace, or update nodes and their attributes.

    Parameters:

    • parent: The parent Node of the element being patched.
    • PATCH: An object describing the change. It must contain a type property.
    • child (optional): The specific Node to be patched if the operation is not targeting the parent directly.

    Supported Action Types:

    • ACTION_CREATE: Appends a new node (provided in PATCH.node) to the parent.
    • ACTION_REMOVE: Removes the target element from the parent.
    • ACTION_REPLACE: Replaces the target element with a new node (from PATCH.node). If PATCH.value is a string, it updates the nodeValue of the element instead.
    • ACTION_UPDATE: Performs a complex update on an element. It applies attribute changes (from PATCH.attributes) and recursively calls patch for each child in PATCH.children.
    import { patch } from './patch';
    import { ACTION_CREATE, ACTION_UPDATE } from './consts';
    
    // Example: Creating a new element
    const createPatch = {
      type: ACTION_CREATE,
      node: document.createElement('div')
    };
    await patch(document.body, createPatch);
    
    // Example: Updating an existing element's attributes and children
    const updatePatch = {
      type: ACTION_UPDATE,
      attributes: [{ type: 'SET_ATTR', name: 'class', value: 'container' }],
      children: [
        { type: 'CREATE', node: document.createTextNode('Hello World') }
      ]
    };
    await patch(existingElement, updatePatch);
  6. Use the micromorph diff and patch API

    main

    The micromorph package provides a way to compute the difference between two objects (diff) and apply that difference to an object to transform it into the target state (patch). This is useful for efficient object updates and state synchronization.

    • diff(original, target): Computes the minimal set of changes required to transform original into target.
    • patch(original, delta): Applies a delta (produced by diff) to an original object to produce the target object.
    • default: The default export provides the core functionality.
    import { diff, patch } from 'micromorph';
    
    const original = { a: 1, b: { c: 2 } };
    const target = { a: 1, b: { c: 3 }, d: 4 };
    
    // Compute the difference
    const delta = diff(original, target);
    
    // Apply the difference to get the target
    const patched = patch(original, delta);
    
    console.log(patched); // { a: 1, b: { c: 3 }, d: 4 }
  7. Compare DOM nodes by Name, Type, or Value

    main

    Micromorph provides exported comparison functions to identify differences between DOM nodes based on specific attributes. These are useful when determining if a node has changed during a morphing operation.

    Available comparison constants:

    • name: Compares the nodeName of two nodes.
    • type: Compares the nodeType of two nodes.
    • value: Compares the nodeValue of two nodes.
    import { name, type, value } from './compare';
    
    // Example usage (conceptual):
    // const isSameName = name(nodeA, nodeB);
    // const isSameType = type(nodeA, nodeB);
    // const isSameValue = value(nodeA, nodeB);
  8. Reference the available Node Types

    main

    Micromorph uses integer constants to identify the type of node being processed. These constants are used to distinguish between elements, text, comments, and the document root.

    export const NODE_TYPE_ELEMENT = 1;
    export const NODE_TYPE_TEXT = 3;
    export const NODE_TYPE_COMMENT = 8;
    export const NODE_TYPE_DOCUMENT = 9;
  9. Reference the available Diff Actions

    main

    When performing a diff, micromorph identifies changes using specific action constants. These represent the type of mutation required to transform the source into the target.

    export const ACTION_CREATE = 0;
    export const ACTION_REMOVE = 1;
    export const ACTION_REPLACE = 2;
    export const ACTION_UPDATE = 3;
    export const ACTION_SET_ATTR = 4;
    export const ACTION_REMOVE_ATTR = 5;