How to create a npm module that works on browser with webpack 2

The JavaScript ecosystem goes so fast that it's really hard to keep track of everything. I remember 3 years, I had some hard time to understand fully Grunt, and realized right after that the new thing was Gulp. Finally once Gulp understood, everybody was taking about webpack.

I didn't catch the webpack train though. I was pretty happy with Gulp. But since the new 2.0 version came out on February, I though it would be nice to try it out. Plus, I wanted to learn how to build JavaScript modules that work on the browser from a Node.js ES6 version. So here we go.

1. The idea

Nothing too serious. We are just going to redo the sum function.

2. The folder structure

Here is how I structured my folder.

.
├── dist
├── lib
│   └── add.js
├── .babelrc
├── package.json
└── webpack.config.js

dist is the browser module destination once compiled. The lib (sometimes named src too) folder will have all the sources. .babelrc will have the Babel configuration. package.json not need to introduce this one. And finally the webpack.config.js which is the config file for webpack.

To generate a package.json by default, don't hesitate to use the command npm init -f. And then install all the dependencies like so :

npm install --save-dev babel-core babel-loader babel-preset-env babel-preset-es2015 jest webpack  

3. Coding

Something too existing as I said. The file lib/add.js is like that:

const add = (a, b) => {  
  return a + b;
};

module.exports = add;

4. Always make tests

Writing tests is important, I always use Mocha so let's try this new trendy thing : Jest.

You just need to add a add.test.js file next to your add.js

const add = require('./add');

test('should return 10 when value (3, 7)', () => {  
  expect(add(3, 7)).toBe(10);
});

test('should return 25 when value (20, 5)', () => {  
  expect(add(20, 5)).toBe(25);
});

In our package.json, we write the npm test script to use Jest.

{
  "name": "add",
  "version": "1.0.0",
  "description": "Just a add function",
  "main": "lib/add.js",
  "scripts": {
    "test": "jest",
    "build": "webpack"
  },
  "license": "MIT",
  "devDependencies": {
    "babel-core": "^6.23.1",
    "babel-loader": "^6.4.0",
    "babel-preset-env": "^1.2.1",
    "babel-preset-es2015": "^6.22.0",
    "jest": "^19.0.2",
    "webpack": "^2.2.1"
  }
}

We can now launch the test with npm run test and see that everything is ok.

5. Webpack to generate our browser compatible module

Our module works great with Node.js. But now we want to compile it in order to use it on all browser. Since all the browsers don't support ES6 we have to transpile it to ES5.

In the `webpack.config.js``

webpack.config.js

4 important properties here:

  • entry which is our source file.

  • output which is our out file. We tell webpack where do we want the output file and that we want it with the Universal Module Definition

  • module we tell webpack to use Babel to tranpile our js file

  • plugins and we use the built-in Uglifier.

Last thing is to tell Babel that we use ES6 code, so in the .babelrc

npm install --save-dev babel-core babel-loader babel-preset-env babel-preset-es2015 jest webpack  

We can now generate our browser module version with the npm run build command.

lib/add.js

Our module is complete. We can test our add.min.js file. Go inside the dist folder and create a index.html file with this content :

<!DOCTYPE html>  
<html>  
  <head>
    <meta charset="utf-8">
    <title></title>
    <script src="/add.min.js" charset="utf-8"></script>
  </head>
  <body>
    10 + 3 = <span id="result"></span>
  </body>
  <script type="text/javascript">
    document.getElementById('result').innerHTML = add(10, 3);
  </script>
</html>  

To see the result to a

python -m SimpleHTTPServer

You can see at http://localhost:8000 that everything is working properly.

You are no ready to publish your npm modules and use them anywhere, on your server or your navigator.

You can find all the source of this article here: https://github.com/codeKonami/npm-module-starter

Thomas Foricher

Read more posts by this author.