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-mutate

v1.0.0

Published

Easily add user-defined extensions into your react application

Downloads

15

Readme

React Mutate is a tool that lets you swap out nodes in React's virtual DOM. The main use case is to allow end-users the ability to write and add extensions (what we call mutations) to a React application.

Disclaimer

I have 0 idea if this is actually a good idea. Take everything with a grain of salt. My team and I are testing this out for our project, Aurora.

This is really early in development We've really only partially tested this out yet, so I would probably not use it in production yet.

The API will probably change a lot. This project could be abandoned entirely. North Korea could invade France. We could discover flying pigs in a cave somewhere. 🐷✈️ You never know what's gonna happen.

Double Disclaimer

A lot of the recent strategies for implementing this have been heavily inspired by how Hyper does it's extensions (since they also use HOC's as an extension strategy). Hyper is super cool and you should really check it out!

Install

With yarn

yarn add @react-mutate/core @react-mutate/loader

With npm

npm install --save @react-mutate/core @react-mutate/loader

Overview

React-Mutate is a series of packages that work with each other to let you do the following:

  1. Allow users to create mutations (or extensions/plugins) as React HOC's.
  2. Let them store those mutations as npm modules.
  3. Load them in and then apply them to various nodes in your React virtual DOM.

Building an extension

A typical extension that your user will write can be just one code file. You should name it index.js or you can create a node project with a package.json and then point the main attribute to be the name of your file.

Your file should export a "mutations" attribute that is an object where the keys are the components you would like to modify and the values are React HOC functions that modify their keys.

For example, here, I want to make all the <Text /> in this application bold. So I'll write an index.js file that has a Text function that will take in a component and return it wrapped in bold tags.

/* index.js */
module.exports.mutations = {
  Text: Component => (
    <b>
      {" "}
      <Component />{" "}
    </b>
  )
};

Then, once I'm done, I can go and upload it to NPM with npm publish. @react-mutate/loader can help project owners easily install and load in npm projects as mutations.

Installing user extensions

Next, you'll integrate this into your app with react-mutate.

Then, on your app, you can use @react-mutate/loader to install these npm packages for each user.

import { installMutations } from "@react-mutate/loader";

// Installs a bunch of extensions in some folder for user data
installMutations(
  ["some", "list", "of", "npm", "modules"],
  "path/to/save/files"
);

Loading user extensions

Then later, you can load in those modules with loadMutations as a JSON object.

import { loadMutations } from "@react-mutate/loader";

const mutations = await loadMutations("path/to/save/files");

Integrating user extensions into React

You can wrap your app with a <MutationsProvider /> and put those mutations you got from loadMutations in as a prop like so:

import { MutationsProvider } from "@react-mutate/core";

/* ... Somewhere inside your root level React component **/
render() {
    return (
        <MutationsProvider mutations={mutations}>
            <App/>
        </MutationsProvider>
    )
}

Specifying which items can be extended

Then, inside your App you can specify which components you would like to be extendable with mutate like so:

// Text.js
import { Mutate } from "@react-mutate/core";

// Some React component
const Text = ({ children }) => <p>{children}</p>;

export default mutate(Text, "Text");

Passing in an API

If you would like to pass in some functions, you can use the third optional parameter of mutate:

const API = () => {
  Foo: () => {
    console.log("Hello I am a function");
  };
};

const Text = ({ children }) => <p>{children}</p>;

export default mutate(Text, "Text", API);

If you're using redux, you may not need this.

With redux, you can just pass functions via mapDispatchToProps, which may help you give specific components access only to certain apis.

import { doFoo } from "./actions";

const Text = ({ children }) => <p>{children}</p>;

const mapDispatchToProps = dispatch => {
  return {
    Foo: () => dispatch(doFoo)
  };
};

export default connect(null, mapDispatchToProps)(mutate(Text, "Text"));

Mutations vs Extensions

We've chosen to call these mutations instead of extensions because they work differently. With React mutations, a user can write an extension for another extension.

For example, it's entirely possible to have an extension list that looks like this:

const userExtension = {
  Base: withAlpha,
  WithAlpha: withBeta,
  WithBeta: withGamma
  // and so on...
};

Also, mutations don't need to render the existing code. Traditional JS extensions might just add the extension's JS directly onto the existing base, which can lead to slowdown. Mutations will render INSTEAD of the existing code.

(Though it will still load in the code, so it'll still be larger and less efficient than no extensions)

Mutations also allow you to explicitly say what things are easily mutable and what things are not. This lets you clearly define your API and also incrementally add in extensibility to your applicaiton.