diffHTML
v1.0.0-beta.29
An easy-to-use Virtual DOM built for the web!
diffHTML
v1.0.0-beta.29An easy-to-use Virtual DOM built for the web!
Core API
This documentation covers the core public API. All methods and internals work in the browser and directly in Node.js with or without jsdom .
Terminology:
VTree: The internal VDOM structure. They are JavaScript objects that represent a DOM node. They store information such as the tagName, what the childNodes are, and more. A reference to a VTree can get you access to the DOM node it represents. They are used throughout the codebase to simplify and abstract the internals away from the DOM, in favor of one that is virtual, hence the V.
An added bonus to this is that diffHTML can work seamlessly in Node.js without a DOM abstraction such as jsdom.
Transaction: An object that represents a render. One is produced every time you call innerHTML, outerHTML, or toString. You don't need to worry about it unless you're trying to deeply understand the library.
innerHTML (mount, input, options)
Compares and updates the contents of mount
with the input
. Creates a
Transaction, invokes
middleware
, compares old and new markup, and patches the DOM.
Arguments
Name | Description |
---|---|
mount | DOM Node or VTree to sync or patch the childNodes of. |
input | New markup to replace into mount. |
options |
Config options
, inner is always true |
Examples
import { innerHTML } from 'diffhtml';
innerHTML(document.body, `
<h1>Hello world!</h1>
`);
outerHTML (mount, input, options)
Same as
innerHTML
except compares the input
directly to the
mount
, instead of the childNodes
.
Replaces the contents of a DOM node with the passed in markup, only updates what has changed. Additionally updates the attributes of the parent. If the element you're modifying has a parent, you may also change the element type, but this can sometimes result in unexpected behavior.
Arguments
Name | Description |
---|---|
mount | DOM Node or VTree to sync or patch. |
input | New markup to replace into mount. |
options |
Config options
, inner is always false |
Examples
import { outerHTML } from 'diffhtml';
outerHTML(document.body, `
<body>Hello world</body>
`);
toString (input, options)
Takes any valid input and returns a serialized string of XML/HTML markup. This
helps you create static markup from complex renders to a simple VTree
.
All middleware run during this, so features like components and logging work.
Arguments
Name | Description |
---|---|
input | New markup to replace into mount. |
options |
Config options
, inner and executeScripts have no effect |
Examples
import { toString } from 'diffhtml';
toString('<body>Hello world</body>');
// <body>Hello world</body>
html (markup)
A
tagged
template
function that
parses string markup
and creates VTree
under-the-hood. Can also be used like a normal function, where you pass markup
as the first argument, and values as param2
, param3
, ...
. You are able to
"interpolate" or mix dynamic values with the HTML string content. This is
useful when passing event handlers, objects to DOM elements, passing properties
to components, and more.
When you pass a single element and provide newlines and whitespace before and after it, like the examples below, they will be automatically trimmed out of the final tree. If you provide multiple elements, the whitespace will become part of the tree.
Arguments
The two required inputs are a reference element and new element to compare. Although "element" is used, the actual input can be of various input types all representing an element (or many elements).
Examples
A simple example of its usage along with interpolation.
const vTree = html`
<body>
<center style=${{ fontSize: '11px' }}>Hello world</center>
</body>
`;
Will basically convert to:
createTree('body', null, [
createTree('center', { style: { fontSize: '11px' } }, ['Hello world']),
]);
To see how to run this example yourself see the Examples section below.
use (middlewareFunction or middlewareObject)
This function is used to hook plugins into your render pipeline. These plugins are referred to as middleware. They are meant for advanced use cases such as observing the render flow, modifying attributes or elements, and more.
Middleware can be enabled and disabled via code or the browser DevTools.
Arguments
Name | Description |
---|---|
middlewareFunction | Use this when you want total control over the task flow. Return inner functions to delve deeper into the flow. Any of the middleware object properties may be attached the function and used together. |
middlewareObject | Use this when you don't care about the transaction start/stop, and want a cleaner way to monitor the VTree lifecycle.
|
Examples
Logging the start of a render transaction
function someTask(transaction) {
console.log('Start of render transaction:', transaction);
}
use(someTask);
Logging the end of a render transaction
function someTask(transaction) {
console.log('Start of render transaction:', transaction);
return () => {
console.log('End of render transaction scheduled');
// Will fire once the transaction has fully ended.
transaction.onceEnded(() => {
console.log('End of render transaction completed');
});
};
}
use(someTask);
createTree (nodeName, attributes, ...childNodes)
Creates a Virtual Tree (VTree) which can be interpolated and rendered. This has
a similar purpose to hyperscript's h()
and React's createElement
.
Arguments
Name | Description |
---|---|
nodeName | A string for HTML, or couuld be a component or other types like functions when using middleware |
attributes | An object of DOM attributes or properties key and value or null |
...childNodes | An array of child nodes, or a single element merged with any additional arguments |
Examples
const attributes = {
id: 'test',
style: 'color: red',
};
const childNodes = [
createTree('#text', null, 'Hello world'),
];
// Create a div Virtual Tree.
const div = createTree('div', attributes, childNodes);
release (mount)
Use this method if you need to clean up memory allocations and anything else internal to diffHTML associated with your element. This is very useful for unit testing and general cleanup when you're done with an element. Applications will probably not use this if the app lives as long as the tab.
Arguments
Name | Description |
---|---|
mount | Release memory and all internal references to the DOM node. |
Internals
These internals are deemed public API and may be relied upon once the library has reached a stable version. The intention is to allow developers to tweak the library, observe and influence internal memory, and build tooling around the runtime.
MiddlewareCache
A JavaScript Set object that contains registered middleware functions that trigger whenever transaction state changes. Use this to help enable/disable middleware functions from running during renders.
CreateNodeHookCache
A JavaScript Set object that contains functions that trigger whenever a DOM Node is created during the patching process.
CreateTreeHookCache
A JavaScript Set object that contains functions that trigger whenever a Virtual
Tree is created through html
, createTree
, or during the parsing process.
ReleaseHookCache
A JavaScript Set object that contains functions that trigger whenever a Virtual Tree is cleaned up by diffHTML's internal garbage collection. You can do additional cleanup here.
SyncTreeHookCache
A JavaScript Set object that contains functions that trigger whenever Virtual Trees are compared. You can influence how the Virtual DOM synchronizes changes, by changing attributes JIT, telling diffHTML to ignore certain nodes, or tell diffHTML to not apply any changes to a given node.
NodeCache
A Map that can be used to get access to the DOM node associated to a VTree.
This is comparable to findDOMNode
in React. Basically if you encounter an
object that the documentation says is a VTree and you want to convert to a DOM
Node, you could write something like:
import { Internals } from 'diffhtml';
function findDOMNode(vTree) {
return Internals.NodeCache.get(vTree);
}
findDOMNode(someVTree);
If it comes back as null
or undefined
then you should take that to mean
that the VTree is no longer bound to an element in the DOM. You may also find
that diffHTML has re-used the VTree you have saved, so calling NodeCache.get
will yield an unexpected result. Therefore its recommended to call this method
immediately if you need the DOM node and not save a VTree in between
re-renders.
Transaction
A render transaction is scheduled whenever innerHTML
or outerHTML
are
called. It is an instance of a Transaction
class that has a few methods:
abort, end, onceEnded, and start. This instance is mutable and the
properties will change by the internals. You should not modify the transaction
directly unless you know what you're doing. Reading any property is considered
the live source-of-truth and a safe operation.
There are a series of tasks that run when a transaction is created. Depending
on the build flavor, full or runtime, you will get a different set of tasks. By
default transactions run synchronously and you can observe a result immediately
after running innerHTML
or outerHTML
.
> schedule # If another transaction is running, this will run after
> shouldUpdate # If nothing has changed, abort early
> parseNewTree # Full build only, will parse a passed in string of HTML
> reconcileTrees # Align trees before diffing
> syncTrees # Loop through and compare trees as efficiently as possible
> patchNode # Apply chnages to the DOM
> endAsPromise # If a transaction is delayed, resolve once complete
Transactions have a number of properties available to access:
- aborted - The transaction was abandoned
- completed - The transaction successfully completed
- domNode - The container element being rendered into
- endedCallbacks - The set of callbacks that will be called once completed
- input - The raw input to render
- newTree - The reconciled tree to use for new source-of-truth
- oldTree - The old tree which may already be updated with newTree
- options - Options used when updating markup
- patches - What has been updated in the DOM
- state - Internal state object for the transaction
- tasks - Array of functions that were executed when rendering
VERSION
See VERSION
VERSION
Property which indicates the current running version of diffHTML.
Example
console.log(VERSION);
Options
Allows configuring runtime rendering behavior. These options are accessible via
transaction.config
and can be set via query string, environment variables, or
passing a config object to innerHTML
, outerHTML
, and toString
.
In the case of query string and environment variables, uppercase the variables
and prefix with DIFF_
. So inner
becomes DIFF_INNER
. For parser
use a
JSON string: JSON.stringify({ parser: { rawElements: ['div'] } })
.
inner Boolean
Determines if the Transaction should update the DOM Node or just its children.
Setting this to true
will emulate the behavior of innerHTML
and setting it
to false
emulates outerHTML
. You cannot set this using innerHTML
or
outerHTML
, and it has no effect with toString
so it is only useful if you
manually create Transactions which is an advanced use case.
tasks Function[]
Manipulate the tasks which run. This can allow you to do interesting things with the core API. You can do API changes like providing a stream or generator API for the return signature, you can remove syncing and provide your own object for patching, etc. This feature is used by the project to create the toString method, which changes the return value to a string.
Caution: Only modify this in a closed environment and do not ship components or shared utils which attempt to modify the host tasks.
Example
Change the return value of innerHTML to be a callback.
import { innerHTML, Internals } from 'diffhtml';
// Start with the default tasks.
const newTasks = new Set(Internals.defaultTasks);
newTasks.delete(Internals.tasks.endAsPromise);
// Update the transaction end by returning a callback instead of using a
// Promise based API.
newTasks.add(transaction => {
const { promises } = transaction;
// Change the final return value to a callback.
return callback => {
if (promises && promises.length) {
return transaction.promise = Promise.all(promises).then(() => {
transaction.end();
callback(transaction);
});
}
transaction.promise = Promise.resolve(transaction.end());
callback(transaction);
};
});
// You can supress this behavior by setting executeScripts to false
innerHTML(document.body, `<h1>Hello world</h1>`, {
tasks: [...newTasks],
})(transaction => {
console.log('Render has completed with transaction', transaction);
});
executeScripts Boolean
Control whether or not newly appended scripts are executed or not. When
enabled, tricks the browser by setting the type
property to no-execute
when
a script is added. This prevents the browser from executing the script.
Example
import { innerHTML } from 'diffhtml';
// By default scripts will execute
innerHTML(document.body, `<script>window.alert('here')</script>`);
// You can supress this behavior by setting executeScripts to false
innerHTML(document.body, `<script>window.alert('here')</script>`, {
executeScripts: false,
});
disableMutationObserver Boolean
Allows disabling the MutationObserver feature if the mount is known to never become dirty.
Example
import { innerHTML } from 'diffhtml';
// No MutationObserver will observe if document.body changes outside of diffHTML.
innerHTML(document.body, `Some value`, {
disableMutationObserver: true,
});
parser Object
These options modify the parser by changing which elements are treated as block or self closing.
Learn more about these options
Example
This example will throw an error since the parser encountered invalid markup.
import { innerHTML } from 'diffhtml';
innerHTML(document.body, `
<h1>Hello world</h2>
`, { parser: { rawElements: ['div'] } });