Menu Search
Jump to the content X X
Smashing Conf Barcelona 2016

We use ad-blockers as well, you know. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. upcoming SmashingConf Barcelona, dedicated to smart front-end techniques and design patterns.

Writing Next Generation Reusable JavaScript Modules in ECMAScript 6

Are you excited to take advantage of new JavaScript language features but not sure where to start, or how? You’re not alone! I’ve spent the better part of the last year and a half trying to ease this pain. During that time there have been some amazing quantum leaps in JavaScript tooling.

These leaps have made it possible for you and me to dive head first into writing fully ES6 modules, without compromising on the essentials like testing, linting and (most importantly) the ability for others to easily consume what we write.

Writing Next Generation Reusable JavaScript Modules1
ECMAScript 6 is here. An overview of fancy and useful features in the new version of JavaScript2.

In this post, we’re going to focus on how to create a JavaScript package written in ES6 that’s usable in a site or app regardless of whether you’re using CommonJS, asynchronous module definition (AMD) or plain browser global modules.

Wait, is it ES6 or ES2015? My habits certainly prefer ES6, but the name was recently and officially changed to ES2015. However, there’s a greater level of awareness of ES6, which is how I will refer to it in this post.

I’d also like to give special thanks to Doug Neiner3 and Ryan Niemeyer4 – both have shared this journey into better ES6 tooling. This post wouldn’t have been possible without them.

The Tools Link

In parts 1 and 2 of this series, we’ll look at some of the tools that make this possible. Today we’ll cover writing, transpiling and packaging our library; and in part 2 we’ll focus on linting, formatting and testing (using JSCS, ESLint, mocha, Chai, Karma and Istanbul). Meet your new best friends for part 1:

  • Babel85 (which just celebrated its first birthday) has made the process of transpiling ES6 to ES5 not only simple, but pleasant.
  • webpack2396 silenced every aspect of the “module wars” on my team by letting us consume everything (CommonJS, AMD and ES6) with aplomb. It turns out that webpack also does a fantastic job of packaging standalone ES6 libraries – a fact we will look at closely during this post.
  • Gulp7 is a powerful tool for automating build-related tasks.

The Goal Link

Write In ES6, Use In ES5 Link

We’re going to talk about writing ES6 client-side libraries, not bundling entire sites or apps. (This is really any reusable bit of code you’d like to share between projects, whether it’s an open source software project or something you use internally at work between applications.) “Wait a second”, you might be thinking. “Won’t it be a while until the browser range I have to support can handle ES6?”

That’s correct! However, I mentioned Babel85 above because we’re going to use it to convert our ES6 to ES5, making it a practical option to use today for most situations.

Make It Easy For Anyone To Consume Link

The second part of our goal is to write a module that we could use in most common module ecosystems. Die-hard AMD fan? You get a module. CommonJS plus browserify the only song you sing? And you get a module. Not sure what the AMD versus CommonJS fuss is about, and you just want to drop the <script> tag on the page and go? You get a module too! It’s a bit like an Oprah module giveaway – where the part of Oprah is played by webpack2396. webpack will help package our module in a special wrapper called a universal module definition (UMD)2210, making it possible to consume in any of the above scenarios.

Setting Up Our Project Link

Over the next few minutes, we’ll be working towards the resulting code here11. I usually start a project off with src/, spec/ and lib/ folders. In our src/ folder, you’ll see a contrived but fun set of example modules that, when used together, let us retrieve a random quote from a Lego Movie12 character. While the behavior is fairly useless, this example makes use of classes13, modules14, const15, destructuring16, a generator17 and more – all features we’d like to safely transpile to ES5.

The main focus of this post is to discuss how to use Babel and webpack to transpile and package an ES6 library. However, I also wanted to take a brief look at our example code so that you can see that we are indeed using ES6.

Note: Don’t worry if you’re new to ES6 syntax. These examples are simple enough to follow.

The LegoCharacter Class Link

In our LegoCharacter.js module, we see the following (be sure to read the comments for more explanation):

// LegoCharacter.js
// Let's import only the getRandom method from utils.js
import { getRandom } from "./utils";

// the LegoCharacter class is the default export of the module, similar
// in concept to how many node module authors would export a single value
export default class LegoCharacter {
   // We use destructuring to match properties on the object
   // passed into separate variables for character and actor
   constructor( { character, actor } ) {
      this.actor = actor;
      this.name = character;
      this.sayings = [
         "I haven't been given any funny quotes yet."
      ];
   }
   // shorthand method syntax, FOR THE WIN
   // I've been making this typo for years, it's finally valid syntax :)
   saySomething() {
      return this.sayings[ getRandom( 0, this.sayings.length - 1 ) ];
   }
}

Pretty boring on its own – this class is meant to be extended, which we do in our Emmet.js module:

// emmet.js
import LegoCharacter from "./LegoCharacter";

// Here we use the extends keyword to make
// Emmet inherit from LegoCharacter
export default class Emmet extends LegoCharacter {
   constructor() {
      // super lets us call the LegoCharacter's constructor
      super( { actor: "Chris Pratt", character: "Emmet" } );
      this.sayings = [
         "Introducing the double-decker couch!",
         "So everyone can watch TV together and be buddies!",
         "We're going to crash into the sun!",
         "Hey, Abraham Lincoln, you bring your space chair right back!",
         "Overpriced coffee! Yes!"
      ];
   }
}

Both LegoCharacter.js and emmet.js are separate files in our project – this will be case for each module in our example. Depending on how you’ve been writing JavaScript, this might seem a bit foreign to you. By the time we’re done, though, we’ll have a ‘built’ version that combines them together.

The index.js Link

Our index.js – another file in our project – is the main entry point for our library. It imports a few Lego character classes, creates instances of them and provides a generator function to yield a random quote any time a caller asks for one:

// index.js
// Notice that lodash isn't being imported via a relative path
// but all the other modules are. More on that in a bit :)
import _ from "lodash";
import Emmet from "./emmet";
import Wyldstyle from "./wyldstyle";
import Benny from "./benny";
import { getRandom } from "./utils";

// Taking advantage of new scope controls in ES6
// once a const is assigned, the reference cannot change.
// Of course, transpiling to ES5, this becomes a var, but
// a linter that understands ES6 can warn you if you
// attempt to re-assign a const value, which is useful.
const emmet = new Emmet();
const wyldstyle = new Wyldstyle();
const benny = new Benny();
const characters = { emmet, wyldstyle, benny };

// Pointless generator function that picks a random character
// and asks for a random quote and then yields it to the caller
function* randomQuote() {
   const chars = _.values( characters );
   const character = chars[ getRandom( 0, chars.length - 1 ) ];
   yield `${character.name}: ${character.saySomething()}`;
}

// Using object literal shorthand syntax, FTW
export default {
   characters,
   getRandomQuote() {
      return randomQuote().next().value;
   }
};

In a nutshell, the index.js module imports lodash, the classes for our three Lego characters and a utility function. It then creates instances of our Lego characters and exports them (makes them available to consuming code) as well as the getRandomQuote method. If all goes well, when this code is transpiled to ES5 it should still do exactly the same thing.

OK. Now What? Link

We have all this shiny new JavaScript, but how do we transpile it to ES5? First, let’s install Babel using npm18:

npm install -g babel

Installing Babel globally gives us a babel command line interface (CLI) option19. If we navigate to our project’s root directory and type this, we can transpile the modules to ES5 and drop them in the lib/ directory:

babel ./src -d ./lib/

Looking at our lib folder, we’ll see these files listed:

LegoCharacter.js
benny.js
emmet.js
index.js
utils.js
wyldstyle.js

Remember how I mentioned above that we were putting each of our ES6 modules into its own file? Babel has taken each of those files, converted them to ES5 and written them to the same file structure in our lib folder. A quick glance at these files might tell you a couple of things:

  • First, these files could be consumed in node right now, as long as the babel/register20 runtime dependency was required first. You’ll see an example of these running in node before the end of this post. (Transpiling typically involves a runtime dependency even though many – but not all – of these features are now available natively in node v421.)
  • Second, we still have some work to do so that these files can be packaged into one file and wrapped in a universal module definition (UMD)2210 and used in a browser.

Enter webpack Link

Odds are you’ve heard of webpack2396, whose description calls it “a bundler for JavaScript and friends.” The most common use case for webpack is to act as a bundler and loader for a website, enabling you to bundle your JavaScript, as well as other assets like CSS and templates, into one (or more) files. webpack has an amazing ecosystem of “loaders,” which are transformations applied to files loaded by webpack. While building a UMD isn’t the most common use case for webpack, it turns out we can use a webpack loader to load our ES6 modules and transpile them to ES5, and webpack’s bundling process to build out a single output file of our example project.

Loaders Link

Used extensively in webpack, loaders can do things like transpile ES6 to ES5, Less to CSS, load JSON files, render templates and much more. Loaders take a test pattern to use for matching files that they should transform. Many loaders can take additional configuration options as well, which we’ll be making use of. (Curious as to what other loaders exist? Check out this list24.)

Let’s go ahead and install webpack globally (which gives us a webpack CLI25):

npm install -g webpack

Next we can install babel-loader26 to our local project. This loader enables webpack to load our ES6 modules and transpile them to ES5. We can install it, and save it to our package.json’s devDependencies by running this:

npm install --save-dev babel-loader

Before we can use webpack, though, we need to create a webpack configuration file that tells webpack what we want it to do with our source files. Usually named webpack.config.js, a webpack configuration file is a node.js module that exports a set of configuration values telling webpack what to do.

Here’s our initial webpack.config.js file. I’ve commented the code heavily, and we’ll also discuss some of the important details below:

module.exports = {
   // entry is the "main" source file we want to include/import
   entry: "./src/index.js",
   // output tells webpack where to put the bundle it creates
   output: {
      // in the case of a "plain global browser library", this
      // will be used as the reference to our module that is
      // hung off of the window object.
      library: "legoQuotes",
      // We want webpack to build a UMD wrapper for our module
      libraryTarget: "umd",
      // the destination file name
      filename: "lib/legoQuotes.js"
   },
   // externals let you tell webpack about external dependencies
   // that shouldn't be resolved by webpack.
   externals: [
      {
         // We're not only webpack that lodash should be an
         // external dependency, but we're also specifying how
         // lodash should be loaded in different scenarios
         // (more on that below)
         lodash: {
            root: "_",
            commonjs: "lodash",
            commonjs2: "lodash",
            amd: "lodash"
         }
      }
   ],
   module: {
      loaders: [
         // babel loader, testing for files that have a .js extension
         // (except for files in our node_modules folder!).
         {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: "babel",
            query: {
               compact: false // because I want readable output
            }
         }
      ]
   }
};

So let’s look at a couple of key values in our configuration.

Output Link

A webpack configuration file can be given an output object that describes how webpack should build and package the source. In our example above, we’re telling webpack to output a UMD library to our lib/ directory.

Externals Link

You might have noticed our example library uses lodash. We want our built library to be smart enough to require lodash from an external source, rather than have to include lodash itself in the output. The externals option in a webpack config file lets you specify the dependencies that should remain external. In the case of lodash, its global property key (_) is not the same as its name (“lodash”), so our configuration above tells webpack how to require lodash for each given module scenario (CommonJS, AMD and browser root).

The Babel Loader Link

You’ll notice that our babel-loader just calls itself “babel” for the loader name. This is a webpack naming convention: where the module name is “myLoaderName-loader”, webpack treats it as “myLoaderName.”

We’re testing for any file ending in .js, except for files that live under our node_modules/ folder. The compact option we’re passing to the babel loader turns off whitespace compression because I’d like our unminified built source to be readable. (We’ll add a minified build in a moment.)

If we run webpack in our console at the project root, it will see our webpack.config.js file and build our library, giving us output similar to this:

» webpack
Hash: f33a1067ef2c63b81060
Version: webpack 1.12.1
Time: 758ms
            Asset     Size  Chunks             Chunk Names
lib/legoQuotes.js  12.5 kB       0  [emitted]  main
    + 7 hidden modules

If we look in our lib/ folder, we’ll see a newly minted legoQuotes.js file. This time, the contents are wrapped in webpack’s UMD, which we can see in this snippet:

(function webpackUniversalModuleDefinition(root, factory) {
   if(typeof exports === 'object' && typeof module === 'object')
      module.exports = factory(require("lodash"));
   else if(typeof define === 'function' && define.amd)
      define(["lodash"], factory);
   else if(typeof exports === 'object')
      exports["legoQuotes"] = factory(require("lodash"));
   else
      root["legoQuotes"] = factory(root["_"]);
})(this, function(__WEBPACK_EXTERNAL_MODULE_1__) {

// MODULE CODE HERE

});

This UMD performs one kind of CommonJS check, then an AMD check, then another style of CommonJS and finally it falls back to plain browser globals. You can see how it knew to look for lodash as “lodash” if we were in a CommonJS or AMD environment, and to look for _ on the window (root) if we were dealing with plain browser globals.

What Happened, Exactly? Link

When we ran webpack in our console, it looked for the default name of a configuration file (webpack.config.js), and read the configuration. From there it saw that the src/index.js file was our main entry point, and began loading it and its dependencies (except for lodash, which we told webpack was external). Each of these dependencies is a .js file, so the babel loader would be run on the file, transpiling it from ES6 to ES5 as it was loaded. From there, all files loaded were written to a single output file, legoQuotes.js, which is dropped into the lib folder.

Looking at the module code you’ll see that our ES6 source has indeed been transpiled to ES5. For example, our LegoCharacter class is now an ES5 constructor function:

// around line 179
var LegoCharacter = (function () {
   function LegoCharacter(_ref) {
      var character = _ref.character;
      var actor = _ref.actor;
      _classCallCheck(this, LegoCharacter);
      this.actor = actor;
      this.name = character;
      this.sayings = ["I haven't been given any funny quotes yet."];
   }

   _createClass(LegoCharacter, [{
      key: "saySomething",
      value: function saySomething() {
         return this.sayings[(0, _utils.getRandom)(0, this.sayings.length - 1)];
      }
   }]);

   return LegoCharacter;
})();

27It’s Usable! Link

At this point we could include this built file in both a browser (IE9+, as a general rule) and node and it would work in either, as long as the babel runtime dependency is included.

If we wanted to use this in the browser, it would look something like this:

<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <title>Lego Quote Module Example</title>
   <link rel="stylesheet" href="style.css">
</head>
<body>
   <div class="container">
      <blockquote id="quote"></blockquote>
      <button id="btnMore">Get Another Quote</button>
   </div>
   <script src="../node_modules/lodash/index.js"></script>
   <script src="../node_modules/babel-core/browser-polyfill.js"></script>
   <script src="../lib/legoQuotes.js"></script>
   <script src="./main.js"></script>
</body>
</html>

You can see we’ve included our legoQuotes.js file (just below babel’s browser-polyfill.js file) just like any other <script> tag (above). Our main.js file, which uses our legoQuotes library, looks like this:

// main.js
( function( legoQuotes ) {
   var btn = document.getElementById( "btnMore" );
   var quote = document.getElementById( "quote" );

   function writeQuoteToDom() {
      quote.innerHTML = legoQuotes.getRandomQuote();
   }

   btn.addEventListener( "click", writeQuoteToDom );
   writeQuoteToDom();
} )( legoQuotes );

To use it in node, it would look like this:

require("babel/polyfill");
var lego = require("./lib/legoQuotes.js");
console.log(lego.getRandomQuote());
// > Wyldstyle: Come with me if you want to not die.

Moving To Gulp Link

Both Babel’s and webpack’s CLIs are very useful, but it’s common to use a task runner such as Gulp to handle executing these kinds of tasks. This consistency can pay off if you participate in many projects, as the main CLI commands you’ll need to remember consist of gulp someTaskName. I don’t think there’s a right or wrong answer here, for the most part. If you prefer the CLIs, use them. Using Gulp is simply one possible way to go about it.

28Setting Up A Build Task Link

First, let’s install gulp:

npm install -g gulp

Next, let’s create a gulp file that can run what we have done so far. We’ll use the webpack-stream29 gulp plugin, which I’ve installed by running npm install --save-dev webpack-stream. This plugin can consume our webpack.config.js file and allow webpack to play nicely with gulp.

// gulpfile.js
var gulp = require( "gulp" );
var webpack = require( "webpack-stream" );

gulp.task( "build", function() {
   return gulp.src( "src/index.js" )
      .pipe( webpack( require( "./webpack.config.js" ) ) )
      .pipe( gulp.dest( "./lib" ) )
} );

Since I’m using gulp to source our index.js and to write to the output directory, I’ve tweaked the webpack.config.js file by removing entry and updating the filename. I’ve also added a devtool30 prop, set to the value of #inline-source-map (this will write a source map at the end of the file in a comment):

// webpack.config.js
module.exports = {
   output: {
      library: "legoQuotes",
      libraryTarget: "umd",
      filename: "legoQuotes.js"
   },
   devtool: "#inline-source-map",
   externals: [
      {
         lodash: {
            root: "_",
            commonjs: "lodash",
            commonjs2: "lodash",
            amd: "lodash"
         }
      }
   ],
   module: {
      loaders: [
         {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: "babel",
            query: {
               compact: false
            }
         }
      ]
   }
};

31What About Minifying? Link

I’m glad you asked! One approach to minifying can be done using the gulp-uglify32 plugin, along with gulp-sourcemaps33 (since we’d like a source map for our min file) and gulp-rename34 (which lets us target a different file name so we don’t overwrite our non-minified build). I’ve added both to our project via:

npm install --save-dev gulp-uglify gulp-sourcemaps gulp-rename

In this approach, our unminified source will still have an inline source map, but our usage of gulp-sourcemaps below will cause the minified file’s source map to be written as a separate file (with a comment in the minified file pointing to the source map file):

// gulpfile.js
var gulp = require( "gulp" );
var webpack = require( "webpack-stream" );
var sourcemaps = require( "gulp-sourcemaps" );
var rename = require( "gulp-rename" );
var uglify = require( "gulp-uglify" );

gulp.task( "build", function() {
   return gulp.src( "src/index.js" )
      .pipe( webpack( require( "./webpack.config.js" ) ) )
      .pipe( gulp.dest( "./lib" ) )
      .pipe( sourcemaps.init( { loadMaps: true } ) )
      .pipe( uglify() )
      .pipe( rename( "legoQuotes.min.js" ) )
      .pipe( sourcemaps.write( "./" ) )
      .pipe( gulp.dest( "lib/" ) );
} );

If we run gulp build in our console, we should see something similar to:

» gulp build
[19:08:25] Using gulpfile ~/git/oss/next-gen-js/gulpfile.js
[19:08:25] Starting 'build'...
[19:08:26] Version: webpack 1.12.1
        Asset     Size  Chunks             Chunk Names
legoQuotes.js  23.3 kB       0  [emitted]  main
[19:08:26] Finished 'build' after 1.28 s

Our lib/ directory will now contain three files: legoQuotes.js, legoQuotes.min.js and legoQuotes.min.js.map. Not only does everyone attending the Oprah webpack show get a module, but they also get a sourcemap to make debugging the minified file a possibility.

35Webpack Banner Plugin Link

If you need to include a licence comment header at the top of your built files, webpack makes it easy. I’ve updated our webpack.config.js file to include the BannerPlugin36. I don’t like hardcoding the banner’s information if I don’t need to, so I’ve imported the package.json file to get the library’s information. I also converted the webpack.config.js file to ES6, and am using a template string37 to render the banner. Towards the bottom of the webpack.config.js file you can see I’ve added a plugins property, with the BannerPlugin as the only plugin we’re currently using:

// webpack.config.js
import webpack from "webpack";
import pkg from "./package.json";
var banner = `
   ${pkg.name} - ${pkg.description}
   Author: ${pkg.author}
   Version: v${pkg.version}
   Url: ${pkg.homepage}
   License(s): ${pkg.license}
`;

export default {
   output: {
      library: pkg.name,
      libraryTarget: "umd",
      filename: `${pkg.name}.js`
   },
   devtool: "#inline-source-map",
   externals: [
      {
         lodash: {
            root: "_",
            commonjs: "lodash",
            commonjs2: "lodash",
            amd: "lodash"
         }
      }
   ],
   module: {
      loaders: [
         {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: "babel",
            query: {
               compact: false
            }
         }
      ]
   },
   plugins: [
      new webpack.BannerPlugin( banner )
   ]
};

(Note: It’s worth mentioning that by converting my webpack.config.js file to ES6, I can’t run it via the webpack CLI any longer.)

Our updated gulpfile.js includes two additions: the requiring of the babel register hook (on line 1) and the passing of options to the gulp-uglify plugin:

// gulpfile.js
require("babel/register");
var gulp = require( "gulp" );
var webpack = require( "webpack-stream" );
var sourcemaps = require( "gulp-sourcemaps" );
var rename = require( "gulp-rename" );
var uglify = require( "gulp-uglify" );

gulp.task( "build", function() {
   return gulp.src( "src/index.js" )
      .pipe( webpack( require( "./webpack.config.js" ) ) )
      .pipe( gulp.dest( "./lib" ) )
      .pipe( sourcemaps.init( { loadMaps: true } ) )
      .pipe( uglify( {
         // This keeps the banner in the minified output
         preserveComments: "license",
         compress: {
            // just a personal preference of mine
               negate_iife: false
            }
      } ) )
      .pipe( rename( "legoQuotes.min.js" ) )
      .pipe( sourcemaps.write( "./" ) )
      .pipe( gulp.dest( "lib/" ) );
} );

38What’s Next? Link

We’re a good way into our journey! So far we’ve stepped through a quick evolution of using babel and webpack’s CLIs to build our library, then moved on to use gulp (and related plugins) to handle the build for us. The code related to this post39 includes an example/ directory with both a browser- and node-based example of our working transpiled module. In our next post, we’ll look at using ESLint and JSCS for linting and formatting, mocha and chai to write tests, Karma to run those tests and istanbul to measure our test coverage. In the meantime, you might want to check out “Designing Better JavaScript APIs40,” a fantastic article that can help guide you in writing better modules.

(rb, jb, ml, og)

Footnotes Link

  1. 1 https://github.com/lukehoban/es6features
  2. 2 https://github.com/lukehoban/es6features
  3. 3 https://twitter.com/dougneiner
  4. 4 https://twitter.com/rpniemeyer
  5. 5 http://babeljs.io/
  6. 6 http://webpack.github.io/
  7. 7 http://gulpjs.com/
  8. 8 http://babeljs.io/
  9. 9 http://webpack.github.io/
  10. 10 https://github.com/umdjs/umd
  11. 11 https://github.com/ifandelse/legoQuotes/releases/tag/v1.0.0
  12. 12 http://www.imdb.com/title/tt1490017/
  13. 13 http://www.2ality.com/2015/02/es6-classes-final.html
  14. 14 http://www.2ality.com/2014/09/es6-modules-final.html
  15. 15 http://www.2ality.com/2015/02/es6-scoping.html
  16. 16 http://www.2ality.com/2015/01/es6-destructuring.html
  17. 17 http://www.2ality.com/2015/03/es6-generators.html
  18. 18 https://docs.npmjs.com/getting-started/installing-npm-packages-globally
  19. 19 http://babeljs.io/docs/usage/cli/
  20. 20 http://babeljs.io/docs/usage/require/
  21. 21 https://nodejs.org/en/docs/es6/
  22. 22 https://github.com/umdjs/umd
  23. 23 http://webpack.github.io/
  24. 24 http://webpack.github.io/docs/list-of-loaders.html
  25. 25 http://webpack.github.io/docs/cli.html
  26. 26 https://www.npmjs.com/package/babel-loader
  27. 27 #its-usable
  28. 28 #build-task
  29. 29 https://www.npmjs.com/package/webpack-stream
  30. 30 http://webpack.github.io/docs/configuration.html#devtool
  31. 31 #minifying
  32. 32 https://www.npmjs.com/package/gulp-uglify
  33. 33 https://www.npmjs.com/package/gulp-sourcemaps
  34. 34 https://www.npmjs.com/package/gulp-rename
  35. 35 #banner-plugin
  36. 36 http://webpack.github.io/docs/list-of-plugins.html#bannerplugin
  37. 37 http://www.2ality.com/2015/01/template-strings-html.html
  38. 38 #whats-next
  39. 39 https://github.com/ifandelse/legoQuotes/releases/tag/v1.0.0
  40. 40 https://www.smashingmagazine.com/2012/10/designing-javascript-apis-usability/
SmashingConf Barcelona 2016

Hold on, Tiger! Thank you for reading the article. Did you know that we also publish printed books and run friendly conferences – crafted for pros like you? Like SmashingConf Barcelona, on October 25–26, with smart design patterns and front-end techniques.

↑ Back to top Tweet itShare on Facebook

Advertisement

Jim Cowart is tragically geeky about JavaScript & open source development...but he's not a fan of lists, so we'll stop there. Having journeyed through Cold Fusion, an obscure proprietary JavaScript BI implementation, C#, a smidgen of Erlang and even some time as a data warehouse architect and developer (apparently he lied to us about not liking lists), he's most passionate about connecting with other developers – learning, sharing and promoting patterns and ideas that will make development more productive, enjoyable and empowering. Jim works at LeanKit as their Web Architect & Web Team Lead and lives in Chattanooga, TN with his wife and three sons.

  1. 1

    Epic article about JavaScript – it hurts my head at times! Thanks for linking out to “Designing Better JavaScript APIs” also, I`ll take a read of that now.

    Richard

    2
  2. 2

    A great article. But i prefer browserify with babel.

    Another thing that was great, if the demonstration / article was executed with JSPM, because it have Babel transpile and other things like minify and the load CSS, JSON and Text File features.

    ;)

    3
  3. 3

    Vladimir Starkov

    February 3, 2016 2:20 am

    you are not able to use Babel itself to compile your modules without any effort. at first you need babel-cli instead, then you need to install babel-preset-es2015 and save it to babel configuration file named .babelrc otherwise Babel will not transpile anything. Yep, Babel v6 is tricky to use. and don’t forget about Babel plugin for adding module.exports as synonym to export default, because es6 modules have a bit different semantic in this case which is not backwards compatible with commonjs modules, this plugin has a name babel-plugin-add-module-exports.

    for my own sanity I created yeoman generator to setup Babel v6 effortlessly in my own projects:
    $ yo babel es2015 # that’s all

    take a look at it here
    https://github.com/iamstarkov/generator-babel/

    21
    • 4

      Vladimir Starkov

      February 9, 2016 7:37 pm

      i just added an option to install plugins as well, so headache-free babel setup now looks like this:

      $ yo babel es2015 -p add-module-exports

      1
  4. 5
  5. 6

    SystemJS not being mentioned at all, unless I misread the article is rather strange. Unlike Webpack, it’s actually more than reasonable for both HTTP/1 & HTTP/2 Web environments. Furthermore it enables dynamic, JIT loading of modules rather than bundling them which is huge for those who are familiar with the benefits of tentative loading scripts during the post-loading stage of applications with older module systems such as AMD.

    SystemJS way of handling modules is so well done, its way of handling things is what has been carried over to the ES6 Loader spec. Even Webpack 2 will adopt its way of handling module loading.

    4
  6. 7

    webpack is capable of minification and generating sourcemaps so the gulp tasks seem like an unnecessary complication in this setup.

    14
  7. 8

    Are you excited to take advantage of new JavaScript language features but not sure where to start, or how? You’re not alone! I’ve spent the better part of the last year and a half trying to ease this pain. During that time there have been some amazing quantum leaps in JavaScript tooling. These leaps have made it possible for you and me to dive head first into writing fully ES6 modules, without compromising on the essentials like testing, linting and (most importantly) the ability for others to easily consume what we write. The post Writing Next Generation Reusable JavaScript Modules in ECMAScript 6 appeared first on Smashing Magazine.

    -4
  8. 9

    Hi Jim, this article is awesome! Thanks a lot for sharing! Is part 2 out yet?

    0
  9. 10

    ES6 is hardly the “next generation JavaScript,” not when it still retains most of JavaScript’s basic, fundamental flaws. I’m trying to push for a proper reform of the JavaScript language: JavaScript: The Next Generation.

    0

↑ Back to top