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

hilary

v5.2.0

Published

a simple Dependency Injection (DI) library that provides Inversion of Control (IoC) capabilities in Node.js and the browser

Downloads

125

Readme

hilary.js

Hilary is an easy to use JavaScript Inversion of Control (IoC) container written for Node.js and the browser. Hilary's aim is to deliver low-ceremony dependency injection (DI), to aid in decoupling JavaScript modules and testing. It's named after Hilary Page, who designed building blocks that later became known as Legos.

Also check out generator-hilary, our Yeoman generator, and Gidget our route/app engine.

You can find documentation and examples on the documentation. Below is just a quick-start. There are also lots of examples

If the bootstrapper in the examples that follow looks foreign to you, consider reading about the composition root pattern.

Getting Started with Node.js

Install Hilary:

npm install --save hilary

In this example, we'll produce the following files:

  • api.js: our web server
  • http.js: a platform specific HTTP implementation
  • app.js: our composition root / bootstrapper

Let's start with the web server, api.js, which will simply return "Hello World" when we navigate to localhost:3000.

Modules need to export a name and a factory at a minimum. Checkout Registering Modules for more detailed instructions.

Note that we're not referencing Hilary, yet. There is no need to couple Hilary to your modules. Hilary just expects your modules to export specific properties, such as name, dependencies, and factory.

// api.js
module.exports.name = 'api';
module.exports.factory = function (http) {
    'use strict';

    http.createServer(function (req, res) {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end('Hello World\n');
    }).listen(3000, '127.0.0.1');

    console.log('Server running at http://127.0.0.1:3000/');

    return http;
};

The module above depends on the http module. This is built in to Node.js, and we could start our app now, but let's add our own http module that uses httpsys if we're on a Windows platform.

// http.js
module.exports.name = 'http';
module.exports.factory = function () {
    'use strict';

    if (/^win/.test(process.platform)) {
        // the platform is a flavor of Windows
        // take advantage of the httpsys performance enhancements
        return require('httpsys').http();
    } else {
        // otherwise, stick with the standard http module
        return require('http');
    }
};

Finally, we'll start the app. In app.js (filename is your preference), we'll require Hilary, create a scope, and compose our application, using Hilary's bootstrapper.

// app.js
var scope = require('hilary').scope('myApp');

scope.bootstrap([
    scope.makeRegistrationTask(require('./http.js')),
    scope.makeRegistrationTask(require('./api.js'))
], function (err, scope) {
    if (err) {
        console.log(err);
        return;
    }

    console.log('starting api');
    // In this example, resolving `api` starts our app
    scope.resolve('api');
});

We can now run our example: node app, and navigate to localhost:3000 to see it working.

Getting Started with the Browser

Let's say we're building a simple Hello World bot, that asks for your name, and says hello to you. We also want to be able to choose between two notifiers: alerts, and console logs.

In this example, we'll produce the following files:

  • alertNotifier.js: notifies the user with JavaScript alerts
  • consoleNotifier.js: notifies the user with console logs
  • bot.js: says hello
  • viewModel.js: binds to the DOM
  • app.js: our composition root / bootstrapper
  • index.html: the markup

We'll start with the alert notifier:

Modules need to export a name and a factory at a minimum. Checkout Checkout Registering Modules for more detailed instructions. When using a shim, like module.exports, the scope is also required.

// alertNotifier.js
module.exports = {
    scope: 'myApp',
    name: 'alertNotifier',
    factory: function () {
        'use strict';

        return {
            notify: function (message) {
                alert(message);
            }
        };
    }
};

Then, we'll add a console notifier:

// consoleNotifier.js
module.exports = {
    scope: 'myApp',
    name: 'consoleNotifier',
    factory: function () {
        'use strict';

        return {
            notify: function (message) {
                console.log(message);
            }
        };
    }
};

Next, we'll add a bot module that depends on notifier, to say hello:

Note that the interface of notifier matches both the alertNotifier, and the consoleNotifier, but neither have the name, "notifier". We'll register the module we want to use later.

// bot.js
module.exports = {
    scope: 'myApp',
    name: 'bot',
    dependencies: ['notifier'],
    factory: function (notifier) {
        'use strict';

        return {
            sayHello: function (name) {
                notifier.notify('Hello, ' + name);
            }
        };
    }
};

Since this is a web app, we need to bind to the DOM. Let's create a view model that binds to a text input, and a button:

// viewModel.js
module.exports = {
    scope: 'myApp',
    name: 'viewModel',
    dependencies: ['bot'],
    factory: function (bot) {
        'use strict';

        document.getElementById('submit').addEventListener('click', function() {
            bot.sayHello(document.getElementById('name').value);
        }, false);
    }
};

Finally, we'll compose/bootstrap these modules. We need to register the chosen notifier, and resolve viewModel to bind to the DOM, starting the app:

// app.js
hilary.scope('myApp').bootstrap([
    function (scope, next) {
        scope.register({
            name: 'notifier',
            factory: scope.resolve('alertNotifier')
        });

        next(null, scope);
    }
], function (err, scope) {
    if (err) {
        throw err;
    }

    scope.resolve('viewModel');
    console.log('ready');
});

And here's the markup:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>hilary | Hello World</title>
</head>
<body>
    <label>What is your name?</label>
    <input id="name" type="text" />
    <input id="submit" type="submit" value="submit" />

    <script src="bower_components/polyn/release/polyn.min.js"></script>
    <script src="bower_components/hilary/release/hilary.min.js"></script>
    <script src="bower_components/hilary/release/hilary-browser-module-shim.js"></script>
    <script src="alertNotifier.js"></script>
    <script src="consoleNotifier.js"></script>
    <script src="bot.js"></script>
    <script src="viewModel.js"></script>
    <script src="app.js"></script>

</body>
</html>

What if I already have another module.exports shim?

These examples use a module.exports shim, which isn't required. If you are using another module.exports implementation, you can replace this:

module.exports = {
    scope: 'myApp',
    name: 'myModule',
    factory: function () {}
}

with this:

Hilary.scope('myApp').register({
    scope: 'myApp',
    name: 'myModule',
    factory: function () {}
});

You also could write your own shim, if you don't want to couple your modules to hilary (recommended):

window.customRegister = function (val) {
    if (!val) {
        return;
    }

    if (val.scope) {
        hilary.scope(val.scope).register(val);
    } else {
        console.log(new Error('WARNING: you should always declare a scope when registering hilary modules in a browser (module: ' + val.name + ')'));
        hilary.register(val);
    }
}