-
Notifications
You must be signed in to change notification settings - Fork 119
Using SquishIt programmatically without the file system
If your environment does not allow reading/writing to the file system, you may be ready to turn your back on SquishIt. Don't! It is entirely possible to use SquishIt programmatically.
The trick is to programmatically define your bundles in a Application_Bundle
method of your Global.asax file. You will call this method in Application_Start
.
protected void Application_Start() {
// ... everything else
// SquishIt
Application_Bundle();
}
protected void Application_Bundle() {
//SquishIt
Bundle.Css()
.Add("~/Content/Base.css")
.Add("~/Content/MainStyle.css")
.AsCached("main", "~/assets/css/main");
}
The key is the AsCached
method. The first argument is the name of your bundle (or key) and the next is the server URL SquishIt should use (the {id} is the key name, e.g. main
). As you can probably tell, we will need an AssetsController
in our project.
This is simple. If you are using the regular {id}
in MVC for your identifier arguments, simply create a new controller and inherit from SquishItController
.
However, if you are either using a custom BaseController or using a different name for the typical {id}
field (e.g. {identifier}
) you will need to copy the SquishItController code into your own controller. Be sure to specify that the content type is "text/css" for your CSS bundles. An example is below:
// could inherit directly from SquishItController but we use "identifier" as ID parameter in route not "id"
public class AssetsController : BaseController //: SquishItController
{
public ActionResult Js(string identifier)
{
// Set max-age to a year from now
Response.Cache.SetMaxAge(TimeSpan.FromDays(365));
return Content(Bundle.JavaScript().RenderCached(identifier), "text/javascript");
}
public ActionResult Css(string identifier)
{
// Set max-age to a year from now
Response.Cache.SetMaxAge(TimeSpan.FromDays(365));
return Content(Bundle.Css().RenderCached(identifier), "text/css");
}
}
Almost done. Now you just need to render your scripts to your views. Luckily, it's one line of code!
@Bundle.Css().MvcRenderCachedAssetTag("main")
@Bundle.JavaScript().MvcRenderCachedAssetTag("mainscripts")
You will need to import or set up the appropriate SquishIt namespace to use these in the views. SquishIt.Mvc
is not referenced by default if you obtained SquishIt from Nuget. You must add a reference manually, it is stored in /packages/SquishIt-xxx/optional/SquishIt.Mvc.dll
.
It may be useful writing a Razor helper to shorten it even more:
// App_Code\Rzr.cshtml
@helper Css(string key) {
@Bundle.Css().MvcRenderCachedAssetTag(key)
}
@helper Js(string key) {
@Bundle.JavaScript().MvcRenderCachedAssetTag(key)
}
// In a view...
@Rzr.Css("main")
@Rzr.Js("main")
This is relatively simple, however you want to be careful on how you do your request identification. There may be a better way, but this is what works for me.
My web.config file has the following entry
<system.webServer>
<handlers>
<add path="*.css,*.js" name="BundledResourceHandler" type="BundledResourceHandler" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true"/>
</handlers>
</system.webServer>
Assuming that my Bundles work like this
Bundle.Css().AsCached("libs_css", "~/css/libs_#.css");
Bundle.JavaScript().AsCached("libs_js", "~/javascript/libs_#.js");
The actual HTTP Handler looks like this
public class BundledResourceHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
var path = context.Request.FilePath;
var extension = VirtualPathUtility.GetExtension(path);
var filename = VirtualPathUtility.GetFileName(path);
if (filename != null)
{
if (extension == ".css")
{
if (filename.StartsWith("libs_"))
{
context.Response.ClearContent();
context.Response.Write(Bundle.Css().RenderCached("libs_css"));
context.Response.End();
}
}
else if (extension == ".js")
{
if (filename.StartsWith("libs_"))
{
context.Response.ClearContent();
context.Response.Write(Bundle.JavaScript().RenderCached("libs_js"));
context.Response.End();
}
}
}
}
public bool IsReusable { get { return false; } }
}