Question

I have found this link:

http://giddyrobot.com/preserving-important-comments-in-mvc-4-bundles/

It shows how to do this same thing for JavaScript and I have used it to make an attempt for StyleBundles, but I'm unsure if it's doing things correctly on the backend.

Is the source code available? If not does anyone know if this seems right? All I want to keep is comments that start with /*! so that licenses for open source projects like normalize get included properly in production.

Here is what I have so far:

public static void RegisterBundles(BundleCollection bundles)
{
    // Allows us to keep /*! comments for licensing purposes
    var cssBundleSettings = new CssSettings
    {
        CommentMode = CssComment.Important
    };
}

public class ConfigurableStyleBundle : Bundle
{
    public ConfigurableStyleBundle(string virtualPath, CssSettings cssSettings) :
        this(virtualPath, cssSettings, null) { }

    public ConfigurableStyleBundle(string virtualPath, CssSettings cssSettings, string cdnPath) :
        base(virtualPath, cdnPath, new[] { new ConfigurableCSSTransform(cssSettings) })
    {
        // commented out from js concatenation token not sure if this one should have one
        //base.ConcatenationToken = ";";
    }
}

[ExcludeFromCodeCoverage]
public class ConfigurableCSSTransform : IBundleTransform
{

    private readonly CssSettings _cssSettings;

    public ConfigurableCSSTransform(CssSettings cssSettings)
    {
        _cssSettings = cssSettings;
    }

    public void Process(BundleContext context, BundleResponse response)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (response == null)
        {
            throw new ArgumentNullException("response");
        }
        if (!context.EnableInstrumentation)
        {
            var minifier = new Minifier();
            var content = minifier.MinifyStyleSheet(response.Content, _cssSettings);
            if (minifier.ErrorList.Count > 0)
            {
                GenerateErrorResponse(response, minifier.ErrorList);
            }
            else
            {
                response.Content = content;
            }
        }
        response.ContentType = "text/css";
    }

    internal static void GenerateErrorResponse(BundleResponse bundle, IEnumerable<object> errors)
    {
        var content = new StringBuilder();
        content.Append("/* ");
        content.Append("CSS MinifyError").Append("\r\n");
        foreach (object current in errors)
        {
            content.Append(current.ToString()).Append("\r\n");
        }
        content.Append(" */\r\n");
        content.Append(bundle.Content);
        bundle.Content = content.ToString();
    }
}

All of this is wrapped in public class BundleConfig and gets called from Global.asax.

I'm just wondering if CssComment.Important could have negative effects and remove too much and if this seems to be doing what I want it to? When I have tested it everything seems to look correct styling wise, but it doesn't hurt to get some eyes seeing as this is probably useful for a lot of other ASP.NET devs who use open source libraries.

Was it helpful?

Solution

I don't think you've done anything incorrectly. Though I would approach it using the IBundleBuilder interface, as this will also keep regular comments out of production from prying eyes who switch user agent, like specified in How to prevent User-Agent: Eureka/1 to return source code. I show some steps on how to test against this in this related blog post.

public class ConfigurableStyleBuilder : IBundleBuilder
{
    public virtual string BuildBundleContent(Bundle bundle, BundleContext context, IEnumerable<BundleFile> files)
    {
        var content = new StringBuilder();

        foreach (var file in files)
        {
            FileInfo f = new FileInfo(HttpContext.Current.Server.MapPath(file.VirtualFile.VirtualPath));
            CssSettings settings = new CssSettings();
            settings.CommentMode = Microsoft.Ajax.Utilities.CssComment.Important;
            var minifier = new Microsoft.Ajax.Utilities.Minifier();
            string readFile = Read(f);
            string res = minifier.MinifyStyleSheet(readFile, settings);
            if (minifier.ErrorList.Count > 0)
            {
                res = PrependErrors(readFile, minifier.ErrorList);
                content.Insert(0, res);
            }
            else
            {
                content.Append(res);
            }

        }

        return content.ToString();
    }

    private string PrependErrors(string file, ICollection<ContextError> errors )
    {
        var content = new StringBuilder();
        content.Append("/* ");
        content.Append("CSS MinifyError").Append("\r\n");
        foreach (object current in errors)
        {
            content.Append(current.ToString()).Append("\r\n");
        }
        content.Append("Minify Error */\r\n");
        content.Append(file);
        return content.ToString();
    }

    private string Read(FileInfo file)
    {
        using (var r = file.OpenText())
        {
            return r.ReadToEnd();
        }
    }
}

public class BundleConfig
{
    public static void RegisterBundles(BundleCollection bundles)
    {          
        var cssBundle = new ConfigurableStyleBundle("~/Content/css");
        cssBundle.Include("~/Content/stylesheet1.css");
        cssBundle.Include("~/Content/stylesheet2.css");
        bundles.Add(cssBundle);

        //etc      
    }
}

I made a NuGet package for this (including a version for scripts) - https://www.nuget.org/packages/LicensedBundler/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top