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

react-plugins

v0.3.1

Published

Use your react component's as plugins!

Downloads

8

Readme

react-plugins

Use your react components as plugins. Register them from anywhere in your application, and render them wherever you want implicitely!

NPM JavaScript Style Guide

NOTE: This plugin is still in development, and it's API may change between two versions, check out the releases page for updates. This notice will be removed once the package reaches a stable version

Motivation

When managing large-scale apps, sometimes it might be needed to render components defined in some part of your app (a module, a particular feature, etc.) in another part of the application. The most concrete example is:

  • Your application has many modules, which can be enabled/disabled
  • Your application has a sidebar that displays a small widget for each module enabled

In this setup, it would clutter the Sidebar component if it needed to require each widget from each module, like this:

// src/Sidebar.tsx

import BillingWidget from './modules/billing';
import UsersWidget from './modules/users';
import AdminWidget from './modules/admin';
// ... other widget imports

const Sidebar = () => (
  <>
    <BillingWidget />
    <UsersWidget />
    <AdminWidget />
    {/* ... other widgets */}
  </>
);

With this package, you can simply make your modules register the widgets as plugins in the sidebar section, and simply ask the sidebar to display the registered plugins

// src/modules/billing
PluginStore.registerPlugin('sidebar', BillingWidget, 'billing-widget');

// src/modules/users
PluginStore.registerPlugin('sidebar', UsersWidget, 'users-widget');

// src/modules/admin
PluginStore.registerPlugin('sidebar', AdminWidget, 'admin-widget');

// src/Sidebar.tsx
const Sidebar = () => <Plugins section='sidebar' />;

Demo

A basic demo showcasing the main features of this plugin is available at https://lmerotta.github.io/react-plugins/ Code is located in the example folder

Install

npm install --save react-plugins

Features

  • Render components outside of the current parent component
  • Register components at runtime
  • Supports lazy loading

Example Usage

Create a pluginStore

// src/pluginStore.ts
import { PluginStore } from 'react-plugins';

const store = new PluginStore();

export default store;

Define a component as you'd normally do

// src/MyComponent.tsx
const MyComponent = () => <div>Hello, world!</div>;

export default MyComponent;

Register your component as a plugin, and wrap your application with the PluginStoreProvider

// src/index.tsx
import { PluginStoreProvider } from 'react-plugins';
import ReactDOM from 'react-dom';
import App from './App';
import MyComponent from './MyComponent';
import store from './pluginStore';

store.registerPlugin('body', MyComponent, 'MyComponent', 10);

ReactDOM.render(
  <PluginStoreProvider store={store}>
    <App />
  </PluginStoreProvider>,
  document.getElementById('root')
);

Ask your app to render the plugins for the body section, with the Plugins component.

// src/index.tsx
import { Plugins } from 'react-plugins';

const App = () => (
  <div>
    <h1>
      Below are the plugins registered in the <b>body</b> section of the
      PluginStore
    </h1>
    <Plugins section='body' />
  </div>
);

Advanced usage

Lazy-loading with Suspense

Instead of importing your component and registering it as is, you can use React.lazy to import it dynamically.

// src/index.tsx
import { lazy, Suspense } from 'react';
import { PluginStoreProvider } from 'react-plugins';
import ReactDOM from 'react-dom';
import App from './App';
import store from './pluginStore';

store.registerPlugin(
  'body',
  lazy(() => import('./MyComponent')),
  'MyComponent',
  10
);

ReactDOM.render(
  <Suspense fallback='Loading...'>
    <PluginStoreProvider>
      <App />
    </PluginStoreProvider>
  </Suspense>,
  document.getElementById('root')
);
// src/index.tsx
import { Plugins } from 'react-plugins';

const App = () => (
  <div>
    <h1>
      Below are the plugins registered in the <b>body</b> section of the
      PluginStore
    </h1>
    <Plugins section='body' />
  </div>
);

### Registering plugins with props

react-plugins supports registering plugins that are components with props, simply by passing the JSX instead of the component declaration:

store.registerPlugin(
  'body',
  <MyComponent prop='value' secondProp={10} />,
  'MyComponent',
  10
);

### Updating plugins

When you register a plugin, you can update it whenever you want. This allows you for example to update it's props. Simply passe then new component to registerPlugin by specifying the same section and name as the previous one:

store.registerPlugin(
  'body',
  <MyComponent prop='value' secondProp={10} />,
  'MyComponent',
  10
);

// later...

store.registerPlugin(
  'body',
  <MyComponent prop='secondValue' secondProp={125} />,
  'MyComponent',
  10
);

Registering plugins at runtime

Plugins can be registered either before the initial rendering, or from inside another component.

const MyPluginHandler = () => {
  const [pluginProp, setPluginProp] = useState('value');

  // register or update the plugin whenever pluginProp changes
  useEffect(() => {
    store.registerPlugin(
      'body',
      <MyComponent prop={pluginProp} />,
      'MyComponent',
      10
    );
  }, [pluginProp]);

  return (...);
}

// in another file


const App = () => <Plugins section="body" />; // will receive MyComponent and display it

API

PluginStore

registerPlugin(section, component, name, priority)

Registers a plugin to be used in the application

  • section: The section this plugin will appear in
  • component: Either a component definition, or a component instance
  • name: a unique name to identify this component in the section it will appear in
  • priority: used to sort the plugins. A plugin with a higher priority will appear last. Lower priority comes first

removePlugin(section, name)

Removes a plugin from the given section, thus unmounting it if rendered anywhere

  • section: the section where the plugin is registered
  • name: the plugin to remove's name

PluginStoreProvider

Used to make your application aware of the plugins registered

Props

store (PluginStore) The store that will be used to retrieve plugins from

Plugins

Used to render plugins registered in a particular section

Props

section (string) The section to look for plugins. This component will render any plugin found in the given section, sorted by priority in ascending order

usePlugins

Retrieve all plugins ready to render. returns an array of JSX elements that can be mapped and rendered

arguments

section (string) The section to look for plugins. Will return all the components from this section, ready to render

Roadmap

  • [x] Remove global PluginStore and make PluginStoreProvider accept a pluginStore as parameter
  • [x] usePlugins hook to retrieve plugins and leave rendering to the user

License

MIT © lmerotta