From 45063ea13a5d8842809fa6a0784aa07994a298f2 Mon Sep 17 00:00:00 2001 From: aminya Date: Fri, 23 Oct 2020 21:14:51 -0500 Subject: [PATCH 01/13] use es6 import/export instead of commonjs --- lib/composite-disposable.js | 3 +-- lib/disposable.js | 2 +- lib/emitter.js | 7 +++---- lib/event-kit.js | 6 +++--- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/lib/composite-disposable.js b/lib/composite-disposable.js index 495ec5e..ddf5df2 100644 --- a/lib/composite-disposable.js +++ b/lib/composite-disposable.js @@ -1,4 +1,3 @@ -let CompositeDisposable let Disposable // Essential: An object that aggregates multiple {Disposable} instances together @@ -24,7 +23,7 @@ let Disposable // } // } // ``` -module.exports = class CompositeDisposable { +export default class CompositeDisposable { /* Section: Construction and Destruction */ diff --git a/lib/disposable.js b/lib/disposable.js index 2737597..c8abcc9 100644 --- a/lib/disposable.js +++ b/lib/disposable.js @@ -1,6 +1,6 @@ // Essential: A handle to a resource that can be disposed. For example, // {Emitter::on} returns disposables representing subscriptions. -module.exports = class Disposable { +export default class Disposable { // Public: Ensure that `object` correctly implements the `Disposable` // contract. // diff --git a/lib/emitter.js b/lib/emitter.js index 1c7a253..976f233 100644 --- a/lib/emitter.js +++ b/lib/emitter.js @@ -1,5 +1,5 @@ -const Disposable = require("./disposable") -const CompositeDisposable = require("./composite-disposable") +import Disposable from "./disposable" +import CompositeDisposable from "./composite-disposable" // Essential: Utility class to be used when implementing event-based APIs that // allows for handlers registered via `::on` to be invoked with calls to @@ -28,7 +28,7 @@ const CompositeDisposable = require("./composite-disposable") // } // } // ``` -class Emitter { +export default class Emitter { static onEventHandlerException(exceptionHandler) { if (this.exceptionHandlers.length === 0) { this.dispatch = this.exceptionHandlingDispatch @@ -257,4 +257,3 @@ class Emitter { Emitter.dispatch = Emitter.simpleDispatch Emitter.exceptionHandlers = [] -module.exports = Emitter diff --git a/lib/event-kit.js b/lib/event-kit.js index 56b201d..aaea4cc 100644 --- a/lib/event-kit.js +++ b/lib/event-kit.js @@ -1,3 +1,3 @@ -exports.Emitter = require("./emitter") -exports.Disposable = require("./disposable") -exports.CompositeDisposable = require("./composite-disposable") +export { default as Emitter } from "./emitter"; +export { default as Disposable } from "./disposable" +export { default as CompositeDisposable } from "./composite-disposable" From 5b9d8b7433acef08eecf8ca965d9d258a5701e21 Mon Sep 17 00:00:00 2001 From: aminya Date: Fri, 23 Oct 2020 21:36:14 -0500 Subject: [PATCH 02/13] import disposable statically Lazy loading this small file will not have any considerable performance benefits --- lib/composite-disposable.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/composite-disposable.js b/lib/composite-disposable.js index ddf5df2..5ab8a1b 100644 --- a/lib/composite-disposable.js +++ b/lib/composite-disposable.js @@ -1,4 +1,4 @@ -let Disposable +import Disposable from "./disposable" // Essential: An object that aggregates multiple {Disposable} instances together // into a single disposable, so they can all be disposed as a group. @@ -92,10 +92,6 @@ export default class CompositeDisposable { } function assertDisposable(disposable) { - if (Disposable == null) { - Disposable = require("./disposable") - } - if (!Disposable.isDisposable(disposable)) { throw new TypeError( "Arguments to CompositeDisposable.add must have a .dispose() method" From d49124c7e23e0f5a20363cbaf7cedb103d55e09f Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Mon, 18 Jan 2021 23:25:20 -0600 Subject: [PATCH 03/13] bundle and optimize using parcel --- .gitignore | 1 + .npmignore | 1 + README.md | 13 ++++++++++--- appveyor.yml | 2 ++ babel.config.js | 4 +++- package.json | 18 ++++++++++++++++-- 6 files changed, 33 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 560bd6d..6e042c2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ npm-debug.log api.json dist package-lock.json +.parcel-cache diff --git a/.npmignore b/.npmignore index d4c42e7..84a16ea 100644 --- a/.npmignore +++ b/.npmignore @@ -6,3 +6,4 @@ src npm-debug.log .travis.yml .pairs +.parcel-cache diff --git a/README.md b/README.md index 520e490..f4a73ec 100644 --- a/README.md +++ b/README.md @@ -75,8 +75,15 @@ const {Disposable} = require('event-kit') const disposable = new Disposable(() => this.destroyResource()) ``` -### Using ES6 Code -You can use the ES6 style classes from `lib` directory. +### ES6 Classes +For backward compatibility, the main entry of this package uses prototypical functions instead of classes. To use the version of the code that use classes, there are two options: + +- The bundled code: +``` +const {Disposable, Emitter, CompositeDisposable} = require('event-kit/dist/event-kit.bundle') +``` + +- The source code: ``` -const {Disposable} = require('event-kit/lib/event-kit') +const {Disposable, Emitter, CompositeDisposable} = require('event-kit/lib/event-kit') ``` diff --git a/appveyor.yml b/appveyor.yml index f2985be..bf78a44 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,3 +1,5 @@ +image: Visual Studio 2017 + environment: matrix: - nodejs_version: "10" diff --git a/babel.config.js b/babel.config.js index 873b92c..e37886e 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,6 +1,8 @@ let presets = ["babel-preset-atomic"]; -let plugins = ["@babel/plugin-transform-classes"] // this is needed so Disposabale can be extended by ES5-style classes +let plugins = process.env.PARCEL_ENV + ? [] // the optimized bundle uses ES6 class + : ["@babel/plugin-transform-classes"] // this is needed so Disposabale can be extended by ES5-style classes module.exports = { presets: presets, diff --git a/package.json b/package.json index 5efa0a5..9034dcd 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,11 @@ "version": "2.5.3", "description": "Simple library for implementing and consuming evented APIs", "main": "./dist/event-kit", + "bundle": "./dist/event-kit.bundle.js", "scripts": { - "build": "cross-env BABEL_KEEP_MODULES=false babel lib --out-dir dist --delete-dir-on-start", + "babel": "cross-env BABEL_KEEP_MODULES=false babel lib --out-dir dist --delete-dir-on-start", + "bundle": "cross-env PARCEL_ENV=true cross-env NODE_ENV=production parcel build --target bundle lib/event-kit.js", + "build": "npm run babel && npm run bundle", "docs": "joanna-tello -o api.json package.json lib", "prepublish": "npm run build && npm run docs", "test": "jasmine-focused --captureExceptions --forceexit spec" @@ -23,6 +26,17 @@ "babel-preset-atomic": "^3.0.1", "cross-env": "^7.0.3", "jasmine-focused": "^1.0.7", - "joanna": "https://github.com/aminya/joanna" + "joanna": "https://github.com/aminya/joanna", + "parcel": "^2.0.0-nightly.429" + }, + "targets": { + "bundle": { + "context": "electron-renderer", + "engines": { + "electron": ">=6.x" + }, + "outputFormat": "commonjs", + "isLibrary": true + } } } From fccb4a0768a11e85eb87fe8f221fdbfd937df5a6 Mon Sep 17 00:00:00 2001 From: aminya Date: Fri, 23 Oct 2020 21:49:56 -0500 Subject: [PATCH 04/13] CompositeDisposable: create the set directly from the args Array --- lib/composite-disposable.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/composite-disposable.js b/lib/composite-disposable.js index 5ab8a1b..6113e48 100644 --- a/lib/composite-disposable.js +++ b/lib/composite-disposable.js @@ -29,12 +29,9 @@ export default class CompositeDisposable { */ // Public: Construct an instance, optionally with one or more disposables - constructor() { + constructor(...args) { this.disposed = false - this.disposables = new Set() - for (let disposable of arguments) { - this.add(disposable) - } + this.disposables = new Set(args) } // Public: Dispose all disposables added to this composite disposable. From cd888e3e2c3115567eabef26c8ee6d02e8c479d8 Mon Sep 17 00:00:00 2001 From: aminya Date: Fri, 23 Oct 2020 22:02:14 -0500 Subject: [PATCH 05/13] CompositeDisposable: inline assertDisposable --- lib/composite-disposable.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/composite-disposable.js b/lib/composite-disposable.js index 6113e48..df45e9c 100644 --- a/lib/composite-disposable.js +++ b/lib/composite-disposable.js @@ -58,7 +58,11 @@ export default class CompositeDisposable { add() { if (!this.disposed) { for (const disposable of arguments) { - assertDisposable(disposable) + if (!Disposable.isDisposable(disposable)) { + throw new TypeError( + "Arguments to CompositeDisposable.add must have a .dispose() method" + ) + } this.disposables.add(disposable) } } @@ -87,11 +91,3 @@ export default class CompositeDisposable { } } } - -function assertDisposable(disposable) { - if (!Disposable.isDisposable(disposable)) { - throw new TypeError( - "Arguments to CompositeDisposable.add must have a .dispose() method" - ) - } -} From 6fddb755730a524314b90c247bfbbdcb540fed37 Mon Sep 17 00:00:00 2001 From: aminya Date: Fri, 23 Oct 2020 22:02:54 -0500 Subject: [PATCH 06/13] CompositeDisposable: use ...args instead of arguments --- lib/composite-disposable.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/composite-disposable.js b/lib/composite-disposable.js index df45e9c..f0d9b87 100644 --- a/lib/composite-disposable.js +++ b/lib/composite-disposable.js @@ -55,9 +55,9 @@ export default class CompositeDisposable { // // * `...disposables` {Disposable} instances or any objects with `.dispose()` // methods. - add() { + add(...args) { if (!this.disposed) { - for (const disposable of arguments) { + for (const disposable of args) { if (!Disposable.isDisposable(disposable)) { throw new TypeError( "Arguments to CompositeDisposable.add must have a .dispose() method" From 04a7974cc33b73d63f9952be961fff88cfb9fc77 Mon Sep 17 00:00:00 2001 From: aminya Date: Fri, 23 Oct 2020 22:42:57 -0500 Subject: [PATCH 07/13] CompositeDisposable: use traditional for instead of forEach traditional for is faster: https://jsbench.me/67kgn473ko/1 --- lib/composite-disposable.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/composite-disposable.js b/lib/composite-disposable.js index f0d9b87..b257ac2 100644 --- a/lib/composite-disposable.js +++ b/lib/composite-disposable.js @@ -40,7 +40,11 @@ export default class CompositeDisposable { dispose() { if (!this.disposed) { this.disposed = true - this.disposables.forEach(disposable => disposable.dispose()) + // traditional for is faster: https://jsbench.me/67kgn473ko/1 + const disposablesArray = [...this.disposables] + for (let i = 0, len = disposablesArray.length; i < len; i++) { + disposablesArray[i].dispose(); + } this.disposables = null } } From b65bdd258b25133c93c849978b91f9eb32a710dd Mon Sep 17 00:00:00 2001 From: aminya Date: Sat, 24 Oct 2020 00:22:00 -0500 Subject: [PATCH 08/13] Disposable: use two independent comparisons in isDisposable --- lib/disposable.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/disposable.js b/lib/disposable.js index c8abcc9..e28c8df 100644 --- a/lib/disposable.js +++ b/lib/disposable.js @@ -8,7 +8,7 @@ export default class Disposable { // // Returns a {Boolean} indicating whether `object` is a valid `Disposable`. static isDisposable(object) { - return typeof (object != null ? object.dispose : undefined) === "function" + return Boolean(object) && (typeof object.dispose === "function") } /* From 0057ccf8f59a07e2ba7b426346faeee12bcc9484 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Tue, 19 Jan 2021 00:38:29 -0600 Subject: [PATCH 09/13] Bump Parcel --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9034dcd..3f75a55 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "cross-env": "^7.0.3", "jasmine-focused": "^1.0.7", "joanna": "https://github.com/aminya/joanna", - "parcel": "^2.0.0-nightly.429" + "parcel": "2.0.0-nightly.495" }, "targets": { "bundle": { From 70ce1bb4261c30e058294df4f488786287e5c16b Mon Sep 17 00:00:00 2001 From: aminya Date: Sat, 24 Oct 2020 01:32:13 -0500 Subject: [PATCH 10/13] Emitter: use traditional for in getTotalListenerCount [traditional for is faster](https://github.com/aminya/typescript-optimization#traditional-for-vs-for-of-vs-for-in--looping-ovr-objects) --- lib/emitter.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/emitter.js b/lib/emitter.js index 976f233..27d9bb7 100644 --- a/lib/emitter.js +++ b/lib/emitter.js @@ -248,8 +248,9 @@ export default class Emitter { getTotalListenerCount() { let result = 0 - for (let eventName of Object.keys(this.handlersByEventName)) { - result += this.handlersByEventName[eventName].length + const eventNames = Object.keys(this.handlersByEventName) + for (let i = 0, len = eventNames.length; i < len; i++) { + result += this.handlersByEventName[eventNames[i]].length } return result } From 42361b3e63364b49798bf825d52fa17f9f428b86 Mon Sep 17 00:00:00 2001 From: aminya Date: Sat, 24 Oct 2020 01:37:41 -0500 Subject: [PATCH 11/13] Emitter: use optional chaining to access handlers --- lib/emitter.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/emitter.js b/lib/emitter.js index 27d9bb7..7006f6a 100644 --- a/lib/emitter.js +++ b/lib/emitter.js @@ -212,8 +212,7 @@ export default class Emitter { // for the same name will be invoked. // * `value` Callbacks will be invoked with this value as an argument. emit(eventName, value) { - const handlers = - this.handlersByEventName && this.handlersByEventName[eventName] + const handlers = this.handlersByEventName?.[eventName] if (handlers) { // create a copy of `handlers` so that if any handler mutates `handlers` // (e.g. by calling `on` on this same emitter), this does not result in @@ -226,8 +225,7 @@ export default class Emitter { } emitAsync(eventName, value) { - const handlers = - this.handlersByEventName && this.handlersByEventName[eventName] + const handlers = this.handlersByEventName?.[eventName] if (handlers) { const promises = handlers.map(handler => this.constructor.dispatch(handler, value) From 813282e6db0030de686501abe23d61acbf50ef08 Mon Sep 17 00:00:00 2001 From: aminya Date: Sat, 24 Oct 2020 01:38:39 -0500 Subject: [PATCH 12/13] Emitter: use optional chaining in listenerCountForEventName's return --- lib/emitter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/emitter.js b/lib/emitter.js index 7006f6a..ef68a66 100644 --- a/lib/emitter.js +++ b/lib/emitter.js @@ -241,7 +241,7 @@ export default class Emitter { listenerCountForEventName(eventName) { const handlers = this.handlersByEventName[eventName] - return handlers == null ? 0 : handlers.length + return handlers?.length ?? 0 } getTotalListenerCount() { From 75660c419a07609e7fb8c926709f4dc17983245c Mon Sep 17 00:00:00 2001 From: aminya Date: Sat, 24 Oct 2020 01:39:44 -0500 Subject: [PATCH 13/13] Emitter: cache array's length in emit --- lib/emitter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/emitter.js b/lib/emitter.js index ef68a66..5b109a6 100644 --- a/lib/emitter.js +++ b/lib/emitter.js @@ -218,7 +218,7 @@ export default class Emitter { // (e.g. by calling `on` on this same emitter), this does not result in // changing the handlers being called during this same `emit`. const handlersCopy = handlers.slice() - for (let i = 0; i < handlersCopy.length; i++) { + for (let i = 0, len = handlersCopy.length; i < len; i++) { this.constructor.dispatch(handlersCopy[i], value) } }