Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transform Styles' Urls to CDN Urls in ASP.NET Bundling and Minification

Some of my styles use url(../img/sprites/main_sprite.png) to local resources in development and stage. However in production I use CDN and all my static resources are on it. Is it possible to transform bundles so that all urls in .css are replaced with cdn path?

For Example:

.Logo {
background-image: url(../img/sprites/main_sprite.png);  
}

However, in production I would like it to be

.Logo {
background-image: url(http://MyCdn.com/img/sprites/main_sprite.png);    
}

I already use CssRewriteUrlTransform() to rewrite my relative paths to absolute, so the resources can be found after they bundled.

I was thinking to extend the class as something like this

public string Process(string includedVirtualPath, string input)
{

    if (_useCdn)
        {
             return  new CssRewriteUrlTransform().Process(_cdn + VirtualPathUtility.ToAbsolute(includedVirtualPath), input);                           
        }
        else
        {
             return  new CssRewriteUrlTransform().Process("~" + VirtualPathUtility.ToAbsolute(includedVirtualPath), input);
        }

    }

However, Process must have VirtualPath, otherwise it throws an exception when I append CDN path.

Is there an equivalent of this class to rewrite URLS with CDN in it?

like image 556
Roman Mik Avatar asked Nov 26 '14 16:11

Roman Mik


1 Answers

I was not able to find an existing solution. So, I used CssRewriteUrlTransform code as the base for my CDNStylesTransformer. I hope it will be useful for you too.

/// <summary>
/// Finds and Replaces Urls with CDN links.
/// </summary>
public class CDNStylesTransformer : IItemTransform
{
    private bool _useCdn;
    private string _cdnBaseUrl;
    public CDNStylesTransformer(bool UseCDN, string CdnBaseUrl)
    {
        _useCdn = UseCDN;
        if(CdnBaseUrl == null || CdnBaseUrl.Equals(string.Empty))
        {
            throw new ArgumentNullException("CdnBaseUrl");
        }
        _cdnBaseUrl = CdnBaseUrl;

    }

    internal static string RebaseUrlToCDNUrl(string cdnUrl, string url)
    {
        // Don't do anything to invalid urls or absolute urls
        if (String.IsNullOrWhiteSpace(url) ||
            String.IsNullOrWhiteSpace(url) ||
            url.StartsWith("data:") ||
               !VirtualPathUtility.IsAbsolute(url))
        {
            return url;
        }

        return cdnUrl + url;
    }

    internal static string ConvertUrlsToCDNUrl(string cdnUrl, string content)
    {
        if (String.IsNullOrWhiteSpace(content))
        {
            return content;
        }
        // Replace all urls with CDN urls
        Regex url = new Regex(@"url\(['""]?(?<url>[^)]+?)['""]?\)");
        return url.Replace(content, ((match) =>
        {
            return "url(" + RebaseUrlToCDNUrl(cdnUrl, match.Groups["url"].Value) + ")";
        }));
    }

    public  string Process(string includedVirtualPath, string input)
    {
        if (_useCdn) 
        {

            return ConvertUrlsToCDNUrl(_cdnBaseUrl, input);
        }
        else
        {
            return input; //do nothing 

        }
    }
}

In your BundleConfiguration class

string cdnPath ="http://MyCdn.com";
bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
      "~/Content/themes/base/style1.css", new CDNStylesTransformer(bundles.UseCdn,cdnPath)
      ));
like image 178
Roman Mik Avatar answered Oct 06 '22 05:10

Roman Mik