Thursday, July 28, 2016

Expose an ES2015 Module as a Global with Browserify (react-addons-update)

Calling the React setState() method within TypeScript in Visual Studio Code requires that all properties of the state object are set in the parameter to that method. That was proving a nuisance when there are a few state properties, so I decided to use the update addon available in React - that allows for a much simpler command such as
let newState = update(this.state, {
    message: {$set: "Success!"}
});
this.setState(newState);
Adding the react-addons-update module without any other changes to the build operations in gulp caused the content of that addon to be included in the bundled JS when processed by browserify.

That additional content can be excluded from the bundled JS by these adjustments:
  1. Use the "external()" method on browserify to remove it from the bundle
        let bundler =  browserify({
                entries: config.rootJS,
                debug: true //This provides sourcemapping
            })  //Initialising browserify
            .external(['react', 'react-addons-update', 'react-dom', 'react-router']);
    
  2. Add a shim entry in the package.json file to map a global name to the addon
      "browserify-shim": {
        "react": "global:React",
        "react-addons-update": "global:React_Addons_Update",
        "react-dom": "global:ReactDOM",
        "react-router": "global:ReactRouter"
      }
    
  3. Create an additional JavaScript file containing the ES2015 addon code transpiled to E5
That last stage required a new gulp task, passing the file "update.js" file from the React source to browserify.

However, that new bundled file for the addon did not expose a global name that could be used within my custom bundle. The key to exposing this global name proved to be adding the "standalone" parameter in the browserify call (line 6 in the code below).
gulp.task('packageReactAddons', () => {

    let bundler =  browserify({
            entries: 'node_modules/react/lib/update.js',
            debug: false,
            standalone: 'React_Addons_Update'
        });

    return bundler.bundle()
        .on('error', console.error.bind(console))
        .pipe(source('react_addons_update.js')) // Pass desired output file name to vinyl-source-stream
        .pipe(gulp.dest(config.librariesOutputPath)); // Destination for the bundle
})
After uploading the resulting JS file to a page, I could see the object named "React_Addons_Update" in the global name space of the page. Yeah!

No comments: