Here I'm going to post whatever that is interesting for me. All things about programming using JavaScript and ASP.NET Core. And something else.

A blog about ASP.Net Core and JavaScript

A while ago webpack 4 has been released. And it is really fast. It is not fast as daylight, but it is quicker than Gulp or Grunt.

Despite this, when you try to find some examples how to use it to deal with ASP.NET Core 2.x, you'll fail. Ok! You will not. At least, you have found this post ;).  But most examples on the Internet use webpack 2.x.

This guide shows results of my researching and experiments while building a very minimalistic ASP.NET Core 2.1 application with Visual Studio 2017. Here I will use tools and pipelines that are conventional among the front-end developers:

  • NPM package manager to manage Node.js packages and to run scripts.
  • Javascript ES6-module syntax in the JavaScript code.
  • SASS to process styles.
  • webpack 4 to bundle all things together.

So, let's start.

Notes! The webpack configuring part of this post is outdated. The version 1.0.0 of the css-loader plugin does not contain the minimize option (see changelog). To keep your css minimized, use postcss-loader with cssnano or use optimize-cssnano-plugin.

You can find a new solution in my post "Using webpack 4, PostCss and cssnano in the Asp.Net Core 2.x projects to process SASS styles and minify resulting JavaScript and CSS".

Contents

Step 1. Creating dummy ASP.NET Core 2.x MVC application

A little bit of knowledge of ASP.NET MVC and Visual Studio is assumed. Hope, you already know how to create an ASP.NET Core MVC app from scratch. Here you’ll get a quick path to do this.

1.1 Create a new empty ASP.NET Core Web Application

The structure of the project should be as in the figure below.

1.2 Modify the Startup class

It should look like listed below. The namespace name depends on your project name.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;

namespace AspNetWebpack
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseStaticFiles();
            app.UseMvcWithDefaultRoute();
        }
    }
}

1.3 Add a Home controller

Create Controllers folder and add a file HomeController.cs with Index() action.

using Microsoft.AspNetCore.Mvc;
namespace AspNetWebpack.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
    }
}

You can find how to add controller here.

1.4 Add Views

Create a Views folder. Next, create Home and Shared subfolders inside it.

Add the _ViewStart view to the Views folder. (Use this article to get know how to add views.) Visual Studio will create the _ViewStart.cshtml file. Put the next content to this file:

@{
    Layout = "_Layout";
}

 

Create the _ViewImports.cshtml file into the Views folder and place the next code inside it:

@using AspNetWebpack
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

The AspNetWebpack using depends on the project name (the project namespace, to be clear).

Create the Index.cshtml file inside the Views folder and add the next code to it:

@{
    ViewData["Title"] = "Index";
}

<h2>Index</h2>

The Index.cshtml file contains the default view of the Home controller.

Add the _Layout.cshtml file to the Shared folder. This file should include a common layout for all of the views i. e. navigation menu,  footer, etc. So, put the next HTML markup inside.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"]</title>
</head>
<body>
    <div>
        @RenderBody()
    </div>
</body>
</html>

After finishing this step, the project structure should look like in the image below.

And the only thing our application can do is simply displaying the "Index" header :).

Step 2. Adding NodeJS packages to the project

You should have Node.js installed to continue. At the moment I have an 8.9.4 version of Node.js  at my machine.

2.1 Adding an NPM configuration file to the project

It's time to add NPM settings to the project. The simplest way to do this is to use npm init command from the command line. 

By performing this command, NPM has created the basic package.json file inside your project directory.

2.2. Install webpack and other development dependencies

Type (or simply copy and paste) the next command to the command line tool:

npm install --save-dev webpack webpack-cli css-loader extract-loader file-loader node-sass sass-loader style-loader

With this command, npm installs webpack, webpack command line and other node packages which are needed to process JavaScript code and CSS styles into the bundles.

After finishing it should look like at the figure:

You can install other development dependencies at any time you need.

2.3 Install third-party JavaScript libraries

At this step (and any time later), you can install JavaScript libraries, frameworks or other staff, which needed for your project. For example, let's use the lodash library.

npm install --save lodash

After these steps completed, you will get the next package.json (packages versions will differ at yours systems):

{
  "name": "aspnetwebpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "css-loader": "^0.28.11",
    "extract-loader": "^2.0.1",
    "file-loader": "^1.1.11",
    "node-sass": "^4.9.0",
    "sass-loader": "^7.0.1",
    "style-loader": "^0.21.0",
    "webpack": "^4.8.1",
    "webpack-cli": "^2.1.3"
  },
  "dependencies": {
    "lodash": "^4.17.10"
  }
}

Step 3. Adding JavaScript and SASS sources

Because of using the ES6 standard of JavaScript and SASS to define CSS styles, we need the directory to store initial source codes. Those sources will be compiled into the production bundles by webpack.

3.1. Add the JavaScript sources

Inside the project directory, create the src subfolder. Add the index.js file to this folder and put the next code inside:

import _ from 'lodash';

function component() {
    var element = document.createElement('div');
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
    return element;
}

document.body.appendChild(component());

Here we add the new div-element with "Hello webpack" text to our web-page. Nothing fancy.

3.2. Add the SASS sources

Add the sass subdirectory to the src folder, created at the previous step. Inside it create two files: index.scss and common.scss.

The common.scss file intended to store variables, which are common for our project. Let's put inside a single variable:

$color: #444;

The index.scss file should contain all needed styles, so it must import common.scss.

@import 'common.scss';
body {
    color: $color;
}

After completing this step, the project structure should change like on an image:

Step 4. Configuring the webpack

Now we have some sources to process. It's time to hire a webpack to do its job.

Create the webpack.config.js and put into it the next code:

Notes! The version 1.0.0 of the css-loader plugin does not contain the minimize option (see changelog). To keep your css minimized, use postcss-loader with cssnano or use optimize-cssnano-plugin.

You can find a new solution in my post "Using webpack 4, PostCss and cssnano in the Asp.Net Core 2.x projects to process SASS styles and minify resulting JavaScript and CSS".

"use strict";
const path = require('path');
const bundleFileName = 'bundle'; module.exports = { mode: "development", entry: ['./src/index.js', './src/sass/index.scss'], output: { filename: bundleFileName + '.js', path: path.resolve(__dirname, 'wwwroot/dist') }, module: { rules: [{ test: /\.scss$/, use: [ { loader: 'file-loader', options: { name: bundleFileName + '.css' } }, { loader: 'extract-loader' }, { loader: "css-loader", options: { minimize: true || {/* or CSSNano Options */ } } }, { loader: "sass-loader" } ] }] } };

In details:

mode: "development",

Here we set a development mode by default. It also could be production or none. Learn more about the mode configuration here.

entry: ['./src/index.js', './src/sass/index.scss'],

Specifies the array of entry files. One main JavaScript file and main SASS file.

 output: {

        filename: bundleFileName + '.js',

        path: path.resolve(__dirname, 'wwwroot/dist')

    },

Here we configure output JavaScript bundle file, its filename and destination path.

And in the rules array, we configure the pipeline to process the sass styles.

Description of each loader you can find in the webpack loaders documentation.

Step 5. Adding npm scripts to run webpack

After configuring, webpack is able to create the bundle. But how do we instruct it to do that? The easiest way to do this is to add few commands to the scripts section of the package.json file:

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --progress --profile",
    "watch": "webpack --progress --profile --watch",
    "production": "webpack --progress --profile --mode production"
  },

More about webpack command line interface options you can find here.

To create development bundles, which can be debugged in the browser development tools, use the next command:

npm run build

In the same way, you can run production minified bundles:

npm run production

When developing, it’s convenient to update bundles when something changes. So, use this command:

npm run watch

All of these commands create two bundle files into wwwroot/dist folder.

Step 6. Using bundles in the _Layout view

The last step is adding the references to the bundles into the _Layout.cshtml.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"]</title>
    <link rel="stylesheet" href="~/dist/bundle.css" />
</head>
<body>
    <div>
        @RenderBody()
    </div>
    <script src="~/dist/bundle.js"/>
</body>
</html>

Step 7. Developing the product

Running NPM scripts from the command line is not very convenient. I prefer to use NPM Task Runner, the Visual Studio tool, created by Mads Kristensen

If you are going to use it, do not forget to lift the $(PATH) variable in the locations of external tools (Tools > Options > Project and Solutions > Web Package Management > External Web Tools).

My usual front-end development pipeline is as follow:

1. Running watch task from the Task Runner Explorer.

2. Running the project.

3. Development and debugging.

To display the result, refresh the web-page.

Results and conclusions

The purpose of this post is to show how to configure the webpack in the ASP.NET Core 2.1 MVC Application project. And how to use it while developing front-end staff.

As the preface to this post says, this post explains creating the very minimalistic  ASP.NET Core 2.1 MVC application.

You can find the whole source code at AspNetWebpack repository on GitHub.