A Perfect Replacement Scheme for Microsoft.AspNet.Web.Optimization.Bundle

Keywords: ASP.NET JSON JQuery Attribute

Web applications contain a large number of style (css) and script (js) files, which have many solutions for reference, management and publication. In Asp.Net MVC applications, the most familiar solution should be Microsoft.AspNet.Web.Optimization package. This package is also very convenient to use, for me, it depends on too many packages, which is not my appetite, I prefer the simpler kind. Next, I introduce the use of this package and how to replace it perfectly.

1. Bundle use of Microsoft. AspNet. Web. Optimization

Add the merged files to the BundleTable.Bundles collection. StyleBundle class is used for style files and ScriptBundle class is used for script files. Examples are as follows:

public class BundleConfig
{
    public static void RegisterBundles(BundleCollection bundles)
    {
        var style = new StyleBundle("~/Content/login")
            .Include("~/Content/common.css", "~/Content/login.css");
        bundles.Add(style);

        var script = new ScriptBundle("~/Scripts/login")
            .Include("~/Scripts/common.js", "~/Scripts/login.js");
        bundles.Add(style);
    }
}

View pages are rendered using two classes, Styles and cripts. Examples are as follows:

@Styles.Render("~/Content/login")
@Scripts.Render("~/Scripts/login")

Here's a brief introduction to the use of Bundle. Personally, I think there are the following problems:

  • Depending on too many package s, there are WebGrease, Antlr, Newtonsoft.Json;
  • Style files in different folders can't output a min file at the same time. When wrapped together, some of the pictures referenced by style files can't be displayed. I didn't want to solve this problem. With the above one, I didn't want to solve it either.

2. Perfect alternatives

In order to replace the Bundle of Microsoft.AspNet.Web.Optimization perfectly, I adopt the VS extension of Bundler & Minifier, which can easily configure and generate min files of styles and scripts. This extension can only generate min files, instead of Bundle, which can output source files and min files according to the development and production environments, but this problem is solved very well. Here's how to implement it.

  • Install Bundler & Minifier extensions and configurations
    Click "Tools - Extension and Update - Online" in VS, then enter Bundler search, download, restart VS to complete installation.
  • Configuration of Bundle
    Its configuration is simple, with a set of outputFileName and inputFiles. Open the bundleconfig.json file and configure it as follows:
[
  {
    "outputFileName": "static/modules/login/index.min.css",
    "inputFiles": [
      "static/modules/login/index.css"
    ]
  },
  {
    "outputFileName": "static/modules/login/index.min.js",
    "inputFiles": [
      "static/libs/jquery.min.js",
      "static/libs/jquery.md5.js",
      "static/modules/common.js",
      "static/modules/login/index.js"
    ]
  }
]
  • Solving the Output Characteristics of Development Environment and Production Environment
    We know that the Web.config file has the following nodes, which can set the environment of the current program and can be obtained by the IsDebugging Enabled attribute of the HttpContextBase class.
<configuration>
  <system.web>
    <compilation debug="true" />
  </system.web>
</configuration>

According to this node, we can realize the output of style and script files in different environments, i.e. source files at development time and min files in production environment. We add an extension of the HtmlHelper class. One is the MinStyle output style, the other is the MinScript output script. The View page is used as follows:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    @Html.MinStyle("static/modules/login/index.min.css")
</head>
<body>
    <div class="login">
        ...
    </div>
    @Html.MinScript("static/modules/login/index.min.js")
</body>
</html>

Following are the concrete implementations of these two extension methods:

public static class HtmlExtension
{
    public static IHtmlString MinStyle(this HtmlHelper helper, string path)
    {
        var format = "<link rel=\"stylesheet\" href=\"{0}\">";
        var html = GetHtmlString(helper, format, path);
        return new HtmlString(html);
    }

    public static IHtmlString MinScript(this HtmlHelper helper, string path)
    {
        var format = "<script src=\"{0}\"></script>";
        var html = GetHtmlString(helper, format, path);
        return new HtmlString(html);
    }

    private static string GetHtmlString(HtmlHelper helper, string format, string path)
    {
        var random = DateTime.Now.ToString("yyMMddss");
        var html = string.Format(format, path + "?r=" + random);
        var httpContext = helper.ViewContext.RequestContext.HttpContext;
        if (httpContext.IsDebuggingEnabled)
        {
            var bundle = BundleInfo.GetBundle(httpContext, path);
            if (bundle != null)
            {
                var paths = bundle.inputFiles.Select(f => string.Format(format, f + "?r=" + random));
                html = string.Join(Environment.NewLine, paths);
            }
        }

        return html;
    }

    class BundleInfo
    {
        public string outputFileName { get; set; }
        public List<string> inputFiles { get; set; }

        public static BundleInfo GetBundle(HttpContextBase httpContext, string outputFile)
        {
            var jsonFile = httpContext.Server.MapPath("~/bundleconfig.json");
            if (!File.Exists(jsonFile))
                return null;

            var json = File.ReadAllText(jsonFile);
            if (string.IsNullOrWhiteSpace(json))
                return null;

            var bundles = json.FromJson<List<BundleInfo>>();
            if (bundles == null || bundles.Count == 0)
                return null;

            return bundles.FirstOrDefault(b => b.outputFileName == outputFile);
        }
    }
}

Posted by portia on Tue, 08 Jan 2019 12:18:09 -0800