reflecter

0.6.0 • Public • Published

reflecter

The reflector supports reflection utilities for node.js with no- to little impact on runtime performance. It support a short list of features:

  • Works in node.js
  • Creates metadata at runtime:
    • Loaded Modules - all files that have been required with require()
    • Loaded Packages - all top-level packges with package.json and loaded packges one-level deep
    • For exported class, associates the module and package that loaded it for introspection
  • Live source reloading

Installation

npm install --save reflecter

Usage

// To enable, set the RELOAD_ENABLED environment variable
// export RELOAD_ENABLED=

require('reflecter');

Reflector only needs to be required


// const MyClass = require('./mymodule');
let myItem = new MyClass();

// Find information about this item, from package.json
const pack = myItem.constructor.$runtime.package;
pack.name;        // name from package.json
pack.version;     // version from package.json
pack.modules;     // all loaded files from package

// Find information about the class
const module = this.constructor.$runtime.module;
module.file;      // file name that defines this class
module.package;   // package for module
module.reload();  // reloads file if changed

Live Source Reloading

Reflecter supports live reloading of source files into the runtime upon file save. It uses fs.watch() to observe when source files change in the load path whether Javascript or transpiled language (Typescript) an reloads the source without restarting the server and affecting application state.

const runtime = require('reflecter');
// Reloading is now live for current and future source file edits if 
// environment variable is set:
// export RELOAD_ENABLED=

runtime.isReloadEnabled           // -> true if RELOAD_ENABLED env variable set
runtime.setReloadEnabled(false);  // Halts source loading
runtime.setReloadEnabled(true);   // (Re)starts source loading
  • No need to restart server to reload source
  • Redefines exported symbols and ES6 classes
  • Existing instances of classes adopt new methods and properties
  • Reflector tracks version number in MyClass.$runtime.version
  • Enable using RELOAD_ENABLED environment variable
  • Enable programmatically using runtime.setReloadEnabled(true)

Usage Scenarios

  • Speed development
    Modify running servers and applications without restarts.
  • Change source without debugger restart
    Stay in the debugger longer. Reflecter plays well with debuggers, allowing you to edit and save changes to source while debugging.
  • Make changes in long running node servers
    Without restarting, reduce restarts and downtime. Apply emergency patches.

How does it work?

Reflector's runtime watches all file changes in top-level source directories (ones not inside a node_modules directory). Any time a loaded source file is modified, Reflecter walks through module.exports looking for redefinable symbols, primarily classes, exports of classes, then copies all property definitions, both static and prototype, from the new definiton into all previous definitions of the class/symbol. This is so that all instances created on prior definitions get to take advantage of the updated implementation, along with accurate debugging line numbers.

If there's a probem when the file is reloaded, such as syntax error, it happens! The existing loaded symbols are left intact.

Caveats

  • Hard bindings to event handlers or timers won't use the new implementation since the binding is at bind() time not call time

    • Instead of
      stream.on('data', this.readData.bind(this)); write:
      stream.on('data', data => this.readData(data));

    • Instead of
      setInterval(this.reload.bind(this), 10e3); write
      setInterval(() => this.reload(), 10e3);


Runtime Class

const runtime = require('reflecter');
runtime.packages; // all loaded packages

Properties

  • packages (Object<string,Package>)

    Current set of packages with at least one module loaded. The package provides information sucn as all loaded modules within the package and information inside the package.json file. See the Package

  • modules (Object<string,Module>)

    All loaded modules. Modules provide access to the Package it is contained within as well as exported type information.

  • main (Module)

    The main module or program entry. To find the main package use runtime.main.package

  • locals (Object<string,Package>)

    Local packages, i.e. packages not loaded through node_modules

  • isReloadEnabled (boolean) & setReloadEnabled()

    Whether the source reloader is enabled

Methods

  • runtime.package(abspath)
    runtime.package(class)
    runtime.package(object)

    • path (string) – the directory for the package class (class) – A class, or
      object (object) – An instance of a class
    • returns (Package)

    This overloaded method returns the Package for the directory or the packagke that defines the class or object's constructor.

  • runtime.module(abspath)
    runtime.module(class)
    runtime.module(object)

    • path (string) – the directory for the module class (class) – A class, or
      object (object) – An instance of a class
    • returns (Module)

    Returns the Module for the file, class or object.

Events

  • reloaded(path, module)

    • path (string) – the file path of the file
    • module (Module) - the reloaded module definition

    Emitted when a source file at the given path has been reloaded.

  • package(path, package)

    • path (string) – the directory path of the package
    • package (Package) – package definition loaded

    Emitted when a new package is loaded.

  • module(path, module)

    • path (string) – the file path of the loaded module
    • module (Module) - the loaded module definition

    Emitted when a new module is loaded.

  • watching(dir, package)

    • dir (string) – the director being watched
    • package (Package) - the watching package

    Emitted when a package is being watched

  • unwatched(dir, package)

    • dir (string) – the director being watched
    • package (Package) - the watching package

    Emitted when a package is no longer being watched


Package class

// ./index.js
const runtime = require('reflecter');
const pack = runtime.package(__dirname) ;
pack.modules; // -> all loaded modules/source files

Represents a package or any local directory with a package.json.

Properties

  • name (string)

    The basename of the package, such as "reflecter".

  • dir (string)

    The absolute path of the direcory package.

  • info (object)

    The contents of the package.json for the package or null if there's no package.json listed in the dir.

  • modules (Object<string,Module>)

    Loaded modules in the package including keyed by the relative file path such as 'lib/file.js'. See the Module

  • dependencies (Object<string,Package>)

    A map of package dependences as loaded at runtime, as distinct from what's listed in package.json.


Module class

// ./my-class.js
class MyClass {

  // Get the version from package.json
  packageVersion() {
    const metadata = this.constructor.$runtime;
    return metadata.package.info.version;
  }

}

// Get information about a class
const runtime = require('reflector');
const module = runtime.module(MyClass);
module.file; // file name of the class
module.reload(); // reload if changed

Represents a loaded source file

Properties

  • file (string)

    The absolute path of the source file

  • stat (fs.Stat)

    The latest stat for the filea

  • package (Package)

    The package in which this module is contained. See Package

  • version (number)

    The runtime version of this module, incremented every time this module is reloaded and has symbols to redefine

  • types (Object<string,function|class>)

    A flatten list of reloadable exported symbols in the module. This is the list of symbols defined by the runtime.

Methods

  • module.reload()

    Reloads the module programmically. If the file has not changed since the last reload, this method does nothing.

Dependencies (0)

    Dev Dependencies (2)

    Package Sidebar

    Install

    npm i reflecter

    Weekly Downloads

    3

    Version

    0.6.0

    License

    Apache-2.0

    Unpacked Size

    77.8 kB

    Total Files

    15

    Last publish

    Collaborators

    • kloshih