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

entry-script

v2.1.1

Published

Modular control for entry script execution.

Downloads

509

Readme

npm package License Quality

Contents

Introduction

Modular control for entry script execution.

Many top-level NodeJS executables look something like:

// bin.ts
import express from 'express.js';
import { database } from './my-database.js';
import { middleware } from './my-middleware.js';

await database.connect();

const app = express();
app.use(middleware);

app.listen(3000);

This file is not testable, extendable, or modular because it executes the moment it is loaded. It is not possible to stub methods like database.connect in a test suite.

entry-script solves this by providing a light class to extend and export as default. The internals of EntryScript detect that the class is the top-level script, and kicks off the process.

But during a test environment where it is not the top-level script, nothing is executed! That allows you to mock and inspect methods as necessary to fully test your code.

Install

npm i entry-script

Example

// my-app.ts
import { EntryScript, runtimeError } from 'entry-script';
import express from 'express';
import { database } from './my-database.js';
import { middleware } from './my-middleware.js';

/**
 * All method overrides are optional!
 * Only fill in what you need
 */
export default MyApp extends EntryScript {

    /**
     * Override this method to provide async setup/loading logic
     */
    public static async create() {
        await database.connect();
        return new MyApp(process.env.PORT);
    }

    /**
     * Attach any custom parameters to instance
     */
    constructor(port) {
        super();
        this.port = port;

        // Handle uncaught errors
        this.on(runtimeError, () => {
            process.exitCode = 1;
        });
    }

    /**
     * Override this method for core app logic.
     */
    public async start() {
        const app = express();
        app.use(middleware);

        app.listen(this.port);

        // Also an event emitter!
        this.emit('Listening!', this.port);

        return new Promise((resolve, reject) => {
            // Graceful shutdown
            process.once('SIGTERM', () => {
                resolve();
            });
        });
    }

    /**
     * Override this method to perform any cleanup logic, regardless if `start` threw an error.
     */
    public async finish() {
        await database.disconnect();
    }
}

Now executing node ./my-app.js will start the server as expected!

But import MyApp from './my-app.js'; will return the app class that is ripe for unit/integration testing!

Usage

entry-script is an ESM module. That means it must be imported. To load from a CJS module, use dynamic import const { EntryScript } = await import('entry-script');.

Any class that extends EntryScript must export itself as the default export.

The EntryScript itself extends StaticEmitter for event emitting convenience.

API

EntryScript

Extendable class that control logic flow of an entry point. Will not perform any execution if the entry point for nodejs does not export a child class of EntryScript as default.

run

Available on both the class and instance. Controls script lifecycle.

In general this method should not be called directly, as it is called implicitly by the internal EntryScript lifecycle.

May be called manually when the script is not exposed as the top-level default export.

class MyScript extends EntryScript {
    public start() {
        // Do stuff...
    }
}

// Creates the script and executes
await MyScript.run();

// Create the script manually and execute.
const myScript = await MyScript.create();
await myScript.run();

Methods to override

Each method can call super.<method>() as desired, but the base methods are very basic, often NOOP, logic.

create

Async static method.

Perform any "pre-execution" logic here, such as loading configs or connecting to databases.

Must return an instance of the class, either by calling return new MyClass() directly, or return super.create().

constructor

Normal class constructor.

Customize the properties of the class as appropriate.

start

Async instance method.

Perform most of the business logic here. Once this promise resolves, cleanup will be initialized.

So long-running tasks like servers should return a dangling promise, one that is perhaps only resolved on signal interrupts.

finish

Async instance method.

Perform any "post-execution" logic here, such as disconnecting from databases, or writing final data to disk.

This will be called regardless of the "success" of the start script.

runtimeError

Symbol that will be used as event key on the EntryScript instance whenever start throws an error.

Listening on this event is optional, but recommended for handling unexpected cleanup, or taking options such as setting a failing exit code.