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

@connect211/react-pluggable

v0.4.3

Published

### 1) Introduction

Downloads

1

Readme

React Pluggable

1) Introduction

React Pluggable: A plugin system for JS & React apps

While React itself is a plugin system in a way, it focuses on the abstraction of the UI. It is inherently declarative which makes it intuitive for developers when building UI. With the help of React Pluggable, we can think of our app as a set of features instead of a set of components. It provides a mixed approach to solve this problem.

We at GeekyAnts have used React Pluggable for large & complex apps like BuilderX to add independent and dependent features over time, and it has worked wonderfully for us. Find out more on our official documentation.

2) Motivation

In React, we think of everything as components. If we want to add a new feature, we make a new component and add it to our app. Every time we have to enable/disable a feature, we have to add/remove that component from the entire app and this becomes cumbersome when working on a complex app where there are lots of features contributed by different developers.

We are a huge fan of Laravel and love how Service Provider works in it. Motivated by how we register any service for the entire app from one place, we built a plugin system that has all your features and can be enabled/disabled with a single line of code.

React Pluggable simplifies the problem in 3 simple steps:

  1. To add a new feature in your app, you write it's logic and install it in the plugin store.
  2. You can use that feature anywhere in the app by calling that feature using PluginStore rather than importing that feature directly.
  3. If you do not want a particular plugin in your app, you can uninstall it from your plugin store or just comment out the installation.

3) Features

  • Open-closed Principle

The O in SOLID stands for Open-closed principle which means that entities should be open for extension but closed for modification. With React Pluggable, we can add plugins and extend a system without modifying existing files and features.

  • Imperative APIs for Extensibility

React is inherently declarative which makes it intuitive for developers when building UI but it also makes extensibility hard.

  • Thinking Features over Components

React abstracts components very well but a feature may have more than just components. React Pluggable pushes you to a feature mindset instead of a component mindset.

4) Installation

Use npm or yarn to install this to your application:

npm install react-pluggable
yarn add react-pluggable

5) Usage

  • Making a plugin

ShowAlertPlugin.tsx

import React from 'react';
import { IPlugin, PluginStore } from 'react-pluggable';

class ShowAlertPlugin implements IPlugin {
  public pluginStore: any;

  getPluginName(): string {
    return 'ShowAlert';
  }

  getDependencies(): string[] {
    return [];
  }

  init(pluginStore: PluginStore): void {
    this.pluginStore = pluginStore;
  }

  activate(): void {
    this.pluginStore.addFunction('sendAlert', () => {
      alert('Hello from the ShowAlert Plugin');
    });
  }

  deactivate(): void {
    this.pluginStore.removeFunction('sendAlert');
  }
}

export default ShowAlertPlugin;`
  • Adding it to your app

App.tsx

import React from 'react';
import './App.css';
import { createPluginStore, PluginProvider } from 'react-pluggable';
import ShowAlertPlugin from './plugins/ShowAlertPlugin';
import Test from './components/Test';

const pluginStore = createPluginStore();
pluginStore.install(new ShowAlertPlugin());

const App = () => {
  return (
    <PluginProvider pluginStore={pluginStore}>
      <Test />
    </PluginProvider>
  );
};

export default App;
  • Using the plugin

Test.tsx

import * as React from 'react';
import { usePluginStore } from 'react-pluggable';

const Test = () => {
  const pluginStore = usePluginStore();

  return (
    <>
      <button
        onClick={() => {
          pluginStore.executeFunction('sendAlert');
        }}
      >
        Show Alert
      </button>
    </>
  );
};

export default Test;
  • Using the inbuilt renderer

Sometimes a plugin has a UI component associated with it. You can implement this functionality by simply building a plugin of your own or using the default plugin provided by the package.

SharePlugin.tsx

import React from 'react';
import { IPlugin, PluginStore } from 'react-pluggable';

class SharePlugin implements IPlugin {
  public pluginStore: any;

  getPluginName(): string {
    return 'Share plugin';
  }

  getDependencies(): string[] {
    return [];
  }

  init(pluginStore: PluginStore): void {
    this.pluginStore = pluginStore;
  }

  activate(): void {
    this.pluginStore.executeFunction('RendererPlugin.add', 'top', () => (
      <button>Share</button>
    ));
  }

  deactivate(): void {
    //
  }
}

export default SharePlugin;

You can add the inbuilt renderer plugin by importing and installing RendererPlugin provided in the package.

  • Importing the plugin

App.tsx

import \* as React from 'react';
import { usePluginStore } from 'react-pluggable';
import {
createPluginStore,
PluginProvider,
RendererPlugin,
} from 'react-pluggable';
import SharePlugin from './plugins/SharePlugin';
import Test from './components/Test';

const pluginStore = createPluginStore();
pluginStore.install(new RendererPlugin());
pluginStore.install(new SharePlugin());

function App() {
return (
<PluginProvider pluginStore={pluginStore}>
<Test />
</PluginProvider>
);
}

export default App;

Test.tsx

import \* as React from 'react';
import { usePluginStore } from 'react-pluggable';

const Test = (props: any) => {
const pluginStore: any = usePluginStore();

let Renderer = pluginStore.executeFunction(
'RendererPlugin.getRendererComponent'
);

return (
<>
<h1>I am header</h1>
<Renderer placement={'top'} />
</>
);
};

export default Test;

6) Examples

Here are some examples of React Pluggable:

7) Tech Stack

Javascript & React.

8) Naming Conventions

Although the naming of plugins, functions, or events is not an enforced rule, we recommend a few conventions to standardize things.

  1. Plugin Name: Let's consider a plugin which provides authentication, named as Auth.
  2. Class Name: The name of the class will be your plugin name suffixed with 'Plugin' i.e. AuthPlugin.
  3. getPluginName: When returning the name of the plugin, we add <plugin_name> with @, followed by the version. ex : [email protected] (<plugin_name>@).
  4. Adding functions: While functions can be added to pluginStore with any name, to ensure uniqueness across plugins, we recommend the format <plugin_name>.<function_name>. Ex : Auth.authenticate.
  5. Events: Events can be added and dispatched from pluginStore using any name. To show which event belongs to which plugin, we recommend the format <plugin_name>.<event_name> Ex: Auth.checking.

Example :

AuthPlugin.tsx

import React from 'react';
import { IPlugin, PluginStore } from 'react-pluggable';

class AuthPlugin implements IPlugin {
  getPluginName(): string {
    return '[email protected]'; //line 2
  }

  getDependencies(): string[] {
    return [];
  }

  public pluginStore: any;

  init(pluginStore: PluginStore): void {
    this.pluginStore = pluginStore;
  }

  authenticate = (credentials: object) => {
    // checks the credentials and returns username if matches.
    return { name: 'username' };
  };

  activate(): void {
    this.pluginStore.addFunction(
      'Auth.authenticate', //line 3
      (credentials: object) => this.authenticate(credentials)
    );
  }

  deactivate(): void {
    this.pluginStore.removeFunction('Auth.authenticate'); //line 4
  }
}

export default AuthPlugin;

We have seen in the class AuthPlugin that the name of the plugin is used several times. An alternate way is to define a variable that stores the name of the plugin and use that variable in the class wherever we want the plugin name.

AuthPlugin

import React from 'react';
import { IPlugin, PluginStore } from 'react-pluggable';

class AuthPlugin implements IPlugin {
  private namespace = 'Auth';

  getPluginName(): string {
    return `${this.namespace}@1.0.0`; //line 2
  }

  getDependencies(): string[] {
    return [];
  }

  public pluginStore: any;

  init(pluginStore: PluginStore): void {
    this.pluginStore = pluginStore;
  }

  authenticate = (credentials: object) => {
    // checks the credentials and returns username if matches.
    return { name: 'username' };
  };

  activate(): void {
    this.pluginStore.addFunction(
      `${this.namespace}.authenticate`, //line 3
      (credentials: object) => this.authenticate(credentials)
    );
  }

  deactivate(): void {
    this.pluginStore.removeFunction(`${this.namespace}.authenticate`); //line 4
  }
}

export default AuthPlugin;

9) Contributors

10) How to Contribute

Thank you for your interest in contributing to React Pluggable! Pull requests are welcome. Head over to Contribution Guidelines and learn how you can be a part of a wonderful, growing community.

For major changes, please open an issue first to discuss changes and update tests as appropriate.

11) License

Licensed under the MIT License, Copyright © 2020 GeekyAnts. See LICENSE for more information.