Cobwwweb logo

Export ES6 Class Globally with Webpack

Dec 01, 2018 ES6, JavaScript, Webpack

In a previous article on distributing JavaScript libraries I used an example that uses Webpack to build (and Babel to transpile) an ES6 class and expose it as a global variable.

Most of this process came from an article on this very subject.

That articles states that there are only a few steps. I'll demonstrate those steps quickly with my HelloWorld example:

The Process

Let's say my main file is src/index.js, which looks like this:

src/index.js

import { HelloWorld } from './components/hello-world';
module.exports = HelloWorld;

And my component looks like this:

src/components/hello-world.js

export class HelloWorld {

  static log() {
    console.log('Hello world!')
  }

  static write() {
    document.body.append('Hello World!')
  }

}

To make this class globally available I have to adjust my webpack config slightly:

webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'hello-world.js',
    path: path.resolve(__dirname, 'dist'),
    libraryTarget: 'var',
    library: 'HelloWorld'
  }
}

I add two extra lines:

The Problem

That's where the article got me, but there's a problem with it today. It causes this error:

Cannot assign to read only property 'exports' of object '#<Object>'

Essentially what that means is you can't mix ES6 imports with CommonJS exports.

The Fix

The thing is we need the CommonJS export for this to work. So, what do we do? Change the import to require so both use CommonJS. The most important piece, though, is that we append .default to the require so that we attach the ES6 module directly to the variable (as opposed to nested within its default object).

So, index.js changes to:

src/index.js

const HelloWorld = require('./components/hello-world').default;
module.exports = HelloWorld;

And the component's class name isn't necessary, so we can do this:

src/components/hello-world.js

export default class {
  // ...
}

Now you can build and see the bundle available globally as HelloWorld, effectively exposing the two static methods in my example (log() and write()) direct on the HelloWorld object.

In other words, if you were to load the resulting bundle on a website, you'd have access to run both static methods like so:

HelloWorld.log(); // Logs "Hello World!" to the console.
HelloWorld.write(); // Appends "Hello World!" to the DOM's body.

Did you learn something or find this article interesting?

If so, why not