Skip to content

Instantly share code, notes, and snippets.

@codedemonuk
Created September 9, 2012 14:47
Show Gist options
  • Save codedemonuk/3684807 to your computer and use it in GitHub Desktop.
Save codedemonuk/3684807 to your computer and use it in GitHub Desktop.
ASP.NET Optimization Minifiers
// <copyright>
// Copyright (c) 2011+ Dusan Janosik, MIT License
// </copyright>
using System.IO;
using System.Web;
using System.Web.Hosting;
using dotless.Core.Input;
namespace MoonCode.Web.Optimization
{
/// <summary>
/// <see cref="IPathResolver"/> implementation used to resolve paths to imported files (http://lesscss.org/#-importing).
/// </summary>
public class ImportedFilePathResolver : IPathResolver
{
private string currentFileDirectory;
private string currentFilePath;
/// <summary>
/// Initializes a new instance of the <see cref="ImportedFilePathResolver"/> class.
/// </summary>
/// <param name="currentFilePath">The path to the currently processed file.</param>
public ImportedFilePathResolver(string currentFilePath)
{
CurrentFilePath = currentFilePath;
}
/// <summary>
/// Gets or sets the path to the currently processed file.
/// </summary>
public string CurrentFilePath
{
get { return currentFilePath; }
set
{
currentFilePath = value;
currentFileDirectory = Path.GetDirectoryName(value);
}
}
/// <summary>
/// Returns the absolute path for the specified improted file path.
/// </summary>
/// <param name="filePath">The imported file path.</param>
public string GetFullPath(string filePath)
{
filePath = filePath.Replace('\\', '/').Trim();
if (filePath.StartsWith("~"))
{
filePath = VirtualPathUtility.ToAbsolute(filePath);
}
if(filePath.StartsWith("/"))
{
filePath = HostingEnvironment.MapPath(filePath);
}
else if (!Path.IsPathRooted(filePath))
{
filePath = Path.Combine(currentFileDirectory, filePath);
}
return filePath;
}
}
}
// <copyright>
// Copyright (c) 2011+ Dusan Janosik, MIT License
// </copyright>
using System;
using System.IO;
using System.Text;
using System.Web;
using Microsoft.Web.Optimization;
using dotless.Core;
using dotless.Core.Abstractions;
using dotless.Core.Input;
using dotless.Core.Loggers;
using dotless.Core.Parser;
namespace MoonCode.Web.Optimization
{
/// <summary>
/// The bundle transform used to compile and minify LESS files.
/// </summary>
public class LessMinify : YuiCssMinify
{
/// <summary>
/// Processes the specified bundle of LESS files.
/// </summary>
/// <param name="bundle">The LESS bundle.</param>
public override void Process(BundleResponse bundle)
{
if (bundle == null)
{
throw new ArgumentNullException("bundle");
}
HttpContext.Current.Response.Cache.SetLastModifiedFromFileDependencies();
var lessParser = new Parser();
ILessEngine lessEngine = CreateLessEngine(lessParser);
var content = new StringBuilder(bundle.Content.Length);
foreach (FileInfo file in bundle.Files)
{
SetCurrentFilePath(lessParser, file.FullName);
string source = File.ReadAllText(file.FullName);
content.Append(lessEngine.TransformToCss(source, file.FullName));
content.AppendLine();
AddFileDependencies(lessParser);
}
bundle.Content = content.ToString();
base.Process(bundle);
}
/// <summary>
/// Creates an instance of LESS engine.
/// </summary>
/// <param name="lessParser">The LESS parser.</param>
private ILessEngine CreateLessEngine(Parser lessParser)
{
var logger = new AspNetTraceLogger(LogLevel.Debug, new Http());
return new LessEngine(lessParser, logger, false);
}
/// <summary>
/// Adds imported files to the collection of files on which the current response is dependent.
/// </summary>
/// <param name="lessParser">The LESS parser.</param>
private void AddFileDependencies(Parser lessParser)
{
IPathResolver pathResolver = GetPathResolver(lessParser);
foreach (string importedFilePath in lessParser.Importer.Imports)
{
string fullPath = pathResolver.GetFullPath(importedFilePath);
HttpContext.Current.Response.AddFileDependency(fullPath);
}
lessParser.Importer.Imports.Clear();
}
/// <summary>
/// Returns an <see cref="IPathResolver"/> instance used by the specified LESS lessParser.
/// </summary>
/// <param name="lessParser">The LESS prser.</param>
private IPathResolver GetPathResolver(Parser lessParser)
{
var fileReader = lessParser.Importer.FileReader as FileReader;
if (fileReader != null)
{
return fileReader.PathResolver;
}
return null;
}
/// <summary>
/// Informs the LESS parser about the path to the currently processed file.
/// This is done by using custom <see cref="IPathResolver"/> implementation.
/// </summary>
/// <param name="lessParser">The LESS parser.</param>
/// <param name="currentFilePath">The path to the currently processed file.</param>
private void SetCurrentFilePath(Parser lessParser, string currentFilePath)
{
var fileReader = lessParser.Importer.FileReader as FileReader;
if (fileReader == null)
{
lessParser.Importer.FileReader = fileReader = new FileReader();
}
var pathResolver = fileReader.PathResolver as ImportedFilePathResolver;
if (pathResolver != null)
{
pathResolver.CurrentFilePath = currentFilePath;
}
else
{
fileReader.PathResolver = new ImportedFilePathResolver(currentFilePath);
}
}
}
}
// <copyright>
// Copyright (c) 2011+ Dusan Janosik, MIT License
// </copyright>
using System;
using Microsoft.Web.Optimization;
using Yahoo.Yui.Compressor;
namespace MoonCode.Web.Optimization
{
/// <summary>
/// The bundle transform used to minify CSS files by using YUI Compressor for .Net.
/// </summary>
public class YuiCssMinify : IBundleTransform
{
/// <summary>
/// Processes the specified bundle of CSS files.
/// </summary>
/// <param name="bundle">The CSS bundle.</param>
public virtual void Process(BundleResponse bundle)
{
if (bundle == null)
{
throw new ArgumentNullException("bundle");
}
bundle.Content = CssCompressor.Compress(bundle.Content, 0, CssCompressionType.Hybrid, true);
bundle.ContentType = "text/css";
}
}
}
// <copyright>
// Copyright (c) 2011+ Dusan Janosik, MIT License
// </copyright>
using System;
using Microsoft.Web.Optimization;
using Yahoo.Yui.Compressor;
namespace MoonCode.Web.Optimization
{
/// <summary>
/// The bundle transform used to minify JS files by using YUI Compressor for .Net.
/// </summary>
public class YuiJsMinify : IBundleTransform
{
/// <summary>
/// Processes the specified bundle of JS files.
/// </summary>
/// <param name="bundle">The JS bundle.</param>
public virtual void Process(BundleResponse bundle)
{
if (bundle == null)
{
throw new ArgumentNullException("bundle");
}
bundle.Content = JavaScriptCompressor.Compress(bundle.Content);
bundle.ContentType = "text/javascript";
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment