question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Plugins and middleware approach

See original GitHub issue

I’m investigating patterns for a plugin / extension approach for matter.js. Ultimately I’d like to maintain a collection of small module packages named matter-* that follow a common pattern (e.g. like the grunt / gulp ecosystem) rather than a monolithic library.

This should hopefully:

  • make the core lighter and simpler
  • allow new features without feature creep worries
  • encourage community contributions without needing pull requests

Some goals for a plugin approach are:

  • a common pattern
  • simple to define
  • simple to use
  • forwards and backwards compatibility
  • compatibility with other plugins
  • promote low coupling

To start we can say that plugins should be:

  • CommonJS module format
  • Built with browserify / webpack for browser use

One of the more difficult concerns for plugins is the need to extend existing methods like Engine.update or Body.create with new features. To do this plugins will need to hook these module methods so they can apply their own operations at the right moment. We could use events for this, but this requires definitions of lots of new events and there is little control over order of execution.

My proposal is that plugins can patch any module method through function composition. It could work like this:

MyPlugin.js

var MyPlugin = module.exports = {};

MyPlugin.patch = function(base) {
    // check dependencies
    assert(base.Engine);
    assert(Matter.Plugin.has(base, 'matter-another-plugin'));

    // or we can load our own plugin dependencies directly
    Matter.Plugin.use(base, MyPluginDep); // or 'matter-my-plugin-dep'

    // use function composition to patch and extend
    var engineUpdate = base.Engine.update;
    base.Engine.update = function(engine, delta, correction) {
        MyPlugin.Engine.update(engine, delta, correction);
        return engineUpdate(engine, delta, correction);
    }

    // more patched methods here
}

MyPlugin.somethingNew = function(things) {
    // doing something new has no need for patching
}

MyPlugin.Engine = {};

MyPlugin.Engine.update = function(engine, delta, correction) {
    // do plugin stuff on the engine
}

App.js

var Matter = require('matter-js');
var MyPlugin = require('matter-my-plugin');
var AnotherPlugin = require('matter-another-plugin');

Matter.use(MyPlugin);
Matter.use(AnotherPlugin);

// Matter.use is sugar for Matter.Plugin.use(Matter, MyPlugin) e.g. 
// (base, plugin) => { if (!Matter.Plugin.has(base, plugin)) { plugin.patch(base); base.plugins.push('matter-my-plugin'); } }

// we can now use Matter.* as normal, with additional features :)

var newThings = MyPlugin.somethingNew([Matter.Body.Rectangle(...)]);

I realise that monkey-patching like this might make some people wince. But it’s extremely powerful.

It’s also optional! As it’s entirely possible to use plugins defined like this without using Matter.use (obviously takes more work on the user’s part). Documentation of plugins might be a little tricky…

Candidates for plugins so far:

  • Matter.Render
  • Matter.RenderPixi
  • Matter.Runner
  • Matter.Svg

If anybody has any comments, ideas or examples of other good approaches I’d be interested to hear.

Edit: Looks like Vue.js is using a very similar approach.

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Comments:13 (9 by maintainers)

github_iconTop GitHub Comments

9reactions
liabrucommented, Aug 8, 2016

Just an update on this, I’m very close to having finalised the plugins implementation and it will be published in a branch soon!

3reactions
liabrucommented, Sep 4, 2016

The plugins branch is now pushed! Check it out!

Take a look at the code for Matter.Plugin to see the implementation.

There are also two new wiki pages on Using plugins and Creating plugins that go in to detail on the approach and the design of the plugin system.

Here are three simple plugins you can try:

You can see them in action by running the attractors example.

I’d appreciate it if you guys got back to me with your thoughts!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Middleware Plugin - Verdaccio
Middleware plugins have the capability to modify the API (web and cli) layer, either adding new endpoints or intercepting requests.
Read more >
How to run nuxt plugins before global middleware?
Add firebase plugin in client side only by renaming it like firebase.client.ts; Run middleware only when process.client is true; This PR might ...
Read more >
Plugin Architecture Overview Between Express, Fastify and ...
In this blog post we're going to review different architectural approaches to plug-ins of some popular Node.js tools such as Fastify, ...
Read more >
Plugin to Traefik: Create and Publish Your Own Middleware
In this meetup, Kevin discusses Traefik Plugins and how you can build your custom middleware using this new feature of Traefik.
Read more >
Middleware - Fastify
Remember that middleware can be encapsulated; this means that you can decide where your middleware should run by using register as explained in...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found