Choosing a Module Bundler for ng2

Datetime:2016-08-23 00:27:37          Topic: Webpack  AngularJS           Share

This blog post will give you an overall picture of modular javascript. We will discuss some of the popular JS module bundlers and its comparison along with the implementation in context of Angular2 .

Yes, angular2 !! why ? — When I started with angular2 I was bit confused which one should I use for bundling and loading modules.

The basic tutorial In the official site is using SystemJS and they have written ” SystemJS happens to be a good choice but we want to be clear that it was a choice and not a preference.”

Webpackis one of the most popular JS bundler in today’s date, so we will compare it’s implementation with the SystemJS ’s implementation, try to figure out the one we should go with angular2 and also inspect some of the good features of other module systems available in the market.

Let’s begin with some of the Basics

What is modular JavaScript ?

In general, when we say modular programing, it means the code is composed of a set of highly decoupled, distinct pieces of functionality stored in modules.

Why modular JavaScript?

There are numerous reason why authors divides their books into chapters and sections. These division makes it easier for reader to see how the book is built up and to find the specific parts that they are interested in. They also help the author by providing a clear focus for every sections.

Similarly writing the code in modular structure makes it highly maintainable, scalable by removing dependencies where possible. When this is implemented efficiently, it’s quite easy to see how changes to one part of a system may affect another.

Need for JS Module Bundler :

Today’s websites are evolving into web apps:

* More and more JavaScript is in a page.

* You can do more stuff in modern browsers.

* Again everybody is going for SPA (Single Page Application).

As a result there is a lot of code on the client side!

So if we didn’t use any module bundler, then probably this is the way we would handle a modularized code base.

 <scriptsrc=”module1.js”></script>
 <scriptsrc=”module2.js”></script> 
 <scriptsrc=”libraryA.js”></script>
 <scriptsrc=”module3.js”></script>

Common problems if we use the above method,

  • Conflicts in the global object.
  • Order of loading is important.
  • No of request increases which will impact the performance in terms of loading time.
  • Developers have to resolve dependencies of modules/libraries.
  • In big projects the list can get really long and difficult to manage.

Yes!! This is where module system came to picture as a saviour :).

Popular module systems available and their comparison:

The below link will provide you a clear picture on comparison of popular module systems.

https://webpack.github.io/docs/comparison.html

Before going into the implementation with Angular2, we will just look at some of the key differences in Angular2 from Angular 1.x, which can be factors to decide the module system we should go with for Angular2.

Angular 2 vs Angular 1.x

  1. Angular 2 is entirely component based, so every unit is a module.
  2.  It is written entirely in Typescript and meets the ECMAScript 6 specification.
    • TypeScript is an extension of ECMAScript,
      in fact: TypeScript = ES6 + Types + Annotations
    • TypeScript will not be used in the browser. The program code is compiled to JavaScript.

It is not mandatory to use TypeScript in Angular 2, but clearly all parts of your code will be more elegant if you do.

We will start with webpack implementation.

Webpack Implementation:

Here is my package.json file,

{
 “name”: “angular2-webpack-sample”,
 “version”: “1.0.0”,
 “description”: “”,
 “scripts”: {
    “build”: “webpack”,
    “start”: “webpack-dev-server”
  },
 “license”: “ISC”,
 “devDependencies”: {
    “ts-loader”: “^0.7.2”,
    “tsd”: “^0.6.5”,
    “typescript”: “^1.7.5”,
    “webpack”: “^1.12.11”,
    “webpack-dev-server”: “^1.14.1”
  },
 “dependencies”: {
    “angular2”: “^2.0.0-beta.14”,
    “es6-promise”: “^3.0.2”,
    “es6-shim”: “^0.33.13”,
    “reflect-metadata”: “^0.1.2”,
    “rxjs”: “^5.0.0-beta.0”,
    “zone.js”: “^0.5.10”
 }
}

As I said typescripts used for angular2 to write well groomed code and it can not be run on the browser. So we need to transpile typescripts to javascripts before running it on the browser.

I have typescript and tsd installed globally. npm install typescript -g

I also included them in my devDependencies just in case some one don’t want to install those globally.

I have used ts-loader , that will load(transpile) typescript file as per the configuration mentioned in tsconfig.json .

Here is my tsconfig.json file.

{
  "compilerOptions": {
    "target": "ES5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  },
  "exclude": [
    "node_modules"
  ],
  "files": [
    "app/main.ts",
    "app/vendor.ts"
  ],
  "compileOnSave": false,
  "buildOnSave": false,
}

to know more about configuration option of tsconfig.json , you can refer - tsconfig wiki .

I have written 2 nmp scripts in my package.json file.

Webpackscript will listen to webpack.config.js .

Here is my webpack.config.js file.

var webpack = require("webpack");
 
module.exports = {
  entry: {
    "vendor": "./app/vendor",
    "app": "./app/boot"
  },
  output: {
    path: __dirname,
    filename: "./dist/[name].bundle.js"
  },
  resolve: {
    extensions: ['', '.js', '.ts']
  },
  devtool: 'source-map',
  module: {
    loaders: [
      {
        test: /\.ts/
        loaders: ['ts-loader'],
        exclude: /node_modules/
      }
    ]
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin(/* chunkName= */"vendor", /* filename= */"./dist/vendor.bundle.js")
  ]
}

For more details on webpack, refer to webpack configuration .

I have splitted my code into 2 bundle files.

1. app.bundle.js
2. vendor.bundle.js // contains all the external js file such as `angular2`, `rx.js` etc.

I used CommonsChunkPlugin to remove all vendor modules from app bundle.

I used source-map as dev-tool to make the debugging easy. By setting this option source map files will be generated along with bundles, it will make original typescript files available at the browser source option(in developer option).

Here is the git-link for this example along with guide to run the code.

SystemJS Implementation:

For systemJS implementation we will refer the angular official quickstrat-example .

Comparison of both webpack and systemJS implementation:

Wait !! before proceeding for the comparison, let me ask one question “Is systemJS a bundler ?”. No it is not.Let’s make it very clear that systemJS is not a bundler,it is only a universal module loader.

So using systemJS alone, we will not get much advantages.

Following are the advantages of webpack over the sytemJS implementation:

  • We can generate bundle js with webpack, but to generate bundle with systemJS we need additional builders.
  • Also with systemJS, we need additional package manager to do the additional tasks such as typescript transpilation.
  • Through webpack we can tap into npm’s huge module ecosystem.
  • webpack has a rich and flexible plugin infrastructure, so we can do lot more stuffs with it.

P.S : webpack has lot of advantages as it’s a complete module system.

So now we can say webpack is better than sytemJS.

But if we consider JSPM which comes with systemJS as it’s module loader, is a bundler as well as package manager like bower, npm.

For more on JSPM refer to jspm.io .

Advantages of JSPM with SystemJS over webpack is package management and out of box support for ECMAScript 2015(ES6).

Webpack requires a little more configuration to work with ES6 code, still webpack is on weighted side because of it’s huge plugin ecosystem and simplicity.

Again there is webpack2 , which is currently in beta version, has some more features on top of the features that are available in webpack1. It has a better support for ES6 and also it uses tree shaking algorithm, which is basically a dead code elimination algorithm, it helps in reducing the bundle size significantly.

It eliminates unused exports in two steps:

First, all module files are bundled into a single bundle file. In this process, exports that were not imported anywhere, will be removed.

Second, the bundle is minified along with dead code elimination. In this process entities, that are neither exported nor used inside their modules, do not appear in the minified bundle.[5]

So here is an article for webpack2 with tree shaking .

I went with webpack for my project, as I found it simple and clean, and it solved all my needs such as transpiling, bundling, running unit test and generating docs so on.

Conclusion:

That ends our gentle discussion on javascript module sytems. We skipped some detailed implementation but this will give an overall idea about the features provided by JS module systems and some idea on choosing a module system for your Angular2 application.

References:





About List