Bundle javascripts safely in ASP.NET MVC

Problem:

The other day I spent a lot of time to figure out that why my web application didn’t work correctly is because of the ASP.NET MVC default JavaScript bundle renamed the function name of Canvas to e. So I need to find a way to make the javascripts get compressed and bundled safely.

 

Solution for ASP.NET MVC 4:

public class BundleConfig
    {
        public static void RegisterBundles(BundleCollection bundles)
        {
#if DEBUG
            BundleTable.EnableOptimizations = false;
#else
            BundleTable.EnableOptimizations = true;
#endif
        bundles.Add(new ScriptBundle("~/Scripts/Common/js")
            .Include("~/Scripts/jquery-1.8.3.js")
            .Include("~/Scripts/zizhujy.com.js")
            .Include("~/Scripts/Globalize.js")
            .Include("~/Scripts/common.js")
            .Include("~/Scripts/requireLite/requireLite.js"));

if DEBUG

        foreach (var bundle in BundleTable.Bundles)
        {
            bundle.Transforms.Clear();
        }

else

        foreach(var bundle in BundleTable.Bundles) {
            if (bundle is ScriptBundle)
            {
                bundle.Transforms.Clear();
                bundle.Transforms.Add(new SafeJsBundleTransform());
            }
        }

endif

    }

}

public class SafeJsBundleTransform : IBundleTransform
{
    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 codeSetting = new CodeSettings
            {
                // Important to make it all safe, otherwise the function grapher would 
                // run to problems which extensively uses window.eval("some expression").
                EvalTreatment = EvalTreatment.MakeAllSafe,
                PreserveImportantComments = false
            };

            var min = new Minifier();
            var content = min.MinifyJavaScript(response.Content, codeSetting);

            if (min.ErrorList.Count > 0)
            {
                GenerateErrorResponse(response, min.ErrorList);
            }
            else
            {
                response.Content = content;
            }
        }

        response.ContentType = "text/javascript";
    }

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

public class MvcApplication : HttpApplication
{
// Inside your global.asax.cs
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);

    // MVC 4 style:
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}</pre>

Solution for ASP.NET MVC 3:

    public class SafeJsBundleTransform : IBundleTransform
    {
        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 codeSetting = new CodeSettings
                {
                    // Important to make it all safe, otherwise the function grapher would 
                    // run to problems which extensively uses window.eval("some expression").
                    EvalTreatment = EvalTreatment.MakeAllSafe,
                    PreserveImportantComments = false
                };

                var min = new Minifier();
                var content = min.MinifyJavaScript(response.Content, codeSetting);

                if (min.ErrorList.Count > 0)
                {
                    GenerateErrorResponse(response, min.ErrorList);
                }
                else
                {
                    response.Content = content;
                }
            }

            response.ContentType = "text/javascript";
        }

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

    public class MvcApplication : HttpApplication
    {
	// Inside your global.asax.cs
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);

		// MVC 3 style:
            BundleTable.Bundles.EnableDefaultBundles();
        }

	protected void Application_BeginRequest(object source, EventArgs e)
         {
            HttpApplication app = (HttpApplication)source;
            HttpContext context = app.Context;

            // Attempt to perform first request initialization
            FirstRequestInitialization.Initialize(context);
        }

        private class FirstRequestInitialization
        {
            private static bool _initializedAlready = false;
            private readonly static object _SyncRoot = new Object();

            public static void Initialize(HttpContext context)
            {
                if (_initializedAlready) { return; }

                lock (_SyncRoot)
                {
                    if (_initializedAlready) { return; }

                    Init_BundleTable();

                    _initializedAlready = true;
                }
            }

            static void Init_BundleTable()
            {                
                BundleTable.Bundles.EnableDefaultBundles();
                BundleTable.Bundles.Clear();

                IBundleTransform jsTransform = new SafeJsBundleTransform();

                // scripts added to header not NOT deferred
                var commonJs = new Bundle("~/Scripts/Common/js", jsTransform);
                commonJs.AddFile("~/Scripts/jquery-1.8.3.js", true);
                commonJs.AddFile("~/Scripts/zizhujy.com.js", true);
                commonJs.AddFile("~/Scripts/Globalize.js", true);
                commonJs.AddFile("~/Scripts/common.js", true);
                commonJs.AddFile("~/Scripts/requireLite/requireLite.js", true);
                BundleTable.Bundles.Add(commonJs);
                BundleTable.Bundles.Add(stringCompressionJs);
            }
	}
    }