By using this site, you acknowledge that you have read and understand our Cookie policy, Privacy policy and Terms .
close

Articles about ASP.NET Core 1.x, 2.x and 3.x.

rss_feed Subscribe RSS

Background

If you have been working on ASP.NET projects in the past years, you probably have heard or used quite a few client library management frameworks/tools. For example, Bower, npm, Gulp, Grunt, Webpack, Yarn, Parcel, Libman, etc. Before SPA became popular, the default ASP.NET (or ASP.NET Core) project templates use Bower as default client management tool and you need to bundle or minimize your client scripts or resources using other tools like Bundler & Minifier. This approach worked quite well for me except that:

  • I still use custom scripts to copy client resources, for example font files, to publish folder (wwwroot).
  • Bower doesn’t support bundle or minimisation. The project also is currently being maintained and it recommends using other frameworks/tools to manage client libs.

In this post, I’m going to show you how to migrate your projects from Bower to Gulp (with npm).

Prerequisites

Gulp run on top of nodejs. Please make sure you have nodejs installed in your system.

Existing project

Client packages/libs

The following packages are used by my project (this website) as configured in bower.json file:

{
  "name": "kontext-v3.0.0-alpha.6",
  "private": true,
  "dependencies": {
    "bootstrap": "v4.3.1",
    "jquery": "3.4.0",
    "jquery-validation": "jquery-validate#1.19.0",
    "jquery-validation-unobtrusive": "v3.2.9",
    "popper.js": "v1.15.0",
    "font-awesome": "4.7.0",
    "Stickyfill": "2.1.0",
    "summernote": "v0.8.9"
  }
}

bundleconfig.json

The following bundling configurations are created:

// Configure bundling and minification for the project.
// More info at https://go.microsoft.com/fwlink/?LinkId=808241
[
  {
    "outputFileName": "wwwroot/css/site.min.css",
    // An array of relative input file paths. Globbing patterns supported
    "inputFiles": [
      "wwwroot/lib/bootstrap/dist/css/bootstrap.css",
      "wwwroot/lib/font-awesome/css/font-awesome.min.css",
      "wwwroot/lib/summernote/dist/summernote-bs4.css",
      "wwwroot/css/site.css"
    ]
  },
  {
    "outputFileName": "wwwroot/js/site.min.js",
    "inputFiles": [
      "wwwroot/lib/jquery/dist/jquery.js",
      "wwwroot/lib/popper.js/dist/umd/popper.js",
      "wwwroot/lib/Stickyfill/dist/stickyfill.js",
      "wwwroot/lib/bootstrap/dist/js/bootstrap.js",
      "wwwroot/lib/jquery.toc/jquery.toc.js",
      "wwwroot/lib/jquery-validation/dist/jquery.validate.js",
      "wwwroot/lib/jquery-validation-unobtrusive/dist/jquery.validate.unobtrusive.js",
      "wwwroot/js/site.js"
    ],
    // Optionally specify minification options
    "minify": {
      "enabled": true,
      "renameLocals": true
    },
    // Optionally generate .map file
    "sourceMap": false
  }
]

Now let’s begin to migrate from Bower to Gulp.

Add npm configuration file package.json

First, add a npm Configuration File package.json.

image

And then add the dependencies for all the current used packages.

Please note some package name is different in npm compared with Bower. For example, Stickyfill is named stickyfilljs in npm instead of Stickyfill. There might be small changes to other packages too. You can go to each package’s official website to find out the package names.

{
  "version": "3.0.0",
  "name": "kontext",
  "private": true,
  "devDependencies": {
    "gulp": "^4.0.0",
    "gulp-concat": "2.6.1",
    "gulp-cssmin": "0.2.0",
    "gulp-uglify": "3.0.0",
    "rimraf": "2.6.1"
  },
  "dependencies": {
    "bootstrap": "4.3.1",
    "jquery": "3.4.0",
    "jquery-validation": "1.19.0",
    "jquery-validation-unobtrusive": "3.2.9",
    "popper.js": "1.15.0",
    "font-awesome": "4.7.0",
    "stickyfilljs": "2.1.0",
    "summernote": "0.8.9"
  }
}

I also added devDependencies for Gulp related packages which I’m going to use in the following sections.

After creating this package file, you can then run the following command to install the packages if it is not automatically done:

npm install

Create Gulp script file

Now we can create a JavaScript file named Gulpfile.js in your website project folder.

I’ve created the following JavaScript content to include the tasks I need to bundle and minimize client scripts.

///
"use strict";

const gulp = require("gulp"),
    rimraf = require("rimraf"),
    concat = require("gulp-concat"),
    cssmin = require("gulp-cssmin"),
    uglify = require("gulp-uglify");

const paths = {
    webroot: "./wwwroot/",
    node_modules: "./node_modules/"
};

/*CSS files */
paths.cssFiles = [
    paths.webroot + "css/_imports.css",
    paths.node_modules + "bootstrap/dist/css/bootstrap.css",
    paths.node_modules + "font-awesome/css/font-awesome.css",
    paths.node_modules + "summernote/dist/summernote-bs4.css",
    paths.webroot + "css/site.css"
];
paths.concatCssDest = paths.webroot + "css/site.min.css";

/*Javascript files */
paths.jsFiles = [
    paths.node_modules + "jquery/dist/jquery.js",
    paths.node_modules + "popper.js/dist/umd/popper.js",
    paths.node_modules + "stickyfilljs/dist/stickyfill.js",
    paths.node_modules + "bootstrap/dist/js/bootstrap.js",
    paths.node_modules + "jquery-validation/dist/jquery.validate.js",
    paths.node_modules + "jquery-validation-unobtrusive/dist/jquery.validate.unobtrusive.js",
    paths.webroot + "js/site.js"];
paths.concatJsDest = paths.webroot + "js/site.min.js";

/*Editor js files */
paths.jsFileEditor = [paths.node_modules + "summernote/dist/summernote-bs4.js"];
paths.concatJsDestEditor = paths.webroot + "js/site.editor.min.js";

/*Clean tasks*/
gulp.task("clean:js", done => rimraf(paths.concatJsDest, done));
gulp.task("clean:js:editor", done => rimraf(paths.concatJsDestEditor, done));
gulp.task("clean:css", done => rimraf(paths.concatCssDest, done));
gulp.task("clean:fonts:fontawesome", done => rimraf(paths.webroot + "fonts/", done));
gulp.task("clean:fonts:summernote", done => rimraf(paths.webroot + "css/font/", done));
gulp.task("clean", gulp.series(["clean:js", "clean:js:editor", "clean:css", "clean:fonts:fontawesome", "clean:fonts:summernote"]));


gulp.task("min:css", () => {
    return gulp.src(paths.cssFiles, { base: "." })
        .pipe(concat(paths.concatCssDest))
        .pipe(cssmin())
        .pipe(gulp.dest('.'));
});

gulp.task("min:js", () => {
    return gulp.src(paths.jsFiles, { base: "." })
        .pipe(concat(paths.concatJsDest))
        .pipe(uglify())
        .pipe(gulp.dest("."));
});

gulp.task("min:js:editor", () => {
    return gulp.src(paths.jsFileEditor, { base: "." })
        .pipe(concat(paths.concatJsDestEditor))
        .pipe(uglify())
        .pipe(gulp.dest("."));
});


gulp.task("copy:font:fontawesome", () => {
    return gulp.src(paths.node_modules + "font-awesome/fonts/*")
        .pipe(gulp.dest(paths.webroot + "fonts/"));
});

gulp.task("copy:font:summernote", () => {
    return gulp.src(paths.node_modules + "summernote/dist/font/*")
        .pipe(gulp.dest(paths.webroot + "css/font/"));
});

gulp.task("min", gulp.series(["min:js", "min:js:editor", "min:css"]));

gulp.task("build", gulp.series(["min", "copy:font:fontawesome", "copy:font:summernote"]));

// A 'default' task is required by Gulp v4
gulp.task("default", gulp.series(["min"]));

In this post, I am not going to cover the details about Gulp. If you want to learn more, please visit Gulp official website.

Basically the following Gulp tasks are created:

  • Tasks to clean existing bundled files (CSS and JavaScript) and fonts
  • Tasks to minimize CSS files into one single CSS file.
  • Tasks to bundle and ugnify JavaScript files.
  • Tasks to run multiple serial tasks.

Once these tasks are created, you can view all the tasks in Task Runner Explorer:

image

During development time, you can run each task by right-click the task in Task Runner Explorer or through nodejs command:

node node_modules\\gulp\\bin\\gulp.js {task name}

Gulp glob

In the above Gulp script file, I’m using script file names to make it easier for you to understand. However, usually you can use Gulp globs to match different files in one go.

For more details, refer to Explaining Globs.

Add nodejs commands into project file

<Target Name="PrepublishScript" BeforeTargets="BeforePublish">
     <Exec Command="npm install" />
     <Exec Command="node node_modules\\gulp\\bin\\gulp.js clean" />
     <Exec Command="node node_modules\\gulp\\bin\\gulp.js build" />
   </Target>

You can now add the above code to your website project file so that npm and Gulp commands are called before publishing the website.

What about development environments?

In your project, you might be directly using these CSS or script files like the following:

<environment include="Development">
     <link rel="stylesheet" href="~/css/_imports.css" />
     <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
     <link rel="stylesheet" href="~/css/site.css" />
     <link rel="stylesheet" href="~/lib/font-awesome/css/font-awesome.css" />
     <link rel="stylesheet" href="~/lib/summernote/dist/summernote-bs4.css" />
</environment>
<environment exclude="Development">
     <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
</environment>

Now because these libraries are not existing in your wwwroot folder (instead in node_modules filder), the code won’t work anymore.

To make sure it still works, we can just add middleware to route those requests to node_modules folder:

if (env.IsDevelopment())
                 {
                     app.UseStaticFiles(new StaticFileOptions()
                     {
                         FileProvider = new PhysicalFileProvider(
                           Path.Combine(Directory.GetCurrentDirectory(), @"node_modules")),
                         RequestPath = new PathString("/lib")
                     });
                 }

Summary

Now you will have a very clean wwwroot folder in your ASP.NET core websites. Gulp doesn’t only support bundle and minimisation but also can copy other resources like fonts into your publish folder.

You can also use Webpack (also based on nodejs) to implement similar tasks. In fact, ASP.NET SPA project template by default uses Webpack as client package management tool.

info Last modified by Raymond at 11 months ago * This page is subject to Site terms.

info About author

More from Kontext

local_offer asp.net core 2 local_offer asp.net core local_offer dotnetcore local_offer open-banking

visibility 199
thumb_up 0
access_time 13 months ago

I’ve just started an asp.net core 2.2 based implementation for Australia Consumer Data Standards (published by Data 61). Opening Banking initiative will follow these standards. The purpose is to help you to get familiar with these standards, especially the APIs that need to be implemented. ...

open_in_new View

local_offer asp.net core local_offer identity core 2

visibility 13491
thumb_up 0
access_time 3 years ago

The identity system in ASP.NET has evolved over time. If you are using ASP.NET Core, you probably found User property is an instance of ClaimsPrincipal in Controller or Razor views. Thus to retrieve the information, you need to utilize the claims.

open_in_new View

local_offer dotnet core local_offer asp.net core

visibility 3788
thumb_up 0
access_time 3 years ago

IP Address In ASP.NET Core, Request.UserHostAddress has been removed though that attribute exists in the traditional ASP.NET applications. We can use HttpContext.Connection to retrieve the remove client IP address: var ipAddress = HttpContext.Connecti...

open_in_new View

local_offer asp.net core 2 local_offer asp.net core

visibility 1070
thumb_up 0
access_time 3 years ago

Other related issues are found during my migration. Unable to Change Identity Table Names ...

open_in_new View

Kontext Column

Kontext Column

Created for everyone to publish data, programming and cloud related articles. Follow three steps to create your columns.

Learn more arrow_forward
info Follow us on Twitter to get the latest article updates. Follow us