Distributing your React Component as a Standalone Version

react-opti

At work we’ve been building quite some stuff on top of React the past few months. We use Grunt (and more recently Webpack) to run browserify with the babelify transform to transpile our ES6 code into ES5.

Earlier this week I came to the point where I wanted to distribute a built component as a standalone .js file, for inclusion in the browser by 3rd party developers (in case they don’t know React themselves, or use ES5, or just don’t want to include the component’s source).

Building that standalone version comes with a few prerequisites:

  1. No copy of react nor react-dom should be included in the component itself – just like a jQuery plugin does not include jQuery itself but relies on it being available instead.
  2. The contained classes should be accessible on a single namespace to the 3rd party developer.

That way an implementer could include the component as follows:

<-- Include react and react-dom -->
<script type="text/javascript" src="/libs/react/15.2.1/react.js"></script>
<script type="text/javascript" src="/libs/react/15.2.1/react-dom.js"></script>

<-- Include the Component -->
<script type="text/javascript" src="/script/my-react-component.js"></script>

<-- Use the Component -->
<script type="text/javascript">
  var c = new MyComponent.Player();
</script>

To get this working, I had to make a few adjustments into the build script:

  1. Prevent both the react and react-dom packages from being included into my distributable file, using browserify’s external option. This option will tell browserify to not try and include react/react-dom whenever it encounters an import/require() for one of those packages, but to trust us to them being available.
  2. Transform all import/require() calls for react/react-dom to use the external (global) copies of React, using the browserify-global-shim transform for Browserify.
  3. Define a (global) namespace into which all of my classes will become available, using browserify’s standalone option.

Puzzling all pieces together, our browserify Grunt task to build the standalone/distrubutable version looks like this:

{
	dist: {
		src: ['src/index.js'],
		dest: 'dist/my-react-component.js',
		options: {
			watch: false,
			external: [
				'react',
				'react-dom',
			],
			transform: [['babelify', {
				presets: ['react', 'es2015'],
				compact: false,
				plugins: ['transform-class-properties', 'transform-object-rest-spread', 'add-module-exports']
			}], ['browserify-global-shim', {
				"react": "React",
				"react-dom": "ReactDOM"
			}]],
			browserifyOptions: {
				extensions: ['.js'],
				debug: false,
				standalone: 'MyComponent'
			}
		}
	}
}

In summary:

  1. options.external prevents react/react-dom from being included locally into the dist file itself,
  2. The entry browserify-global-shim (along with its own options) in options.transform wires the import/require() calls for react/react-dom to the global versions as the local versions don’t exist,
  3. options.browserifyOptions.standalone defines the namespace which gets exported globally.
Did this help you out? Like what you see?
Consider donating.

I don’t run ads on my blog nor do I do this for profit. A donation however would always put a smile on my face though. Thanks!

☕️ Buy me a Coffee ($3)

Published by Bramus!

Bramus is a frontend web developer from Belgium, working as a Chrome Developer Relations Engineer at Google. From the moment he discovered view-source at the age of 14 (way back in 1997), he fell in love with the web and has been tinkering with it ever since (more …)

Unless noted otherwise, the contents of this post are licensed under the Creative Commons Attribution 4.0 License and code samples are licensed under the MIT License

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.