@joaomelo/bus

Library providing a simple Event Bus for JS apps.

Usage no npm install needed!

<script type="module">
  import joaomeloBus from 'https://cdn.skypack.dev/@joaomelo/bus';
</script>

README

Bus

Library providing a simple Event Bus for JS apps.

Motivation

The Event Bus is a typical programming pattern to decouple pieces of an app. It is a central interface to signal or react to behavior like logging or alerting. Some modules can subscribe to an event without any knowledge of the publisher component and vice-versa.

Let's imagine we are developing a JavaScript web app that needs to route to a new URL after login. You could do something like this:

// login.js
import { route } from './router';

function login (email, password) {
  // perform some login logic
  route.to('/home');
}

A few days later, you discover that after login, you have to make sure the user has profile information saved or create the default preferences. The code should evolve into something new.

// login.js
import { route } from './router';
import { hasProfile, createProfile } from './profile';

function login(email, password) {
  // perform some login logic
  if (!hasProfile(email)) {
    createProfile(email);
  }
  route.to('/home');
}

Cool, let's take a break 😎, do some fun stuff, and come back six months later to update the profile and router modules. What's the odds of this future you or some teammate remembers that login code is dependent on router or profile logic? Well, never tell me the odds.

The Event Bus approach is one way (of many) to minimize this kind of hard dependency. There are some variations in how to implement it. But they gravitate around publishing and subscribing events, also known as topics.

Getting Started

We start by installing it with npm.

npm install @joaomelo/bus

Usage

The behavior is driven by the subscribe and publish functions. To listen to a topic, you import the subscribe function and call it passing the topic key and a observer function that will be called when the event is published. Our router and profile modules become:

// router.js
import { subscribe }  from '@joaomelo/bus';
subscribe('USER_LOGGED_IN', () => route.to('/home'));

// profile.js
import { subscribe }  from '@joaomelo/bus';
subscribe('USER_LOGGED_IN', email => { 
  if (!hasProfile(email)) {
    createProfile(email)
  }
});

The login module should now just publish the event without the need to understand any details about how this would be used. Data is passed as payload to all observer functions.

// login .js
import { publish } from '@joaomelo/bus'

function login(email, password) {
  // perform some login logic
  publish('USER_LOGGED_IN', email)
}

Unsubscribe

The subscribe function returns another function. Invoking it will prevent that corresponding observer from being executed in future event publications.

// some-module.js
import { subscribe } from '@joaomelo/bus';

const unsub = subscribe('MY_TOPIC', payload => console.log(payload));
unsub(); // forget about it

Late subscription

Everything until here is enough to use the Bus effectively. Complex business cases will impose more sophistication like queue management or failsafe recovery. Our little package has only one configuration option. It is optional and could be passed as the third parameter of the subscribe function.

Maybe you are subscribing after an event was already published. For example, you want to listen for the user login, and it automatically happened on initialization based on some cached data. The code that subscribes to the login event was then unable to catch that first signal.

The Bus library could compensate for that by running the callback immediately after subscription if the topic was published at least once. The last payload will be passed. For that to happen, adopt a true value as the third parameter to subscribe.

subscribe('SOME_TOPIC', callback, true);

Testing

The package has 100% test coverage. To run the tests, clone the repository, install all dev dependencies, and have fun 🎉.

git clone https://github.com/joaomelo/bus.git
npm install
npm test

Wrapping up

If you are learning to program, the EventBus is an excellent way to exercise coding skills. The whole library code resides in a few lines inside a single file. There is also this post I wrote about how to implement an Event Bus.

License

Made by João Melo and licensed under the GNU General Public License v3.0 - see the LICENSE file for details.