Angular 2 Bundle Using WebPack In ASP.NET MVC

Introduction to the Webpack

Webpack is the module bundler for modern javascript oriented applications. It has a configuration based setup. There are four basic concepts or core parts in webpack which are Entry, Output, Loaders and plugins. We will be discussed these concepts to have a better idea about core functions webpack performing.

  1. Entry
  2. Output
  3. Loaders
  4. Plugins

Entry

Webpack basically creates a graph of all of your dependencies and for every application there is a single starting point which is called the entry point. It tells webpack where to start and bundle all related dependencies.

In webpack we define entry point using entry property in configuration file.

  1. module.exports = {  
  2. entry: {  
  3. "polyfills""./Angular2/polyfills.ts",  
  4. "vendor""./Angular2/vendor.ts",  
  5. "app""./Angular2/main.ts"  
  6. },  
  7. },  

 

In entry object we declare key as name of the file and value as the path associated with it. 

Output

You can think of it like some one has interacted with a web application in a way to input some data and execute the command by pressing button so that after processing it will show you processed output in any form which you initiated just like in webpack if there is an entry point to tell the webpack but after creating a bundle there must be some destination to place these bundles in webpack and we use output property to place the bundle files.

  1. module.exports = {  
  2.         output: {  
  3.             path: "./Views/Home",  
  4.             filename: '../../angularBundle/[name].[hash].build.js'  
  5.         },   

In output object we use path where to create directory if it's already not created and filename as filenaming syntax starting with the directory_name/file_name_from_entry_key_value.randomhashvalue.js

Loaders

The basic goal of the loaders is to load the type of all assets/files and every file is a module in webpack language which it processed and converted to javascript as webpack only if it understands javascript.

For transformation process webpack has loaders for all the file types supported like for .ts file types 'awesome-typescript-loader','source-map-loader','tslint-loader' webpack uses these loaders and so on.

To register the file types we will use module property and use the rules where we define the file name in test and loader type in loader property like this.

 

  1. module: {  
  2.         rules: [{  
  3.             test: /\.ts$/,  
  4.             loaders: ['awesome-typescript-loader''source-map-loader''tslint-loader']  
  5.         }, {  
  6.             test: /\.(png|jpg|gif|woff|woff2|ttf|svg|eot)$/,  
  7.             loader: 'file-loader?name=assets/[name]-[hash:6].[ext]'  
  8.         }, {  
  9.             test: /favicon.ico$/,  
  10.             loader: 'file-loader?name=/[name].[ext]'  
  11.         }, {  
  12.             test: /\.css$/,  
  13.             loader: 'style-loader!css-loader'  
  14.         }, {  
  15.             test: /\.scss$/,  
  16.             exclude: /node_modules/,  
  17.             loaders: ['style-loader''css-loader''sass-loader']  
  18.         }, {  
  19.             test: /\.html$/,  
  20.             loader: 'raw-loader'  
  21.         }],   

Plugins

The fourth and the last functional part of the webpack is the plugins which will aid the webpack to do some processing and actions after creating bundle like if the created bundle is not a minified webpack use some uglified plugin to minify code and other related plugins as per user need.

Plugins property is used to add new plugin initialized with a new keyword.

 

  1. plugins: [  
  2.     new webpack.optimize.CommonsChunkPlugin({  
  3.         name: ['app''polyfills'/*'vendor'*/ ]  
  4.     }),  
  5.     new CleanWebpackPlugin(  
  6.         ['./AngularBundle', ]),  
  7.     new HtmlWebpackPlugin({  
  8.         template: "./Views/Home/loader",  
  9.         filename: "./Index.cshtml",  
  10.         inject: false,  
  11.     }),  
  12.     new CopyWebpackPlugin([{  
  13.         from: './angular2/images/*.*',  
  14.         to: 'assets/',  
  15.         flatten: true  
  16.     }])  
  17. ]   

Let’s move step by step to configure our app for webpack.

Step 1

Create the package.json on the root of the application.

using command prompt run command 

  1. npm init -f   

Step 2 Installing Development Dependencies

The development dependencies are those libraries, which are required only to develop the application. For Example javascript libraries for unit tests, minification, module bundlers are required only at the time of development of the application.

Our Angular 2 application needs Typescript. Webpack module, loaders & plugins etc.

Install the required webpack npm package. 

  1. npm install webpack webpack-dev-server --save-dev   

Step 3

install webpack loaders

 

  1. npm install angular2-template-loader awesome-typescript-loader css-loader file-loader    
  2.     
  3. html-loader null-loader raw-loader style-loader to-string-loader --save-dev    

Step 4

install webpack plugins 

  1. npm install html-webpack-plugin webpack-merge extract-text-webpack-plugin --save-dev   

Step 5

install other dependencies 

  1. npm install rimraf --save-dev   

Step 6

Configuring our application

Create the file tsconfig.json in the root folder of our project and copy the following code into it.

 

  1. {  
  2.     "compilerOptions": {  
  3.         "module""es2015",  
  4.         "target""es5",  
  5.         "module""commonjs",  
  6.         "moduleResolution""node",  
  7.         "sourceMap"true,  
  8.         "emitDecoratorMetadata"true,  
  9.         "experimentalDecorators"true,  
  10.         "removeComments"false,  
  11.         "noImplicitAny"false,  
  12.         "skipLibCheck"true,  
  13.         "lib": ["es2015""dom"],  
  14.         "types": ["node"]  
  15.     },  
  16.     "awesomeTypescriptLoaderOptions": {  
  17.         "useWebpackText"true  
  18.     },  
  19.     "compileOnSave"false,  
  20.     "buildOnSave"false  
  21. }   

Step 7 Webpack Bundle

The next step is to configure the Webpack. Webpack allows us to bundle all our javascript files into  one or more files. Let us create TWO bundles in our application

In the first bundle, we add all our application code like components, service, modules etc. We call it as an app. We do not have to create a separate file to that. Our main.ts file will be the starting point for this bundle.

In the second bundle, we include the polyfills we require to run Angular applications in most modern browsers. Create a file called polyfills.ts and copy the following code.

  1. import 'ie-shim'// Internet Explorer 9 support.    
  2. import 'core-js/es6/symbol';  
  3. import 'core-js/es6/object';  
  4. import 'core-js/es6/function';  
  5. import 'core-js/es6/parse-int';  
  6. import 'core-js/es6/parse-float';  
  7. import 'core-js/es6/number';  
  8. import 'core-js/es6/math';  
  9. import 'core-js/es6/string';  
  10. import 'core-js/es6/date';  
  11. import 'core-js/es6/array';  
  12. import 'core-js/es6/regexp';  
  13. import 'core-js/es6/map';  
  14. import 'core-js/es6/set';  
  15. import 'core-js/es6/weak-map';  
  16. import 'core-js/es6/weak-set';  
  17. import 'core-js/es6/typed';  
  18. import 'core-js/es6/reflect';  
  19. import 'core-js/es7/reflect';  
  20. import 'zone.js/dist/zone';  
  21. import 'ts-helpers';   

Step 8

Webpack configuration

The next step is to configure the Webpack.

The Webpack by convention uses the webpack.config.js file to read the configuration information. Create the webpack.config.js in the root folder of our project. Add the following code.

 

  1. var environment = (process.env.NODE_ENV || "development").trim();  
  2. if (environment === "development") {  
  3.     module.exports = require('./webpack.dev.js');  
  4. else {  
  5.     module.exports = require('./webpack.prod.js');  
  6. }   

The Webpack can be set up so that you can have a separate configuration option for testing , development, and production. What you need to do is to create separate config files for development, testing and production and then switch between these config file in the main configuration file.

Create webpack.dev.js under the config folder and add the following code.

  1. var path = require('path');  
  2. var webpack = require('webpack');  
  3. var HtmlWebpackPlugin = require('html-webpack-plugin');  
  4. var CopyWebpackPlugin = require('copy-webpack-plugin');  
  5. var CleanWebpackPlugin = require('clean-webpack-plugin');  
  6. console.log('@@@@@@@@@ USING DEVELOPMENT @@@@@@@@@@@@@@@');  
  7. module.exports = {  
  8.     devtool: 'source-map',  
  9.     performance: {  
  10.         hints: false  
  11.     },  
  12.     entry: {  
  13.         "polyfills""./Angular2/polyfills.ts",  
  14.         // "vendor":"./A2/vendor.ts",    
  15.         "app""./Angular2/main.ts"  
  16.     },  
  17.     output: {  
  18.         path: "./Views/Home",  
  19.         filename: '../../angularBundle/[name].[hash].build.js'  
  20.     },  
  21.     resolve: {  
  22.         extensions: ['.ts''.js''.json''.css''.scss''.html''.cshtml'],  
  23.         modules: [path.resolve(__dirname, './src'), 'node_modules']  
  24.     },  
  25.     devServer: {  
  26.         historyApiFallback: true,  
  27.         contentBase: path.join(__dirname, '/wwwroot/'),  
  28.         watchOptions: {  
  29.             aggregateTimeout: 300,  
  30.             poll: 1000  
  31.         }  
  32.     },  
  33.     module: {  
  34.         rules: [{  
  35.             test: /\.ts$/,  
  36.             loaders: ['awesome-typescript-loader''source-map-loader''tslint-loader']  
  37.         }, {  
  38.             test: /\.(png|jpg|gif|woff|woff2|ttf|svg|eot)$/,  
  39.             loader: 'file-loader?name=assets/[name]-[hash:6].[ext]'  
  40.         }, {  
  41.             test: /favicon.ico$/,  
  42.             loader: 'file-loader?name=/[name].[ext]'  
  43.         }, {  
  44.             test: /\.css$/,  
  45.             loader: 'style-loader!css-loader'  
  46.         }, {  
  47.             test: /\.scss$/,  
  48.             exclude: /node_modules/,  
  49.             loaders: ['style-loader''css-loader''sass-loader']  
  50.         }, {  
  51.             test: /\.html$/,  
  52.             loader: 'raw-loader'  
  53.         }],  
  54.         exprContextCritical: false  
  55.     },  
  56.     plugins: [  
  57.         new webpack.optimize.CommonsChunkPlugin({  
  58.             name: ['app''polyfills'/*'vendor'*/ ]  
  59.         }),  
  60.         new CleanWebpackPlugin(  
  61.             ['./AngularBundle', ]),  
  62.         new HtmlWebpackPlugin({  
  63.             template: "./Views/Home/loader",  
  64.             filename: "./Index.cshtml",  
  65.             inject: false,  
  66.         }),  
  67.         new CopyWebpackPlugin([{  
  68.             from: './angular2/images/*.*',  
  69.             to: 'assets/',  
  70.             flatten: true  
  71.         }])  
  72.     ]  
  73. };   

Step 9

Finally, Open the package.json and replace the scripts options with the code below.

 

  1. "ngc""ngc -p ./tsconfig-aot.json",      
  2. "start""concurrently \"webpack-dev-server --hot --inline --port 8080\" \"dotnet run\" ",      
  3. "webpack-dev""set NODE_ENV=development && webpack",    
  4. "webpack-production""set NODE_ENV=production && webpack",    
  5. "build-dev""npm run webpack-dev",    
  6. "build-production""npm run ngc && npm run webpack-production",    
  7. "watch-webpack-dev""set NODE_ENV=development && webpack --watch --color",    
  8. "watch-webpack-production""npm run build-production --watch --color",    
  9. "publish-for-iis""npm run build-production && dotnet publish -c Release"     

Step 10

create the loader.cshtml file in View/Home/loader.cshtml

Add the generated chunks to the loader.cshtml file

Create the loader.cshtml file and add the index.cshtml view code inside it and after the component selector code add this code.

 

  1. <% for (var chunk in htmlWebpackPlugin.files.chunks) { %>  
  2.     <script src="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>"></script>  
  3.     <% } %>   

Also add the jquery and the bootstrap script and css blocks as required.

 

  1. <script src="~/Content/js/jquery-3.1.1.min.js"></script>  
  2. <script src="~/Content/js/bootstrap.min.js"></script>  
  3. <script src="~/Content/js/datepicker.min.js"></script>  
  4. <script src="~/Content/js/timepicker.js"></script>   
Output