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)

Ionic Package

package-api-diagram-1

The Ionic Package service allows you to create development and production builds of your app that can be submitted to the Apple App Store and Google Play Store, or be installed directly on your friends’, family members’, and colleagues’ devices.

That’s it. Once your build is finished, you just download the distribution file we provide and carry on. Ionic Package takes care of all the heavy lifting and lets you get back to focusing on what really matters: your app.

$ ionic package build ios --profile PROFILE_TAG

The people at Ionic really have gotten this thing directed in the right direction: build an open-source framework and augment it with usefull (soon-to-be commercial) parts such as “Ionic View” and now this “Ionic Package”. It’s tools like this that make it more easy to develop hybrid apps.

If you’re familiar with build servers like Circle-CI or Travis-CI stuff like this – the result of ionic package list – might look familiar:

ionic-package-list

Ionic Package →

Gulp – The streaming build system

gulpjs

gulp.task('sass', function() {
  return gulp.src('src/styles/main.scss')
    .pipe(sass({ style: 'compressed' }))
    .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
    .pipe(gulp.dest('dist/assets/css'))
});

Gulp is a build system and performs tasks such as the ones we do using Grunt: minify, concat, prefix, uglify, etc. Main difference:

Gulp allows you to input your source file(s), pipe them through a bunch of plugins and get an output at the end, rather than configuring each plugin with an input and output—like in Grunt.

Must say that the gulpfile.js embedded below is more readable than its gruntfile.js counterpart where you have to jump through the file when first glancing at it.

Gulp →
Getting started with Gulp →