Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I stop ASP.NET Core 2.0 MVC minification from modifying a specific file?

I'm performing Bundling and Minification in ASP.NET Core 2.0 MVC and I've run into an issue with the minification taking place when it shouldn't. In my page I have the following script tag:

<script src="https://code.jquery.com/jquery-3.3.1.min.js"
        integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT"
        crossorigin="anonymous"
        asp-fallback-test="window.jQuery"
        asp-fallback-src="~/js/jquery.min.js">
</script>

In my bundleconfig.json I have the following section:

{
    "outputFileName": "wwwroot/js/jquery.min.js",
    "inputFiles": [
        "node_modules/jquery/dist/jquery.min.js"
    ],
    "minify": {
        "enabled": false
    }
}

The problem is that the ~/js/jquery.min.js file is losing its trailing newline character when it's transformed by this bundling/minification process which makes the expected hash of the file no longer match. As a workaround I can specify 2 hashes for the integrity value to support a file with or without the newline like so:

integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT sha384-I7/UTpkJas2maMjJpGmrvEgQecqO8Dta/9Wwh+cQrH6Jj984WRRFhWg4MV/oTkIW"

But that's less efficient than just making sure the minification doesn't touch this file. How can I stop this newline from being trimmed?

like image 861
Coder6841 Avatar asked May 06 '18 04:05

Coder6841


2 Answers

I find the default minification system somewhat limited and for things like excluding files I usually end up using a task runner like Gulp instead.

So here is how to do what you want using gulp:

Adding npm support

First add support for npm packages by adding a package.json file if you don't already have it, inside the solution explorer, right click on your project name, then, add new item and search for npm configuration file.

Inside package.json add the following required gulp dependencies as well as any other client side library you want to use, for example, jquery, bootstrap, etc.:

{
  "version": "1.0.0",
  "name": "asp.net",
  "private": true,
  "devDependencies": {
    "gulp": "3.9.1",
    "gulp-concat": "2.6.1",
    "gulp-cssmin": "0.2.0",
    "gulp-uglify": "3.0.0",
    "gulp-filter": "5.1.0",
    "gulp-watch": "5.0.0",
    "rimraf": "2.6.2",
    "jquery": "3.3.1",
    "bootstrap": "4.1.1",
    "popper.js": "1.14.3"
  }
}

Once you save the file a folder will be added to your project directory called node_modules (this folder is not visible unless you activate "Show all files" on the Solution Explorer toolbar.

This folder contains all the libraries and their dependencies, we will use gulp to copy the libraries you want to include from node_modules to your wwwroot folder.

Setting up Gulp

  • Create two other folders in the root of your project, name one Styles and the other one Scripts.

You can use these folders for your application scripts and style-sheets, we will use gulp to combine, minify and copy to the wwwroot folder all these resources.

The idea is to avoid using the wwwroot folder directly so you have full control of what you expose and how when you publish your Website.

  • Add a javascript file to the root of your project and name it gulpfile.js

You can use gulp to create different tasks that can be executed automatically before or after build, when cleaning the project, when the project is open in Visual Studio, etc...

For this example I will create the following tasks:

  • clean:js to clear all files in your wwwroot/js folder.
  • clean:css to clear all css files in your wwwroot/css folder.
  • clean to run clean:js and clean:css one after the other.
  • watch to watch for changes in your application and stylesheet files so whenever you save them, the resources are regenerated in wwwroot.
  • dev:js to generate wwwroot javascript resources during development.
  • dev:css to generate wwwroot css resources during development.
  • dev to execute dev:js and dev:css one after the other.
  • min:js to generate wwwroot javascript resources during production.
  • min:css to generate wwwroot css resources during production.
  • min to execute min:js and min:css one after the other.

Gulp has a lot of plugins, you need to specify which ones are required for your project, to do that, add the following at the beginning of your script:

/// <binding BeforeBuild='clean, dev, min' Clean='clean' ProjectOpened='watch' />
"use strict";

var gulp = require("gulp"),
rimraf = require("rimraf"),
concat = require("gulp-concat"),
cssmin = require("gulp-cssmin"),
uglify = require("gulp-uglify"),
gulpFilter = require("gulp-filter");

As you may deduct from the name, the gulp-filter plugin is what we will use to exclude files from the minification process.

Now, you need to set up some general paths:

var paths = {
    webroot: "./wwwroot/",
    scripts: "./Scripts/",
    styles: "./Styles/",
    node_modules: "./node_modules/"
};

//The following paths will be used to look for any js and css file in your Script and Styles folder or any subfolder inside them 
paths.scripts = paths.scripts + "**/*.js";
paths.styles = paths.styles + "**/*.css";

Note: if you need to specify the order of any script inside these folders, you can do as follows:

paths.scripts = [paths.scripts + "/somescript.js", paths.scripts + "**/*.js"];
paths.styles = [paths.styles + "/somecss.css", paths.styles + "**/*.css"];

Next, define the paths to the vendor scripts which are inside the node_modules folder:

paths.vendorJs = [paths.node_modules + "jquery/dist/jquery.js", 
        paths.node_modules + "popper.js/dist/umd/popper.js",
            paths.node_modules + "bootstrap/dist/js/bootstrap.js"];

paths.vendorCss = [paths.node_modules + "bootstrap/dist/css/bootstrap.css"];

paths.minVendorJs = [paths.node_modules + "jquery/dist/jquery.min.js", 
    paths.node_modules + "jquery/dist/umd/popper.min.js", 
      paths.node_modules + "bootstrap/dist/js/bootstrap.min.js"];

paths.minVendorCss = [paths.node_modules + "bootstrap/dist/css/bootstrap.min.css"];

The idea is to avoid minification for any file that is specified in paths.minVendorJs as they are already minified. The following path will allow you to minify any specific vendor file if you need to do so:

paths.vendorCssToMinify = [paths.node_modules + "perfect-scrollbar/css/perfect-scrollbar.css"]

Then, we define the output files that will be generated, for this example, only one script and one style-sheet will be generated that contains all the application files as well as all vendor files combined within them:

paths.concatJsDest = paths.webroot + "js/application.js";
paths.concatCssDest = paths.webroot + "css/application.css";

paths.minConcatJsDest = paths.webroot + "js/application.min.js";
paths.minConcatCssDest = paths.webroot + "css/application.min.css";

Finally, we define each task:

gulp.task("clean:js", function (cb) {
    rimraf(paths.webroot + "js/**/*.js", cb);
});

gulp.task("clean:css", function (cb) {
    rimraf(paths.webroot + "css/**/*.css", cb);
});

gulp.task("clean", ["clean:js", "clean:css"]);

gulp.task('watch', function () {
    gulp.watch(paths.styles, ['dev:css', 'clean:css']);
    gulp.watch(paths.scripts, ['dev:js', 'clean:js', ]);
});

gulp.task("dev:js", function () {
    return gulp.src(paths.vendorJs.concat(paths.scripts))
        .pipe(concat(paths.concatJsDest))
        .pipe(gulp.dest('.'));
});

gulp.task("dev:css", function () {
    return gulp.src(paths.vendorCss.concat(paths.styles))
        .pipe(concat(paths.concatCssDest))
        .pipe(gulp.dest('.'));
});

gulp.task("min:js", function () {
    // Files to skip from minification.
    var filter = gulpFilter(paths.minVendorJs, {
        restore: true
    });

    return gulp.src(paths.minVendorJs.concat(paths.scripts))
        .pipe(filter)
        .pipe(uglify())
        .pipe(filter.restore)
        .pipe(concat(paths.minConcatJsDest))
        .pipe(gulp.dest("."));
});

gulp.task("min:css", function () {
    // Files to skip from minification.
    var filter = gulpFilter(paths.minVendorCss, {
        restore: true
    });
    return gulp.src(paths.minVendorCss.concat(paths.vendorCssToMinify).concat(paths.styles))
        .pipe(filter)
        .pipe(cssmin())
        .pipe(filter.restore)
        .pipe(concat(paths.minConcatCssDest))
        .pipe(gulp.dest("."));
});

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

And that's it!

To test the configuration, right click on your gulpfile.js file and select Task Runner Explorer. If everything went correctly, you should see something like this:

Task Runner Explorer

You can run the tasks by double clicking on them.

You can use the generated resources in your razor views like this:

<environment include="Development">
    <link rel="stylesheet" href="~/css/application.css" />
</environment>
<environment exclude="Development">
    <link rel="stylesheet" href="~/css/application.min.css" />
</environment>

And

<environment include="Development">
    <script src="~/js/application.js"></script>
</environment>
<environment exclude="Development">
    <script src="~/js/application.min.js"></script>
</environment>

If you need to compile LESS or SASS files you need to use the corresponding Gulp plugin, see here for an example.

More information about using Gulp in ASP.NET Core: https://docs.microsoft.com/en-us/aspnet/core/client-side/using-gulp?view=aspnetcore-2.0

like image 158
Isma Avatar answered Oct 16 '22 14:10

Isma


Try with following configuration :

//1. by default outputMode is singleLine which removes new lines and output on a single line. We are setting it to none.
{
    "outputFileName": "wwwroot/js/jquery.min.js",
    "inputFiles": [
        "node_modules/jquery/dist/jquery.min.js"
     ],
     "minify": {
           "enabled": false,
            outputMode: "none"         
      }
}


//Alternatively, outputMode = "multipleLines" should work with a indentSize of 0 as well.
//In this mode , output file has each line indented by specified indentSize
{
    "outputFileName": "wwwroot/js/jquery.min.js",
    "inputFiles": [
        "node_modules/jquery/dist/jquery.min.js"
     ],
      "minify": {
       "enabled": false,
        outputMode: "multipleLines",
         indentSize: 0
    }
}

You can read about available settings for javascript minifier here

like image 27
Nish26 Avatar answered Oct 16 '22 16:10

Nish26