Smidge + Nuglify bundling, minification and source maps

Smidge + Nuglify bundling, minification and source maps

Smidge 2.0.0 RTM is finally here!

What is Smidge? Smidge is a lightweight runtime bundling library (CSS/JavaScript file minification, combination, compression) for ASP.NET Core -  Here’s some more background info on Smidge

There’s plenty of great new features in the version 2.0.0 , but in this post I’ll just highlight a couple of fun ones….

Nuglify and source maps

Nuglify if an ASP.NET Core port of the old AjaxMin library and this works very nicely with Smidge too. By default Smidge uses an updated version of JsMin that I maintain called JsMinSharp for it’s JavaScript minification engine. JsMin works fairly well, it’s primary feature is that it’s fast because it doesn’t come with any bells and whistles and doesn’t produce a Syntax Tree. Nuglify on the other hand does produce a Syntax Tree which gives it loads of control over how the minification is done so that it can produce much smaller files, has the ability to rename/reduce parts of the JS and to produce source maps. The downfall of all this control is that it becomes much slower but Smidge is smart enough to cache processed files on the server in a persistent state so it won’t re-process your files if it doesn’t need to.

Here’s a quick benchmark of JsMin vs Nuglify to minify jQuery using the default options (and no source map). As you can see JsMin is substantially faster and is far better for memory but Nuglify can reduce the file size quite a lot more (smaller Minified % is better)

Method Median StdDev Scaled Scaled-SD Minified % Gen 0 Gen 1 Gen 2 Bytes Allocated/Op
JsMin 10.2008 ms 0.3102 ms 1.00 0.00 51.75% - - - 155,624.67
Nuglify 69.0778 ms 0.0180 ms 6.72 0.16 32.71% 53.00 22.00 15.00 4,837,313.07

Source maps you say? JsMin isn’t all that smart so it can’t produce source maps (yet) but Nuglify certainly can and by default the Smidge.Nuglify package has this turned on by default. Here’s how you can get this working:

  1. Follow the super easy Smidge quick start installation guide
  2. Install the Smidge.Nuglify package

    PM> Install-Package Smidge.Nuglify

  3. Add Smidge Nuglify to your services: services.AddSmidgeNuglify();
  4. Use Smidge Nuglify in your Configure method: app.UseSmidgeNuglify();
  5. Replace JsMin  with Nuglify for the default pipeline:
    services.Configure(opt =>
    {
        opt.PipelineFactory.OnCreateDefault = (type, pipeline) => pipeline.Replace(opt.PipelineFactory);
    });
    
  6. That’s it! Nuglify is now the JS minifier for the default pipeline and will produce source maps. You can configure the Nuglify settings in the AddSmidgeNuglify method.

Now you can debug via the source maps in dev tools:

image

File watching

Smidge can now watch your source files and if any changes are detected it can auto cache bust the bundle and flag for re-processing.

Previous to version 2.0.0 if you were in release mode all of the bundling/minification would be active but you really just wanted to test this behavior but unfortunately it meant that if you updated a js/css file you would have to go bump the Smidge version in the config file to clear out the server side persistent cache. In 2.0.0, you can configure your bundle with different environment options for both Debug and Production. For example, perhaps in Debug mode you still want your bundles to be active so that the minification, combination, compression, etc… is still happening but you want to still actively edit files … you can easily do this! Here’s a nice fluent syntax to achieve this:

bundles.CreateJs("my-application", "~/js/site.js", "~/js/app")
    .WithEnvironmentOptions(BundleEnvironmentOptions.Create()
        .ForDebug(builder => builder
            .EnableCompositeProcessing()
            .EnableFileWatcher()
            .SetCacheBusterType())
        .Build()
    );

For this example the “my-application” bundle will do the following when being rendered in debug:

  • Still process the files in the bundle and minify, combine, compress into a composite file
  • Attach file watchers to all files in the bundle
  • Change the cache buster for this bundle to only survive the lifespan of the current app domain

And what’s cool is that if you edit any of the source files in this bundle it will auto cache bust to a new value and re-process the bundle when it’s next requested.

Debug vs Production?

There’s a few ways that you could render assets in either debug or production mode but this is probably the easiest and uses ASP.NET Core’s environment tag helpers. Notice the debug attribute on the script/link tags and that the src/href attributes just include the bundle name … this is using Smidge’s tag helpers to define which bundle to render and if it’s in debug mode.

<environment names="Development">
	<link rel="stylesheet" href="my-css" debug="true" />
	<script src="my-js" debug="true"></script>
</environment>

<environment names="Staging,Production">
	<link rel="stylesheet" href="my-css" />
	<script src="my-js"></script>
</environment>

Thanks!

Big thanks to @dazinator for all the help, recommendations, testing, feedback, etc… and for the rest of the community for filing bugs, questions, and comments. Much appreciated :)

Author

Shannon Thompson

I'm a Senior Software Engineer working full time at Microsoft. Previously, I was working at Umbraco HQ for about 10 years. I maintain several open source projects (many related to Umbraco) such as Articulate, Examine and Smidge, and I also have a commercial software offering called ExamineX. Welcome to my blog :)

comments powered by Disqus