• This repository has been archived on 09/Apr/2020
  • Stars
    star
    1,080
  • Rank 42,846 (Top 0.9 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created about 9 years ago
  • Updated about 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Babel plugin to instrument React components with custom transforms

This Project Is Deprecated

React Hot Loader 3 is on the horizon, and you can try it today (boilerplate branch, upgrade example). It fixes some long-standing issues with both React Hot Loader and React Transform, and is intended as a replacement for both. The docs are not there yet, but they will be added before the final release. For now, this commit is a good reference.

babel-plugin-react-transform

react-transform channel on discord

🚀 Now with Babel 6 support (thank you @thejameskyle!)

This plugin wraps React components with arbitrary transforms. In other words, it allows you to instrument React components in any way—limited only by your imagination.

🚧🚧🚧🚧🚧

This is highly experimental tech. If you’re enthusiastic about hot reloading, by all means, give it a try, but don’t bet your project on it. Either of the technologies it relies upon may change drastically or get deprecated any day. You’ve been warned 😉 .

This technology exists to prototype next-generation React developer experience. Please don’t use it blindly if you don’t know the underlying technologies well. Otherwise you are likely to get disillusioned with JavaScript tooling.

No effort went into making this user-friendly yet. The goal is to eventually kill this technology in favor of less hacky technologies baked into React. These projects are not long term.

Table of Contents

Ecosystem

For a reference implementation, see react-transform-boilerplate.
For a starter kit to help write your own transforms, see react-transform-noop.

Transforms

Feeling inspired? Learn how to write transforms and send a PR!

Demo Project

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

Installation

This plugin is designed to be used with the Babel 6 ecosystem. These instructions assume you have a working project set up. If you do not have Babel set up in your project, learn how to integrate it with your toolkit before installing this plugin.

Using NPM

Install plugin and save in devDependencies:

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

Install some transforms:

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

Add react-transform to the list of plugins in your babel configuration (usually .babelrc):

{
  "presets": ["react", "es2015"],
  "env": {
    // this plugin will be included only in development mode, e.g.
    // if NODE_ENV (or BABEL_ENV) environment variable is not set
    // or is equal to "development"
    "development": {
      "plugins": [
        // must be an array with options object as second item
        ["react-transform", {
          // must be an array of objects
          "transforms": [{
            // can be an NPM module name or a local path
            "transform": "react-transform-hmr",
            // see transform docs for "imports" and "locals" dependencies
            "imports": ["react"],
            "locals": ["module"]
          }, {
            // you can have many transforms, not just one
            "transform": "react-transform-catch-errors",
            "imports": ["react", "redbox-react"]
          }, {
            // can be an NPM module name or a local path
            "transform": "./src/my-custom-transform"
          }]
          // by default we only look for `React.createClass` (and ES6 classes)
          // but you can tell the plugin to look for different component factories:
          // factoryMethods: ["React.createClass", "createClass"]
        }]
      ]
    }
  }
}

As you can see, each transform, apart from the transform 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.

Note that when using React.createClass() and allowing babel to extract the displayName property you must ensure that babel-plugin-react-display-name is included before react-transform. See this github issue for more details.

You may optionally specify an array of strings called factoryMethods if you want the plugin to look for components created with a factory method other than React.createClass. Note that you don’t have to do anything special to look for ES6 components—factoryMethods is only relevant if you use factory methods akin to React.createClass.

Writing Transforms

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.

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

More Repositories

1

react-hot-loader

Tweak React components in real time. (Deprecated: use Fast Refresh instead.)
JavaScript
12,257
star
2

overreacted.io

Personal blog by Dan Abramov.
JavaScript
7,053
star
3

react-hot-boilerplate

Minimal live-editing example for React
JavaScript
3,905
star
4

react-transform-boilerplate

A new Webpack boilerplate with hot reloading React components, and error handling on module and component level.
JavaScript
3,372
star
5

whatthefuck.is

An opinionated glossary of computer science terms for front-end developers. Written by Dan Abramov.
CSS
3,008
star
6

react-makes-you-sad

Here’s a flowchart to make you happy again!
Makefile
2,093
star
7

react-document-title

Declarative, nested, stateful, isomorphic document.title for React
JavaScript
1,866
star
8

flux-react-router-example

A sample app showcasing Flux with React Router
JavaScript
1,431
star
9

react-side-effect

Create components whose nested prop changes map to a global side effect
JavaScript
1,217
star
10

suspense-experimental-github-demo

Sample project built with Suspense to demonstrate render-as-you-fetch
JavaScript
807
star
11

todos

Examples for “Idiomatic Redux”: one branch per lesson
JavaScript
802
star
12

react-transform-hmr

A React Transform that enables hot reloading React classes using Hot Module Replacement API
JavaScript
779
star
13

subliminal

An opinionated minimalistic VS Code theme for JavaScript
632
star
14

react-proxy

Proxies React components without unmounting or losing their state
JavaScript
459
star
15

react-pure-render

[No Maintenance Intended] A function, a component and a mixin for React pure rendering
JavaScript
451
star
16

redux-devtools-dock-monitor

A resizable and movable dock for Redux DevTools monitors
JavaScript
405
star
17

library-boilerplate

An opinionated boilerplate for React libraries including ESLint, Mocha, Babel, Webpack and an example powered by Webpack Dev Server and React Hot Loader
JavaScript
386
star
18

redux-devtools-log-monitor

The default monitor for Redux DevTools with a tree view
JavaScript
310
star
19

react-blessed-hot-motion

A console app demo using React for rendering, animation, and hot reloading
JavaScript
281
star
20

react-lag-radar

JavaScript
272
star
21

promise-loader

A webpack bundle-loader ripoff with promise interface
JavaScript
216
star
22

react-transform-catch-errors

React Transform that catches errors inside React components
JavaScript
184
star
23

react-elmish-example

My personal attempt at understanding Elm architecture
HTML
170
star
24

react-deep-force-update

Force-updates React component tree recursively
JavaScript
122
star
25

the-redux-journey

Slides from my talk at React Europe 2016
JavaScript
89
star
26

react-hot-api

(Deprecated) A generic library implementing hot reload for React components without unmounting or losing their state
JavaScript
88
star
27

gitbook-plugin-prism

Gitbook plugin for Prism highlighting
JavaScript
85
star
28

react-stateful

[No Maintenance Intended] A higher-order React component for lifting state
JavaScript
84
star
29

workshop

React Europe 2016 workshop repo
JavaScript
84
star
30

react-transform

A specification for tools instrumenting React components
68
star
31

disposables

Disposables let you safely compose resource disposal semantics
JavaScript
64
star
32

base16-js

Base16 themes in JS
JavaScript
35
star
33

redux-devtools-themes

Color themes for Redux DevTools monitors
JavaScript
34
star
34

react-for-beginners

This is my cloned version of the Wes Bos Series.
CSS
21
star
35

hooks-perf-issues

This repo demonstrates a situation where it is slower to use React hooks than classes
JavaScript
15
star
36

sc-bug-repro

CSS
15
star
37

testcomp

JavaScript
10
star
38

myapp

just testing lol
JavaScript
10
star
39

tictactoe

A LINQy TicTacToe implementation in C# for StackOverflow
C#
8
star
40

test.react.dev

(Work in progress) React documentation website in Test Test TEst
6
star
41

playtronica

A side project for a friend
JavaScript
5
star
42

redux-bootstrap

Bootstrapping function for Redux applications.
TypeScript
5
star
43

react-dnd-example

JavaScript
4
star
44

draft-js-borked

JavaScript
4
star
45

react-dnd-touch-backend

Touch Backend for react-dnd
JavaScript
3
star
46

gaearon.github.io

Oh hi.
HTML
3
star
47

jest-babel-issue

HTML
2
star
48

react-webpack

A starter template for building with React, Gulp and Webpack
JavaScript
2
star
49

jest-mock-issue-repro

JavaScript
2
star
50

rn-bug-loop

Kotlin
2
star
51

ulonkaFrontend01

JavaScript
1
star
52

HtmlWebpackReplaceManifestAssetsPlugin

A subplugin of the HtmlWebpackPlugin for replacing, in a html template, the assets with theis hashed versions
JavaScript
1
star