Giter VIP home page Giter VIP logo

mitt's Introduction

mitt
npm build status gzip size

Mitt

Tiny 200b functional event emitter / pubsub.

  • Microscopic: weighs less than 200 bytes gzipped
  • Useful: a wildcard "*" event type listens to all events
  • Familiar: same names & ideas as Node's EventEmitter
  • Functional: methods don't rely on this
  • Great Name: somehow mitt wasn't taken

Mitt was made for the browser, but works in any JavaScript runtime. It has no dependencies and supports IE9+.

Table of Contents

Install

This project uses node and npm. Go check them out if you don't have them locally installed.

$ npm install --save mitt

Then with a module bundler like rollup or webpack, use as you would anything else:

// using ES6 modules
import mitt from 'mitt'

// using CommonJS modules
var mitt = require('mitt')

The UMD build is also available on unpkg:

<script src="https://unpkg.com/mitt/dist/mitt.umd.js"></script>

You can find the library on window.mitt.

Usage

import mitt from 'mitt'

const emitter = mitt()

// listen to an event
emitter.on('foo', e => console.log('foo', e) )

// listen to all events
emitter.on('*', (type, e) => console.log(type, e) )

// fire an event
emitter.emit('foo', { a: 'b' })

// clearing all events
emitter.all.clear()

// working with handler references:
function onFoo() {}
emitter.on('foo', onFoo)   // listen
emitter.off('foo', onFoo)  // unlisten

Typescript

Set "strict": true in your tsconfig.json to get improved type inference for mitt instance methods.

import mitt from 'mitt';

type Events = {
  foo: string;
  bar?: number;
};

const emitter = mitt<Events>(); // inferred as Emitter<Events>

emitter.on('foo', (e) => {}); // 'e' has inferred type 'string'

emitter.emit('foo', 42); // Error: Argument of type 'number' is not assignable to parameter of type 'string'. (2345)

Alternatively, you can use the provided Emitter type:

import mitt, { Emitter } from 'mitt';

type Events = {
  foo: string;
  bar?: number;
};

const emitter: Emitter<Events> = mitt<Events>();

Examples & Demos

Preact + Mitt Codepen Demo
preact + mitt preview

API

Table of Contents

mitt

Mitt: Tiny (~200b) functional event emitter / pubsub.

Returns Mitt

all

A Map of event names to registered handler functions.

on

Register an event handler for the given type.

Parameters

  • type (string | symbol) Type of event to listen for, or '*' for all events
  • handler Function Function to call in response to given event

off

Remove an event handler for the given type. If handler is omitted, all handlers of the given type are removed.

Parameters

  • type (string | symbol) Type of event to unregister handler from, or '*'
  • handler Function? Handler function to remove

emit

Invoke all handlers for the given type. If present, '*' handlers are invoked after type-matched handlers.

Note: Manually firing '*' handlers is not supported.

Parameters

  • type (string | symbol) The event type to invoke
  • evt Any? Any value (object is recommended and powerful), passed to each handler

Contribute

First off, thanks for taking the time to contribute! Now, take a moment to be sure your contributions make sense to everyone else.

Reporting Issues

Found a problem? Want a new feature? First of all see if your issue or idea has already been reported. If don't, just open a new clear and descriptive issue.

Submitting pull requests

Pull requests are the greatest contributions, so be sure they are focused in scope, and do avoid unrelated commits.

  • Fork it!
  • Clone your fork: git clone https://github.com/<your-username>/mitt
  • Navigate to the newly cloned directory: cd mitt
  • Create a new branch for the new feature: git checkout -b my-new-feature
  • Install the tools necessary for development: npm install
  • Make your changes.
  • Commit your changes: git commit -am 'Add some feature'
  • Push to the branch: git push origin my-new-feature
  • Submit a pull request with full remarks documenting your changes.

License

MIT License © Jason Miller

mitt's People

Contributors

andarist avatar aweary avatar bwendt-mylo avatar danielruf avatar davidkpiano avatar developit avatar dhaxor avatar dotproto avatar esebastian avatar floriangosse avatar gamtiq avatar iyegoroff avatar jackfranklin avatar jaylinski avatar jesperzach avatar lukechilds avatar lukeed avatar mathiasbynens avatar mister-hope avatar oksas avatar pmg103 avatar rvikmanis avatar sealice avatar seveves avatar skellock avatar styfle avatar thiamsantos avatar tungv avatar tunnckocore avatar zbuttram avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mitt's Issues

Restrictions for the event name

This code will produce an exception:

const mitt = require("mitt")

const emitter = mitt()

emitter.on('constructor', e => console.log(1))
emitter.emit('constructor', {})

You may want to filter all those native methods out, or use a different approach of collecting the events.

Benefits?

Why methods don't rely on this is a benefit?

Benefits?

Why to choose Mitt over native EventEmitter?
Just wondering

Clean up repo root

  • Auto-generate (and gitignore) typings.json during build via package-to-typings
  • move mitt.d.ts into src/ (it's still included in the npm package)
  • Move .babelrc into tests/ since that's the only place it's used
  • gitignore yarn.lock
  • remove example.js (started in #37 - should be in the readme instead)

/cc @tunnckoCore

Thanks !

I use a lot of code that you develop and open-source.
I never run into issues that cant be solved by re-reading the docs (and/or in rare cases the code) so I never open issues in here and am using this as a chance to.
I suspect there are many people like me :)

Thanks to @developit ( and all contributors ! ) for the great work !
Cheers 😄

Question: do you want to make `once()` available?

One of the things I find useful about event emitters/signals is the ability to emit an event/signal only once.

I understand this library aims to have a super small footprint, but I do believe adding such feature would not add significant size to the final bundle.

With that being said, do you have interest in adding this feature? If so, I can attempt a PR.

Thank you.

Include dist files

It seems currently the dist files aren't in the repo nor in the release zip.

Can you include them in the next release?

Listen for events that happened before the listener is created.

Hey @developit,

this is a really neat library. I was wondering if it is possible to have a listener fire immediatly if it is attached to an event that already happened? It did not work for me, so is it no supported, or did I do it wrong?

For example I would like to fire an event once the animation library is loaded, so that I can start all animations afterwards, no matter where they are defined.

Thanks for your help.

TransformError in react-native

I believe some babel presets within mitt's package.json are causing following error when used in react-native

NOTE: adding those preset into project itself fixes the issue, but I'm not entirely sure if this it is a good solution to force presets? And it would be good to find out where and how mitt needs these to weight everything.

Loving the project so far <3 I converted my personal project to use mitt alongside slightly altered version of smitty (https://github.com/tkh44/smitty) and it seems much cleaner / easier compared to redux so far, great job 👍

Error received in react native v0.40, mitt 1.0.0

Imgur

Deploy fixes for Flow types to NPM

I noticed that #47 fixes some Flow types issues, but that the package.json is older than that PR. It's causing type errors for us via our svg-baker-runtime package which uses Mitt as a dependency. We're ignoring Mitt in our .flowconfig temporarily, but you might want to make sure it's been deployed.

UglifyJS Build Error

Hey guys, I opened an issue with React Boilerplate, but thought I'd open one here as well to see if you've ever come across problems uglifying this module installed via npm. Maybe there's a problem with the Webpack config and I just need to add something to make it play nice? Anyway, the boilerplate is one of the most popular boilerplates available for React and it yields a build error when Mitt is either a direct dependency, or any dependent packages are using Mitt.

Here are the steps to reproduce:

$ git clone --depth=1 https://github.com/react-boilerplate/react-boilerplate.git
$ cd react-boilerplate
$ npm run setup
$ npm run clean
$ yarn add mitt

Open react-boilerplate/app/containers/HomePage/index.js and add the following import:

import mitt from 'mitt';

Then,

$ npm run build

The given will be something like this:

ERROR in 1.673e1d9e06dc9452619e.chunk.js from UglifyJs
SyntaxError: Unexpected token punc «(», expected punc «:» [1.673e1d9e06dc9452619e.chunk.js:105,4]

if play with array's methods

// impl
function mitt() {
    all = [];
    return {
        on: (name, handler) => all.push(n => ~['*', n].indexOf(name) ? handler : _ => _),
        off: (name, handler) => all = all.filter(h => h(name) !== handler),
        emit: (name, args) => all.map(h => h(name)(name, args))
    };
}


//tests
const t = mitt();

const handler1 = (name, args) => console.log(name, args);
const handler2 = (name, args) => console.log(name, args);

t.on('*', handler1);
t.on('hello', handler2);

t.emit('hello', {
    a: 1
});

t.emit('test', {
    a: 2
});

t.off('*', handler1);
t.off('hello', handler2);

t.emit('hello', {
    a: 3
});

Alternative for removeAllListeners

I currently have an implementation using events and util.inherit (in the browser, so the npm versions), and would like to use mitt instead, however, I can't seem to figure out what I should use instead of removeAllListeners.

I guess I could keep a map of listeners myself, but that seems like duplicating what mitt does in the first place.

So far I have:

function DerivedHelper(mainHelper, fn) {
  this._emitter = mitt();
}

/**
 * Invoke all handlers for the given type.
 * If present, `"*"` handlers are invoked after type-matched handlers.
 *
 * @param {String} type The event type to invoke
 * @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
 * @memberOf mitt
 */
DerivedHelper.prototype.emit = function(type, data) {
  this._emitter.emit(type, data);
};

/**
 * Register an event handler for the given type.
 *
 * @param  {String} type Type of event to listen for, or `"*"` for all events
 * @param  {Function} handler Function to call in response to given event
 */
DerivedHelper.prototype.on = function(type, cb) {
  this._emitter.on(type, cb);
};

/**
 * Remove an event handler for the given type.
 *
 * @param  {String} type Type of event to unregister `handler` from, or `"*"`
 * @param  {Function} handler Handler function to remove
 */
DerivedHelper.prototype.off = function(type, cb) {
  this._emitter.off(type, cb);
};

/**
 * Detach this helper from the main helper
 * @return {undefined}
 * @throws Error if the derived helper is already detached
 */
DerivedHelper.prototype.detach = function() {
  // TODO: find a replacement for this
  this.removeAllListeners();
};

Thanks!

Unsubscribe to all the listener

Hello,

should there be a method to remove all listeners of the emitter, to save performance?

I have an example case when we initialize a component, and the component needs to use the event emitter, and pass it to other function to listen to the component event:

// component.js
componentInit() {
  method.init(emitter);
}

// method.js
init (emitter) {
  emitter.on('something', doSomething);
}

Then, when the component is about to be destroyed, should the emitter be "cleaned up" so the method won't have to preserve the event listener anymore? For ex:

// component.js
componentDestroy() {
  emitter.off('*');
}

ES modules build

I would like to be able to use Mitt from the browser like:

<script type=module>
  import mitt from 'https://unpkg.com/mitt/es.js';

  let emitter = mitt();
  ...
</script>

Would you be open to a build that that includes the export. Since this is using rollup that should be pretty easy I think.

Support emitting multiple arguments

Just like .emit('foo', 1, 2, 3). Initially thought for rest + spread but it adds around 50 bytes.
So I think it may be enough to have explicitly defined 3-4 arguments

That adds 4 bytes.

    emit(type, a, b, c) {
      list('*').concat(list(type)).forEach( f => { f(a, b, c); });
      return ret;
    }

Some faster implementations than node core's uses this tactic, but up to 6-8 args

expose `all`

I think...

off(type) should remove all handlers for the given type

off() without arguments should just clear the all object completely

OR...

you can just expose all! it'll only be an addition of 4 chars, and I won't bother you anymore (or at least that's my story) ;P

Should not allow emitting the wildcard?

See tunnckoCoreLabs/dush#5. Because it will trigger listeners twice. See this reddit thread comment.

The simplest fix is to do something like that

    emit (name, a, b, c) {
      if (name !== '*') {
        (all[name] || []).map((handler) => { handler(a, b, c) });
        (all['*'] || []).map((handler) => { handler(name, a, b, c) })
      }
    }

the test case that i made for dush

test('should not allow emitting the wildcard (issue#5)', function (done) {
  var emitter = dush()

  emitter.on('*', function (name, a, b, c) {
    test.strictEqual(name, 'foo')
    test.strictEqual(a, 1)
    test.strictEqual(b, 2)
    test.strictEqual(c, 3)
  })
  emitter.on('foo', function (a, b, c) {
    test.strictEqual(a, 1)
    test.strictEqual(b, 2)
    test.strictEqual(c, 3)
  })

  emitter.emit('*', 4, 5, 6)
  emitter.emit('foo', 1, 2, 3)
  emitter.emit('*', 555)
  done()
})

emit with multiple arguments

emit(type, ...a) {
  list('*').concat(list(type)).forEach( (f) => { f.apply(null, a); });
}

this seems it would be backwards compatible and support multiple arguments

Bitwise operators question

Hello,

I'm here just to ask what is the main usage of the bit operators here? in the off function you're using >>> at line 40

all[type].splice(all[type].indexOf(handler) >>> 0, 1);

And in the old source code you used ~ also inside the off function at line 34

I just want to know why because I can't see a reason to use them and thank you in advance

Support chaining

It would be cool and is already some habit for some devs.

const mitt = require('mitt')
const emitter = mitt()
emitter.on('foo', console.log).on('bar', console.log).emit('foo', 123)

Wildcards to match segments?

Love seeing a new entry in the space for pubsub/events! Definitely something I keep thinking about.

Have you considered adding support for wildcards to match segments within an event as opposed to being used as a catch-all?
I believe postaljs does this with the # and * characters. Probably only need * to keep things minimalistic, unless there's a reason to differentiate matching one vs. many segments.

Testing

Isn't just enough to not use babel and etc? Why we need this and ES6 syntax and imports at all. It is just overhead. With that we can just remove babel from deps and they will look more clean.

/cc @developit

Uncaught TypeError: mitt is not a constructor

Hi!
Im trying to use mitt in our react project using typescript.
But I get this error in runtime:

Uncaught TypeError: mitt is not a constructor
    at eval (api.ts:11)
    at Object../packages/foo-api/api.ts (bundle.js:10804)
    at __webpack_require__ (bundle.js:672)
    at fn (foo.js:98)
    at eval (index.ts:5)
    at Object../packages/foo-api/index.ts (bundle.js:10817)
    at __webpack_require__ (bundle.js:672)
    at fn (bundle.js:98)
    at eval (Foo.view.tsx:15)
    at Object../packages/foo-ui/Foo.view.tsx (bundle.js:11779)

I'm using ut just like in your example

import * as mitt from 'mitt'
const emitter: mitt.Emitter = new mitt()

When debugging in Dev tools and check mitt it's an object, not a contructor.

Object {__esModule: true, default: function}
   default: function mitt(all )
   __esModule: true
   __proto__: Object

Am I doing something wrong?

Unable to use extend with mitt

Hey,
I noticed that after when I try to use extends in my TypeScript project, the all class stuff are just removed.

Also I need to use ugly hack to execute the constructor of mitt beacuse TypeError: mitt is not a constructor.

const mittConstructor = (mitt as any).default.prototype.constructor;
type ExampleClassEmitter = StrictEventEmitter<mitt.Emitter, IExampleEvents>;
class ExampleClass extends (mittConstructor as { new(): ExampleClassEmitter }) {}

So I need to do like this to get inheritance:

const mittConstuctor = (mitt as any).default.prototype.constructor;
class MittFix {
  constructor() {
    Object.entries(mittConstuctor()).forEach(([key, value]) => {
      this[key] = value;
    });
  }
}

class ExampleClass extends (MittFix as { new(): ExampleClassEmitter }) {}

That's because Mitt constructor returns an object { ... }, and 'this' is not used, but should be.

Regards,
TheAifam5

[question] off(*) behaviour

shouldnt it remove all listeners instead of only listeners attached with on('*', fn)? alternatively it would be good to have some destroy method to remove all listeners, whatsoever, that could be even achieved with emitter.off() (when called without arguments)

Publish latest changes please

It appears that there are some valuable changes in master. Are there bugs or issues preventing a release? I would love to see them published as a new version.

Thanks!

Deduping handler registration

In the initial release of mitt a caller can register one handler multiple times for an event. For some use cases, though, duplicate registrations can be problematic. At the moment, mitt does not provide any APIs to avoid duplicate registration.

I see two straight forward ways of allowing consumers to avoid duplicate registration:

  1. Extend on() to take a dedupe parameter. When truthy, mitt would not register the handler if it's already present on all.
  2. Create a has() method that returns a Boolean indicating if a given handler has been registered for an event. Callers concerned about duplicate handlers can manually check before calling on().

Between the two I feel like 1 provide a more ergonomic API and would likely help keep byte count down.


Prior art

  • Element.addEventListener silently drops duplicate listener registrations.
  • EventEmitter.on states "[m]ultiple calls passing the same combination of eventName and listener will result in the listener being added, and called, multiple times."

"*" listeners may fire more than once.

If you want to only target "*" listeners and do emitter.emit("*", "stuff here"), those listeners will actually fire twice. Checking for that specific value before firing the "*" listeners would fix that.

TypeScript: Wildcard types did not make it into 1.1.3

Just looking at the source package of 1.1.3 and the release notes mention that the wildcard typing was added.

Unfortunately, it looks like 1.1.3 still has the old typing definition. Any chance you can trigger a release of 1.1.4 with the updated wildcard typing?

Strongly typed event names & values

I really like mitt, and the rewrite in TypeScript is a great step forward, but I wonder if we could go a bit further and allow strong typing of both the event names and their associated values.

Ideally, this would be an opt-in behaviour, meaning that by default mitt uses a string | symbol type for event names, and any for values. But passing an interface as a generic type to the constructor would tell mitt what events to expect and what values are associated, along with providing auto-completion in IDEs.

Hypothetical API:

interface MittEvents
{
  foo: number
  bar: string
  egg: {
    a: string[]
    b?: number
  }
  noarg: null
}

const emitter = mitt<MittEvents>()

emitter.on('foo', value => {
  // value has type `number`
})

emitter.on('bar', value => {
  // value has type `string`
})

emitter.on('egg', ({ a, b = 0 }) => {
  // a has type `string[]`
  // b has type `number` with a default value
})

emitter.emit('foo', 42)
emitter.emit('noarg', null)

// Check value type
emitter.emit('foo', 'not a number') // <- TS error

// Check allowed event names
emitter.emit('another', 42) // <- TS error

Such a typing system can be seen in action in vegemite, a state management library with a similar EventEmitter interface.

typescript

Nice little lib. You make extra effort to document the parameters types.

How about typescript ?

Why use slice?

(all['*'] || []).slice().map((handler) => { handler(type, evt); });
Why use slice?

[feature request] once handler

would u consider adding this or is it out of scope? Ive tried implementing it myself so I could send a PR, but my minifications skill are not that great ;)

best result i got was 214B which is exceeding ur goal

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.