Skip to content

Using the Plugin Module Loader

Adam Wolfe edited this page Aug 1, 2024 · 1 revision

When you enable plug-ins in Imperative Based CLIs, the Plugin Management Facility (PMF) initializes the Module Loader. The Module Loader provides the correct versions of the Imperative Framework and the Imperative-based CLI to the plug-in that you installed in your Imperative-based CLI.

To provide the correct version, the Module Loader overrides Module.prototype.require, which also overrides require. In short, the Module Loader performs the following actions:

  1. Stores the original mapping of Module.prototype.require for use at a later time. The Module Loader stores the mapping information in a variable named originalRequire.
  2. Overrides Module.prototype.require with a custom method.

After the Module Loader initializes, all further require calls undergo the following logic:

  1. require is intercepted by the Module Loader custom function.

  2. The custom function checks if the require is for the Imperative-based CLI module or the Imperative module.

    Note: When the require is for the Imperative-based CLI module or the Imperative module, the Module Loader remaps the require to the Imperative-based CLI module or the imperative module that is present in the node_modules of the Imperative-based CLI (injected modules).

  3. The originalRequire method is called and returned. Calling and returning the method helps to ensure that require returns the proper module information to the caller.

The above logic lets your plug-in get the injected modules from the runtime location rather than specifying them as a dependency. When you specify the modules as a dependency, the Module Loader never uses them. However, the Module Loader provides the modules as injected modules. As a best practice, we recommend that you specify the injected modules as a devDependency only when you plan to use them.

Example:

The following example illustrates the structures and properties of an Imperative-based CLI and your installed plug-in.

Imperative-based CLI Setup

Consider the following structure of an Imperative-based CLI:

- /root
  - /node_modules
    - /@brightside/imperative
    - /test-pkg
  - package.json
  - /lib
    - main.js
    - index.js
  • Where plugins are enabled.
  • Where /root/lib/index.js is the application code.
  • Where /root/lib/main.js is the cli entrypoint.
  • Where /root/package.json contains:
{
  "name": "some-package-name",
  "bin": {
    "cli-command": "./lib/main.js"
  },
  "main": "lib/index.js",
  "dependencies": {
    "test-pkg": "1.0.0",
    "@brightside/imperative": "2.0.0"
  }
}

Your plug-in Setup

Consider the following structure for your plug-in:

- /plugin-root
  - /node_modules
    - /test-pkg
    - /@brightside/imperative
    - /some-package-name
  - package.json
  - index.js
  • Where /plugin-root/package.json contains:
{
  "name": "some-plugin-name",
  "main": "index.js",
  "dependencies": {
    "test-pkg": "2.0.0"
  },
  "devDependencies": {
    "@brightside/imperative": "2.0.0",
    "some-package-name": "1.0.0"
  }
}
  • Where /plugin-root/index.js contains:
console.log(require.resolve("@brightside/imperative"));
console.log(require.resolve("@brightside/imperative/lib/error"));
console.log(require.resolve("some-package-name"));
console.log(require.resolve("some-package-name/lib/index"));
console.log(require.resolve("test-pkg"));

Issuing the Test

After you install the plug-in that you developed to the Imperative-based CLI, you can issue the following command to invoke /plugin-root/index.js:

cli-command some-plugin-name

The following output displays.

Observe the difference between the output that displays when the Module Loader is disabled and when the Module Loader is enabled.

Module Loader Disabled

/plugin-root/node_modules/@brightside/imperative/lib/index.js
/plugin-root/node_modules/@brightside/imperative/lib/error/index.js
/plugin-root/node_modules/some-package-name/lib/index.js
/plugin-root/node_modules/some-package-name/lib/index.js
/plugin-root/node_modules/test-pkg/index.js

Module Loader Enabled

/root/node_modules/@brightside/imperative/lib/index.js
/root/node_modules/@brightside/imperative/lib/error/index.js
/root/lib/index.js
/root/lib/index.js
/plugin-root/node_modules/test-pkg/index.js

Comparison of Output

As illustrated by the above example, when the Module Loader is disabled, all imports go to the /plugin-root/node_modules folder. In other words, your plug-in must supply the injected modules (Imperative and some-package-name) that are already in the runtime.

When the Module Loader is enabled, the modules are loaded from the existing modules in the runtime. This lets you install your plug-in without having to install the injected modules, which can help reduce download time and consume less disk space. This is done by specifying the injected modules as devDependencies in the package.json for your plug-in, as illustrated in the setup above.