Skip to main content

Hooks

Hooks are how everything happens in flecks. There are many hooks and the hooks provided by flecks are documented at the hooks reference page.

Implementing (your and other) hooks​

To implement hooks (and turn your plain ol' boring JS modules into beautiful interesting flecks), you only have to export a hooks object:

export const hooks = {
'@flecks/core.starting': () => {
console.log('hello, gorgeous');
},
};

An even better way to hook​

You may also implement hooks using Flecks.hooks and require.context.

If you are implementing many hooks in a single file, things can start to get cluttered. There is a better way to structure your hooks:

export const hooks = Flecks.hooks(require.context('./hooks'));

Supposing you implemented the above in index.js and had a file structure like so:

src
├─ index.js
└─ hooks/
└─ @flecks/
└─ core.starting.js

and the content of core.starting.js was as follows:

export const hook = () => {
console.log('hello, gorgeous');
};

The result would be exactly equivalent to the hooks object definition above.

For a real example of this, see the flecks source for examples here or here.

You may even use require.context for your hooks within flecks.bootstrap.js! Even though it's a CommonJS environment, pirates is used for that little bit of magic. (If that scares you, don't worry — it's only during the build process.) Ergonomics matter!

Coming in hot (and correct)

Some hooks (e.g. @flecks/server.up) are tracked by watching @flecks/core.hmr.hook and will restart the application when any implementations are changed.

If you structure your hooks using Flecks.hooks, HMR will only refresh the hooks that changed. If you export a simple object, all hooks will appear to change on any change. This may lead to more restarts than necessary for a given change.

Invoking your hooks​

Hooks may be invoked using different invocation methods which may affect the order of invocation as well as the final result.

All methods accept an arbitrary number of arguments after the specified arguments.

Catch you on the flip

All methods pass the flecks instance as the last argument. You never have to include it.

invoke​

invokeAsync​

Invokes all hook implementations and returns the results keyed by the implementing flecks' paths.

hook: string​

The hook to invoke.

invokeFleck​

Invoke a single fleck's hook implementation and return the result.

hook: string​

The hook to invoke.

fleck: string​

The fleck whose hook to invoke.

invokeFlat​

Invokes all hook implementations and returns the results as an array.

hook: string​

The hook to invoke.

Just a spoonful of sugar

The following test would pass:

expect(flecks.invokeFlat('some-hook'))
.to.deep.equal(Object.values(flecks.invoke('some-hook')));

invokeComposed​

invokeComposedAsync​

See: function composition.

initial is passed to the first implementation, which returns a result which is passed to the second implementation, which returns a result which is passed to the third implementation, etc.

hook: string​

The hook to invoke.

initial: any​

The initial value.

invokeMerge​

invokeMergeAsync​

Invokes all hook implementations and returns the result of merging all implementations' returned objects together.

hook: string​

The hook to invoke.

invokeMergeUnique​

invokeMergeUniqueAsync​

Specialization of invokeMerge that will throw an error if any keys overlap.

hook: string​

The hook to invoke.

invokeReduce​

invokeReduceAsync​

See: Array.prototype.reduce()

Invokes hook implementations one at a time, their results being passed to the reducer as currentValue. Returns the final reduction.

hook: string​

The hook to invoke.

reduce: function​

The reducer function.

initial: any​

The initial value.

invokeSequential​

invokeSequentialAsync​

Invokes all hook implementations, one after another. In the async variant, each implementation's result is awaited before invoking the next implementation.

hook: string​

The hook to invoke.

makeMiddleware​

Hooks may be implemented in the style of Express middleware.

Each implementation will be expected to accept 0 or more arguments followed by a next function which the implementation invokes when passing execution on to the next implementation.

Usage with express would look something like:

app.use(flecks.makeMiddleware('@my/fleck.hook'));

For more information, see: http://expressjs.com/en/guide/using-middleware.html

Documenting your hooks​

You should document the hooks you define for the benefit of others (and future you)! You may do so in build/flecks.hooks.js within your fleck. If you define a hook called @my/fleck.alarm, you might write:

build/flecks.hooks.js
export const hooks = {
/**
* Ring an alarm.
*
* @param {number} ding The dinger.
* @param {string} dong The donger.
* @returns {boolean} Whether the ding was donged.
*
* @invoke Async
*/
'@my/fleck.alarm': (ding, dong) => {
// Here's some example usage.
},
}

This is how the generated hooks page gathers data to generate the page. You can even take advantage of this for your project!