npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

hot-container

v1.2.0

Published

Dependency injection container with hot-reloading for Node.js

Downloads

9

Readme

hot-container

Dependency injection container with hot-reloading for Node.js.

Introduction

A dependency injection container is an object which knows how to create other objects or functions. These objects or functions can be composed using other objects or functions, called dependencies.

Each object or function managed by the container is defined as a separate Node.js module, i.e. a file with a .js or .json extension, located in a specific directory. It can be either a plain Node.js module, or a special dynamic module which exports a constructor function and an array of dependencies. The dependencies are automatically resolved by the container and injected into the constructor.

When the hot-reloading feature is enabled, the container tracks file changes and automatically reloads modified modules. All objects or functions which depend on the modified modules are also automatically re-created. This is especially useful during development, making it possible to modify the application code on-the-fly without having to restart it. Hot-reloading can be disabled in production mode to reduce resource usage.

Installation

$ npm install hot-container

Usage

Creating a container

const hotContainer = require( 'hot-container' );

const container = hotContainer( {
  root: __dirname,
  dir: 'modules',
  aliases: {
    config: 'data/config.json',
    utils: 'utils'
  },
  watch: true,
  verbose: true
} );

Options:

  • root - the path of the root directory; the default value is the directory containing the current entry script
  • dir - the directory, relative to root, containing modules which are loaded by the container; the default value is '.'
  • aliases - an object which defines file and directory aliases (see the aliases section below)
  • watch - when enabled, modified modules are automatically reloaded; the default value is true
  • verbose - when enabled, debugging information is printed to the console; the default value is false

Dynamic modules

A module which depends on other modules is defined in the following way:

const deps = [ 'db', 'log' ];

function init( db, log ) {
  return function() { ... };
}

module.exports = { deps, init };

The deps array specifies the dependencies of the module. The init function is called with resolved dependencies as arguments. It should return the module instance, i.e. the object or function which can be then retrieved from the container or injected as a dependency of another module.

Static modules

The container can also load simple modules without any dependencies. In that case the module instance should be directly exported from the module:

module.exports = function() { ... };

Retrieving a module instance

Use the get( name ) method to get the instance of the specified module:

const handler = container.get( 'handler' );
if ( handler != null )
  handler( request, response, next );

If the module or one of its dependencies cannot be loaded or initialized, null is returned. See the error handling section below for information about handling errors.

Note that modules are only loaded and initialized when they are needed, i.e. when get() is called. For hot-reloading to work, make sure that get() is called on every request or event processed by the application, in order to get an up-to-date instance of the module.

Use the exists( name ) method to check if a module exists without actually loading it:

if ( container.exists( 'handler' ) {
  const handler = container.get( 'handler' );
  // ...
}

In this case get() can still return null in case of an error.

Programmatic registration

Use the register( name, instance ) method to add an object or function directly to the container:

container.register( 'foo', function() { ... } );

The registered object or function can then be used as a dependency of a dynamic module or retrieved from the container using get().

The container can be registered in itself:

conainer.register( 'container', container );

This makes it possible for modules to access the container, for example in order to retrieve an instance of another module on demand, rather than during initialization.

Error handling

Use the on( name, listener ) method to register an error handler:

container.on( 'error', err => console.error( err ) );

If no error handler is registered, the application will be aborted when an error occurs.

Destroying a module

A dynamic module can export an optional destroy() function:

let timer = null;

const deps = [ 'one', 'two' ];

function init( one, two ) {
  timer = setTimeout( function() { ... }, 1000 );
  return function() { ... };
}

function destroy() {
  if ( timer != null ) {
    clearTimeout( timer );
    timer = null;
  }
}

module.exports = { deps, init, destroy };

This function is called when the module or one of its dependencies are modified. It should clean up any external resources, such as timers, file handles, etc.

Note that a module is destroyed immediately when a modification is detected, but it's not initialized again until it's needed.

Use the destroy() method of the container to destroy all modules:

container.destroy();

Stopping the container

Use the stop() method to stop watching modified files:

container.stop();

Note that the application will keep running as long as the container is watching files.

Module metadata

A dynamic module can optionally export additional properties which describe the module:

const description = 'This is my module.';

const deps = [ 'one', 'two' ];

function init( one, two ) {
  return ...;
}

module.exports = { description, deps, init };

Use the meta( name ) function to get these metadata:

const handler = container.get( 'handler' );
const meta = container.meta( 'hanler' );
console.log( meta.description ); // prints 'This is my module.'

Note that meta() will return null is the module wasn't initialized, so you must call get() first.

Aliases

When passing options to the container, you can define aliases to access files or directories outside of the default dir directory. For example:

const container = hotContainer( {
  aliases: {
    config: 'data/config.json',
    utils: 'utils'
  }
} );

In this case, when 'config' is used as the module name, the container will load the data/config.json file. When the module name is prefixed with 'utils/', for example 'utils/log', it will load files from the 'utils' directory.

The alias paths can be absolute or relative to the root directory.