Distributing your React Component as a Standalone Version


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();

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: [
			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)