Last active
March 14, 2017 00:16
-
-
Save tbranyen/8ac84e3afd80b33188bbdf184a187175 to your computer and use it in GitHub Desktop.
diffHTML 1.0 Middleware Specification + Documentation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Documentation for authoring middleware in diffHTML v1.0 | |
// Usage of the middleware we'll write below, I added it up top, since it's a | |
// single line: | |
diff.use(myFirstMiddleware()); | |
// To make a diffHTML middleware, start by creating a normal function that | |
// accepts options. We don't need to configure our middleware yet, but we want | |
// to keep all middleware consistent with this convention. | |
functon myFirstMiddleware(options = {}) { | |
// diffHTML middleware is built around the concept of transaction render | |
// flows. A transaction flow is a series of tasks that are run in order, and | |
// each are passed a transaction object. By default diffHTML will execute a | |
// task for each step of the Virtual DOM rendering process. Middleware tasks | |
// are very similar to these built-in tasks, except that the task function is | |
// invoked at the start of every render, and if a function is returned, that | |
// function will be injected into the end of the render flow. This allows you | |
// to write middleware that can react to the lifecycle of a transaction. | |
// IMPORTANT: The function name is how it is displayed in the dev tools. It | |
// will convert camel-case into "My First Middleware", the `Task` is also | |
// required. | |
function myFirstMiddlewareTask(transaction) { | |
// When this function is invoked, a transaction has just started, so the | |
// transaction object will only contain initial properties: | |
// | |
// - domNode - The Node passed as the first argument to innerHTML/outerHTML | |
// - markup - The new tree to patch into the DOM, passed as the second arg | |
// - options - Any options passed to diffHTML, like `tasks` or `inner` | |
// - state - An object tied to the Node that persists across transactions | |
// | |
// A useful method on the transaction object is `abort`. If you return this | |
// method invoked, it will terminate the render flow immediately. | |
// If you return a function it will be called near the end of the render | |
// transaction flow along with all other registered middleware. This | |
// function is the "true" render task that gets injected into the flow. | |
return function() { | |
// By the time this function has been called, diffHTML will already have | |
// synchronized the new markup tree into the old tree and applied changes | |
// to the DOM (if no transitions were used). However, if transitions are | |
// used you will need to wait until all promises are complete, before | |
// working with the DOM. | |
// | |
// The transaction object at this point now contains two new properties: | |
// | |
// - patches - An object with all DOM tree, attribute, and value changes | |
// - promises - An array of promises that were attached from transitions | |
// | |
// While you may be tempted to simply Promise.all(promises) to know once | |
// rendering has truly completed, this would not catch cases where the | |
// transaction gets aborted, and may end up resolving after the | |
// transacton complete code has already run. Here is an official hook | |
// that can be used instead and is called once the transaction has | |
// actually ended. | |
// | |
// Simply add a function to set the hook. Don't worry about cleaning up | |
// these references. They are tied directly to the transaction instance, | |
// and are automatically removed after being called so they can be GC'd. | |
transaction.onceEnded(function() { | |
// The transaction has absolutely ended now, all transitions have | |
// completed, you can get the timestamp here to compare with one | |
// made when the task function first gets called to know how long | |
// rendering took. | |
}); | |
}; | |
} | |
// Optional: If your task needs internals from diffHTML, before any tasks | |
// run, this callback will fire synchronously after diffHTML internally | |
// registers the middleware. It is called with the full public diffHTML API, | |
myFirstMiddlewareTask.subscribe = function(diff) { | |
// If you need to connect to a web worker, devtools, or anything else that | |
// lasts the lifetime of the code, gets put inside this function. | |
}; | |
// Optional: If your task is removed and has associated state cleanup, handle | |
// that here. It is called with the full public dsffHTML API, | |
myFirstMiddlewareTask.unsubscribe = function(diff) { | |
// If this middleware could get re-attached, the above subscribe will be | |
// called again, so make sure that you can create a workable lifecycle of | |
// startup and teardown. Don't make the teardown impossible to bring back | |
// up. | |
}; | |
return myFirstMiddlewareTask; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Proposal: Create vTree Hook