# SCSS Transpiling and Bundling ## SASS vs. SCSS The difference is mostly syntactical. They have a very similar feature set and transpile/interpret down to CSS, however: - `SCSS` is a superset of `CSS`, so therefore CSS` `is valid `SCSS`. You can therefore copy `CSS` from the browser straight into your `SCSS` file. - Meanwhile `Sass` is it's own syntax relying heavily on strict indentation instead of curly brackets and semicolons like `SCSS/CSS` ## SASS/SCSS Compilers are written in JS Therefore a JS Engine needs to be present to transpile to CSS. A popular minifier and bundler for .NET Core is [WebOptimizer](https://github.com/ligershark/WebOptimizer). For it to [transpile SASS/SCSS](https://github.com/ligershark/WebOptimizer.sass) it requires a library such as [JavaScriptEngineSwitcher.Extensions.MsDependencyInjection](https://www.nuget.org/packages/JavaScriptEngineSwitcher.Extensions.MsDependencyInjection) which allows several different JS engines to be embedded in your solution. ## Mixing SCSS and CSS WebOptimizer has several middleware methods to declare your bundles. Since SCSS is a superset of CSS, you can do the following: ```csharp pipeline.AddScssBundle( "/static/css/mybundle.css", //output CSS "node_modules/bootstrap/dist/css/bootstrap.css", "wwwroot/css/site.css", "wwwroot/scss/bootstrap-custom.scss") .UseContentRoot(); ``` ## Example ServicesConfiguration extension ```csharp using JavaScriptEngineSwitcher.ChakraCore; using JavaScriptEngineSwitcher.Extensions.MsDependencyInjection; using Microsoft.AspNetCore.ResponseCompression; using WebOptimizer; namespace Services; public static class ServicesConfiguration { public static void ConfigureWebOptimizer(this IServiceCollection services) { services.AddJsEngineSwitcher( o => o.DefaultEngineName = ChakraCoreJsEngine.EngineName) .AddChakraCore(); services.AddWebOptimizer(ConfigureBundles); /** Until ASP.NET Core 7: The cache busted assets have a modified `Response Header: content-type` from the default `application/javascript` to `text/javascript`, which is not contained in the default ResponseCompressionDefaults.MimeTypes before ASP.NET Core 7.0 https://github.com/ligershark/WebOptimizer#https-compression-considerations */ services.AddResponseCompression(options => { options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat( new[] { "text/javascript" } ); }); } private static Action<IAssetPipeline> ConfigureBundles => (pipeline) => { pipeline.AddJavaScriptBundle( "/static/js/scripts.js", "node_modules/bootstrap/dist/js/bootstrap.bundle.js", "wwwroot/js/site.js") .UseContentRoot(); pipeline.AddScssBundle( "/static/css/site.css", "node_modules/bootstrap/dist/css/bootstrap.css", "wwwroot/scss/bootstrap-custom.scss") .UseContentRoot(); }; } ``` Usage in Program.cs: ```csharp var builder = WebApplication.CreateBuilder(args); var config = builder.Configuration; //... builder.Services.ConfigureWebOptimizer(); // <~~~~~~~~~~~~~~ var app = builder.Build(); app.UseHttpsRedirection(); app.UseResponseCompression(); // <~~~~~~~~~~~~~~ app.UseWebOptimizer(); // <~~~~~~~~~~~~~~ app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); //... app.Run(); ```