Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

babel-plugin-react-transform

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

babel-plugin-react-transform

Babel plugin to instrument React components with custom transforms

  • 1.0.3
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
138K
decreased by-8.32%
Maintainers
1
Weekly downloads
 
Created
Source

babel-plugin-react-transform

This Babel plugin wraps all React components into arbitrary transforms written by the community.
In other words, it lets you instrument React components in any custom way.

Such transforms can do a variety of things:

  • catch errors inside render() like react-transform-catch-errors;
  • enable hot reloading like react-transform-webpack-hmr;
  • render an inline prop inspector like react-transform-debug-inspector;
  • highlight parts of the screen when components update (want to write this one?),
  • etc.

The limit is your imagination and the time you feel compelled to spend on writing these transforms.
Time will show whether it is an amazing, or a terrible idea.

react-transform channel on slack

Demo

Check out react-transform-boilerplate for a demo showing a combination of transforms.

Installation

First, install the plugin:

npm install --save-dev babel-plugin-react-transform

Then, install the transforms you’re interested in:

npm install --save-dev react-transform-webpack-hmr
npm install --save-dev react-transform-catch-errors

Then edit your .babelrc to include extra.react-transform.
It must be an array of the transforms you want to use:

{
  "stage": 0,
  "plugins": [
    "react-transform"
  ],
  "extra": {
    // must be defined and be an array
    "react-transform": [{
      // can be an NPM module name or a local path
      "target": "react-transform-webpack-hmr",
      // see specific transform's docs for "imports" and "locals" it needs
      "imports": ["react"],
      "locals": ["module"]
    }, {
      // you can have many transforms, not just one
      "target": "react-transform-catch-errors",
      "imports": ["react", "redbox-react"]
    }, {
      // can be an NPM module name or a local path
      "target": "./src/my-custom-transform"
    }]
  }
}

As you can see each transform, apart from the target field where you write it name, also has imports and locals fields. You should consult the docs of each individual transform to learn which imports and locals it might need, and how it uses them. You probably already guessed that this is just a way to inject local variables (like module) or dependencies (like react) into the transforms that need them.

Writing a Transform

It’s not hard to write a custom transform! First, make sure you call your NPM package react-transform-* so we have uniform naming across the transforms. The only thing you should export from your transform module is a function.

export default function myTransform() {
  // ¯\_(ツ)_/¯
}

This function should return another function:

export default function myTransform() {
  return function wrap(ReactClass) {
    // ¯\_(ツ)_/¯
    return ReactClass;
  }
}

As you can see, you’ll receive ReactClass as a parameter. It’s up to you to do something with it: monkeypatch its methods, create another component with the same prototype and a few different methods, wrap it into a higher-order component, etc. Be creative!

export default function logAllUpdates() {
  return function wrap(ReactClass) {
    const displayName = // ¯\_(ツ)_/¯
    const originalComponentDidUpdate = ReactClass.prototype.componentDidUpdate;

    ReactClass.prototype.componentDidUpdate = function componentDidUpdate() {
      console.info(`${displayName} updated:`, this.props, this.state);

      if (originalComponentDidUpdate) {
        originalComponentDidUpdate.apply(this, arguments);
      }
    }

    return ReactClass;
  }
}

Oh, how do I get displayName?
Actually, we give your transformation function a single argument called options. Yes, options:

export default function logAllUpdates(options) {

It contains some useful data. For example, your options could look like this:

{
  // the file being processed
  filename: '/Users/dan/p/my-projects/src/App.js',
  // remember that "imports" .babelrc option?
  imports: [React],
  // remember that "locals" .babelrc option?
  locals: [module],
  // all components declared in the current file
  components: {
    $_MyComponent: {
      // with their displayName when available
      displayName: 'MyComponent'
    },
    $_SomeOtherComponent: {
      displayName: 'SomeOtherComponent',
      // and telling whether they are defined inside a function
      isInFunction: true
    }
  }
}

Of course, you might not want to use all options, but isn’t it nice to know that you have access to them in the top scope—which means before the component definitions actually run? (Hint: a hot reloading plugin might use this to decide whether a module is worthy of reloading, even if it contains an error and no React components have yet been wrapped because of it.)

So, to retrieve the displayName (or isInFunction, when available), use the options parameter and the second uniqueId parameter given to the inner function after ReactClass:

export default function logAllUpdates(options) {
  return function wrap(ReactClass, uniqueId) {
    const displayName = options.components[uniqueId].displayName || '<Unknown>';

This is it!

Sure, it’s a slightly contrived example, as you can grab ReactClass.displayName just fine, but it illustrates a point: you have information about all of the components inside a file before that file executes, which is very handy for some transformations.

Here is the complete code for this example transformation function:

export default function logAllUpdates(options) {
  return function wrap(ReactClass, uniqueId) {
    const displayName = options.components[uniqueId].displayName || '<Unknown>';
    const originalComponentDidUpdate = ReactClass.prototype.componentDidUpdate;

    ReactClass.prototype.componentDidUpdate = function componentDidUpdate() {
      console.info(`${displayName} updated:`, this.props, this.state);

      if (originalComponentDidUpdate) {
        originalComponentDidUpdate.apply(this, arguments);
      }
    }

    return ReactClass;
  }
}

Now go ahead and write your own!
Don’t forget to tag it with react-transform keyword on npm.

Ecosystem

Limitations

Currently, it can only locate components of two types: ES6 classes with render method and explicit React.createClass() calls. I’m open to adding more heuristics for other common patterns, given enough interest.

Discussion

You can discuss React Transform and related projects in #react-transform channel on Reactiflux Slack.

Patrons

The work on React Transform, React Hot Loader, Redux, and related projects was funded by the community. Meet some of the outstanding companies that made it possible:

See the full list of React Transform patrons.

License

MIT

Keywords

FAQs

Package last updated on 04 Sep 2015

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc