Angular 2 Bundle Using WebPack In ASP.NET MVC

Introduction

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 discuss these concepts to have a better idea about the core functions Webpack performs.

  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 an entry point using the entry property in a configuration file.

module.exports = {
  entry: {
    "polyfills": "./Angular2/polyfills.ts",
    "vendor": "./Angular2/vendor.ts",
    "app": "./Angular2/main.ts"
  },
},

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

Output

You can think of it like someone has interacted with a web application in a way to input some data and execute the command by pressing the 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.

module.exports = {
    output: {
        path: "./Views/Home",
        filename: '../../angularBundle/[name].[hash].build.js'
    },
};

In the output object, we use the path where to create the directory if it's already not created and the filename as file naming 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 is processed and converted to javascript as webpack only if it understands javascript.

For the 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.

module: {
    rules: [{
            test: /\.ts$/,
            loaders: ['awesome-typescript-loader', 'source-map-loader', 'tslint-loader']
        },
        {
            test: /\.(png|jpg|gif|woff|woff2|ttf|svg|eot)$/,
            loader: 'file-loader?name=assets/[name]-[hash:6].[ext]'
        },
        {
            test: /favicon.ico$/,
            loader: 'file-loader?name=/[name].[ext]'
        },
        {
            test: /\.css$/,
            loader: 'style-loader!css-loader'
        },
        {
            test: /\.scss$/,
            exclude: /node_modules/,
            loaders: ['style-loader', 'css-loader', 'sass-loader']
        },
        {
            test: /\.html$/,
            loader: 'raw-loader'
        }
    ],
}

Plugins

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

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

plugins: [
    new webpack.optimize.CommonsChunkPlugin({
        name: ['app', 'polyfills', /*'vendor'*/ ]
    }),
    new CleanWebpackPlugin(
        ['./AngularBundle', ]
    ),
    new HtmlWebpackPlugin({
        template: "./Views/Home/loader",
        filename: "./Index.cshtml",
        inject: false,
    }),
    new CopyWebpackPlugin([{
        from: './angular2/images/*.*',
        to: 'assets/',
        flatten: true
    }])
]

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 the command prompt to run the command

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, and 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.

npm install webpack webpack-dev-server --save-dev

Step 3. Install webpack loaders

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

Step 4. Install webpack plugins

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

Step 5. install other dependencies

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.

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es5",
        "moduleResolution": "node",
        "sourceMap": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "removeComments": false,
        "noImplicitAny": false,
        "skipLibCheck": true,
        "lib": ["es2015", "dom"],
        "types": ["node"]
    },
    "awesomeTypescriptLoaderOptions": {
        "useWebpackText": true
    },
    "compileOnSave": false,
    "buildOnSave": false
}

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, services, modules, etc. We call it an app. We do not have to create a separate file for 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.

import 'ie-shim'; // Internet Explorer 9 support.
import 'core-js/es6/symbol';
import 'core-js/es6/object';
import 'core-js/es6/function';
import 'core-js/es6/parse-int';
import 'core-js/es6/parse-float';
import 'core-js/es6/number';
import 'core-js/es6/math';
import 'core-js/es6/string';
import 'core-js/es6/date';
import 'core-js/es6/array';
import 'core-js/es6/regexp';
import 'core-js/es6/map';
import 'core-js/es6/set';
import 'core-js/es6/weak-map';
import 'core-js/es6/weak-set';
import 'core-js/es6/typed';
import 'core-js/es6/reflect';
import 'core-js/es7/reflect';
import 'zone.js/dist/zone';
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.

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

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 create separate config files for development, testing, and production and then switch between these config files in the main configuration file.

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

var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var CleanWebpackPlugin = require('clean-webpack-plugin');
console.log('@@@@@@@@@ USING DEVELOPMENT @@@@@@@@@@@@@@@');
module.exports = {
    devtool: 'source-map',
    performance: {
        hints: false
    },
    entry: {
        "polyfills": "./Angular2/polyfills.ts",
        // "vendor":"./A2/vendor.ts",
        "app": "./Angular2/main.ts"
    },
    output: {
        path: "./Views/Home",
        filename: '../../angularBundle/[name].[hash].build.js'
    },
    resolve: {
        extensions: ['.ts', '.js', '.json', '.css', '.scss', '.html', '.cshtml'],
        modules: [path.resolve(__dirname, './src'), 'node_modules']
    },
    devServer: {
        historyApiFallback: true,
        contentBase: path.join(__dirname, '/wwwroot/'),
        watchOptions: {
            aggregateTimeout: 300,
            poll: 1000
        }
    },
    module: {
        rules: [{
                test: /\.ts$/,
                loaders: ['awesome-typescript-loader', 'source-map-loader', 'tslint-loader']
            },
            {
                test: /\.(png|jpg|gif|woff|woff2|ttf|svg|eot)$/,
                loader: 'file-loader?name=assets/[name]-[hash:6].[ext]'
            },
            {
                test: /favicon.ico$/,
                loader: 'file-loader?name=/[name].[ext]'
            },
            {
                test: /\.css$/,
                loader: 'style-loader!css-loader'
            },
            {
                test: /\.scss$/,
                exclude: /node_modules/,
                loaders: ['style-loader', 'css-loader', 'sass-loader']
            },
            {
                test: /\.html$/,
                loader: 'raw-loader'
            }
        ],
        exprContextCritical: false
    },
    plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            name: ['app', 'polyfills', /*'vendor'*/ ]
        }),
        new CleanWebpackPlugin(
            ['./AngularBundle', ]
        ),
        new HtmlWebpackPlugin({
            template: "./Views/Home/loader",
            filename: "./Index.cshtml",
            inject: false,
        }),
        new CopyWebpackPlugin([{
            from: './angular2/images/*.*',
            to: 'assets/',
            flatten: true
        }])
    ]
};

Step 9. Finally, Open the package.json and replace the script options with the code below.

"ngc": "ngc -p ./tsconfig-aot.json",
"start": "concurrently \"webpack-dev-server --hot --inline --port 8080\" \"dotnet run\"",
"webpack-dev": "set NODE_ENV=development && webpack",
"webpack-production": "set NODE_ENV=production && webpack",
"build-dev": "npm run webpack-dev",
"build-production": "npm run ngc && npm run webpack-production",
"watch-webpack-dev": "set NODE_ENV=development && webpack --watch --color",
"watch-webpack-production": "npm run build-production --watch --color",
"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.

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

Also, add the jQuery and the bootstrap script and CSS blocks as required.

<script src="~/Content/js/jquery-3.1.1.min.js"></script>
<script src="~/Content/js/bootstrap.min.js"></script>
<script src="~/Content/js/datepicker.min.js"></script>
<script src="~/Content/js/timepicker.js"></script>

Output

Output


Similar Articles