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

rw-dynamic-plugin-sdk-webpack

v0.0.7

Published

Based on the concept of [webpack module federation](https://webpack.js.org/concepts/module-federation/), dynamic plugins are loaded and interpreted from remote sources at runtime. The standard way to deliver and expose dynamic plugins to Console is throug

Downloads

1

Readme

OpenShift Console Dynamic Plugins

Based on the concept of webpack module federation, dynamic plugins are loaded and interpreted from remote sources at runtime. The standard way to deliver and expose dynamic plugins to Console is through OLM operators.

Dynamic plugins are decoupled from the Console application, which means both plugins and Console can be released, installed and upgraded independently from each other. To ensure compatibility with Console and other plugins, each plugin must declare its dependencies using semantic version ranges.

See the OpenShift Console Dynamic Plugins feature page for a high level overview of dynamic plugins in relation to OLM operators and cluster administration.

Example project structure:

dynamic-demo-plugin/
├── src/
├── console-extensions.json
├── package.json
├── tsconfig.json
└── webpack.config.ts

SDK packages

| Package Name | Description | | --- | --- | | @openshift-console/dynamic-plugin-sdk | Provides core APIs, types and utilities used by dynamic plugins at runtime. | | @openshift-console/dynamic-plugin-sdk-webpack | Provides webpack plugin ConsoleRemotePlugin used to build all dynamic plugin assets. | | @openshift-console/dynamic-plugin-sdk-internal | Internal package exposing additional code. | | @openshift-console/dynamic-plugin-sdk-host-app | Provides APIs, Component, and utilities for host applications i.e reducers, actions, etc | | @openshift-console/dynamic-plugin-sdk-internal-kubevirt | Internal package to support KubeVirt plugin migration. |

package.json

Plugin metadata is declared via the consolePlugin object.

{
  "name": "dynamic-demo-plugin",
  "version": "0.0.0",
  "private": true,
  // scripts, dependencies, devDependencies, ...
  "consolePlugin": {
    "name": "console-demo-plugin",
    "version": "0.0.0",
    "displayName": "Console Demo Plugin",
    "description": "Plasma reactors online. Initiating hyper drive.",
    "exposedModules": {
      "barUtils": "./utils/bar"
    },
    "dependencies": {
      "@console/pluginAPI": "*"
    }
  }
}

consolePlugin.name is the plugin's unique identifier. It should be the same as metadata.name of the corresponding ConsolePlugin resource used to represent the plugin on the cluster. Therefore, it must be a valid DNS subdomain name.

consolePlugin.version must be semver compliant.

Dynamic plugins can expose modules representing additional code to be referenced, loaded and executed at runtime. A separate webpack chunk is generated for each entry in consolePlugin.exposedModules object. Exposed modules are resolved relative to plugin's webpack context option.

The @console/pluginAPI dependency is mandatory and refers to Console versions this dynamic plugin is compatible with. The consolePlugin.dependencies object may also refer to other dynamic plugins that are required for this dynamic plugin to work correctly.

See ConsolePluginMetadata type for details on the consolePlugin object and its schema.

console-extensions.json

Declares all extensions contributed by the plugin.

[
  {
    "type": "console.flag",
    "properties": {
      "handler": { "$codeRef": "barUtils.testHandler" }
    }
  },
  {
    "type": "console.flag/model",
    "properties": {
      "flag": "EXAMPLE",
      "model": {
        "group": "kubevirt.io",
        "version": "v1alpha3",
        "kind": "ExampleModel"
      }
    }
  }
]

Depending on extension type, the properties object may contain code references, encoded as object literals { $codeRef: string }. When loading dynamic plugins, encoded code references are transformed into functions () => Promise<T> used to load the referenced objects.

The $codeRef value should be formatted as either moduleName.exportName (referring to a named export) or moduleName (referring to the default export). Only the plugin's exposed modules (i.e. the keys of consolePlugin.exposedModules object) may be used in code references.

Webpack config

Dynamic plugins must be built with webpack in order for their modules to seamlessly integrate with Console application at runtime. Use webpack version 5+ which includes native support for module federation.

All dynamic plugin assets are managed via webpack plugin ConsoleRemotePlugin.

const { ConsoleRemotePlugin } = require('@openshift-console/dynamic-plugin-sdk-webpack');

const config = {
  // 'entry' is optional, but unrelated to plugin assets
  plugins: [new ConsoleRemotePlugin()],
  // ... rest of webpack configuration
};

export default config;

ConsoleRemotePlugin has no configuration options; it automatically detects your plugin's metadata and extension declarations and generates the corresponding assets.

Generated assets

Building the above example plugin produces the following assets:

dynamic-demo-plugin/dist/
├── plugin-entry.js
├── plugin-manifest.json
└── utils_bar_ts-chunk.js

plugin-manifest.json: dynamic plugin manifest. Contains both metadata and extension declarations to be parsed and interpreted by Console at runtime. This is the first plugin asset loaded by Console.

plugin-entry.js: webpack container entry chunk. Provides asynchronous access to specific modules exposed by the plugin. Loaded right after the plugin manifest.

utils_bar_ts-chunk.js: webpack chunk for the exposed barUtils module. Loaded via the plugin entry chunk when needed.

Plugin development

Run Bridge locally and instruct it to proxy e.g. /api/plugins/console-demo-plugin requests directly to your local plugin asset server (web server hosting the plugin's generated assets):

./bin/bridge -plugins console-demo-plugin=http://localhost:9001/

Your plugin should start loading automatically upon Console application startup. Inspect the value of window.SERVER_FLAGS.consolePlugins to see the list of plugins which Console loads upon its startup.

Plugin detection and management

Console operator detects available plugins through ConsolePlugin resources on the cluster. It also maintains a cluster-wide list of currently enabled plugins via spec.plugins field in its config (Console resource instance named cluster).

When the spec.plugins value in Console operator config changes, Console operator computes the actual list of plugins to load in Console as an intersection between all available plugins vs. plugins marked as enabled. Updating Console operator config triggers a new rollout of the Console (Bridge) deployment. Bridge reads the computed list of plugins upon its startup and injects this list into Console web page via SERVER_FLAGS object.

Disabling plugins in the browser

Console users can disable specific or all dynamic plugins that would normally get loaded upon Console startup via disable-plugins query parameter. The value of this parameter is either a comma separated list of plugin names (disable specific plugins) or an empty string (disable all plugins).

Runtime constraints and specifics

  • Loading multiple plugins with the same name (but with a different version) is not allowed.
  • Console will override certain modules to ensure a single version of React etc. is loaded and used by the application.
  • Enabling a plugin makes all of its extensions available for consumption. Individual extensions cannot be enabled or disabled separately.
  • Failure to resolve a code reference (unable to load module, missing module export etc.) will disable the plugin.

Publishing SDK packages

To see the latest published version of the given package:

yarn info <package-name> dist-tags --json | jq .data.latest

Before publishing, it's recommended to log into your npm user account:

npm login

Build all distributable SDK packages into dist directory:

yarn build

Finally, publish relevant packages to npm registry:

yarn publish dist/<pkg> --no-git-tag-version --new-version <version>

If the given package doesn't exist in npm registry, add --access public to yarn publish command.