Middleware/Plugin API
See original GitHub issueThe Idea
A middleware API could be used to easily add a logger
, time-travelling-debugger
or a router
to any hyperapp project. It would provide a single point where a plugin can attach to everything it needs to.
app({
plugins: [logger, router, debug]
// ...
})
Plugins themselves are just a function that will be called as soon as hyperapp starts (basically like a subscription). They will then be able to add reducers
, effects
, hooks
and subscriptions
.
What should be exposed to a plugin?
hooks
, useful for stuff like a loggereffects
, already used by the router foractions.setLocation
reducers
, since they allow model-accesssubscriptions
, can be used to register events. E.g.window.addEventListener('popstate')
To prevent this from becoming an unpredictable mess I’m suggesting a convention that all plugins only use their own namespace. With nested actions that’s already possible. E.g.:
actions.router.setLocation('...')
model.router = {
matched: '/some/route/:id',
// ...
}
Further changes
Router needs a way to interact with the view, so a onRender
hook would be a good start.
Hooks need to be an array, since multiple plugins may want to listen to them.
Router rewrite
I’m also proposing that the router shares state with the rest of the application and uses the normal hyperapp lifecycle. (subscribes to subs, adds some effects, reducers, hooks, etc.)
model.router = {
matched: '/some/route/:id',
url: '/some/route/34593458',
params: {
id: 34593458
}
}
Moving this information to the model has some really good side-effects:
- A time-travelling debugger can easily roll back to an old state by just adjusting the model. No need to change the URL.
- You may decide to directly use
model.router.params.id
in your effects and reducers, which greatly simplifies the actions bound to the view - It’s compatible with the hyperapp lifecycle and embraces how hyperapp works, rather than keeping state somewhere else and hacking together logic that is similar to what hyperapp already does
- Plugins will feel familiar to everyone who ever worked with hyperapp, which makes it trivial to write one yourself
Meta
As usual I added 👍 and 👎 so it’s easy to vote if you don’t want to leave a comment. Ultimately the vote won’t decide what we do though. It’s just an additional thing to consider.
Issue Analytics
- State:
- Created 7 years ago
- Reactions:3
- Comments:12 (4 by maintainers)
@jbucaran That syntax would imply that hyperapp is fine with multiple apps too. Not sure if that makes sense to do. 😃
@dodekeract This would open the gates to hell, can we trust people will not create entangled plugins that depend on other plugins?
I like this proposal though. Currently hyperapp expects a clunky
router
property if you want to use it. Using something likeapp({ ..., plugins })
would generalize the concept, making things feel more “right”. The router is just another plugin.If we move forward with this, however, I’d find it more useful if HyperApp still provided the router out of the box.
The same is going to be true for
toString
, whenever that lands.