/// <summary> /// The crunch css. /// </summary> /// <param name="configuration"> /// The configuration. /// </param> private static void Crunch(ConsoleConfiguration configuration) { // Get the currently operating directory. // http://stackoverflow.com/questions/52797/how-do-i-get-the-path-of-the-assembly-the-code-is-in string directoryName = Path.GetDirectoryName(configuration.InputPath); string rootFolder = Path.IsPathRooted(directoryName) ? directoryName : AppDomain.CurrentDomain.BaseDirectory; string fileName = configuration.InputPath; if (!string.IsNullOrWhiteSpace(fileName) && !string.IsNullOrWhiteSpace(rootFolder)) { string actualInputPath = Path.GetFullPath(Path.Combine(rootFolder, fileName)); string outputPath = GetOutPutPath( rootFolder, actualInputPath, configuration.OutputPath, configuration.TargetType, configuration.Minify); CruncherOptions options = new CruncherOptions { Minify = configuration.Minify, AllowRemoteFiles = true, RootFolder = Path.GetDirectoryName(actualInputPath) }; string crunched; if (configuration.TargetType == CrunchTargetType.CSS) { CssCruncher cssCruncher = new CssCruncher(options); crunched = cssCruncher.Crunch(actualInputPath); crunched = cssCruncher.Minify(crunched); } else { JavaScriptCruncher javaScriptCruncher = new JavaScriptCruncher(options); crunched = javaScriptCruncher.Crunch(actualInputPath); crunched = javaScriptCruncher.Minify(crunched); } FileHelper.WriteFile(outputPath, crunched); } }
/// <summary> /// Processes the css request using cruncher and returns the result. /// </summary> /// <param name="context"> /// The current context. /// </param> /// <param name="minify"> /// Whether to minify the output. /// </param> /// <param name="paths"> /// The paths to the resources to crunch. /// </param> /// <returns> /// The <see cref="string"/> representing the processed result. /// </returns> public async Task<string> ProcessCssCrunchAsync(HttpContext context, bool minify, params string[] paths) { string combinedCSS = string.Empty; if (paths != null) { string key = string.Join(string.Empty, paths).ToMd5Fingerprint(); using (await Locker.LockAsync(key)) { combinedCSS = (string)CacheManager.GetItem(key); if (string.IsNullOrWhiteSpace(combinedCSS)) { StringBuilder stringBuilder = new StringBuilder(); CruncherOptions cruncherOptions = new CruncherOptions { MinifyCacheKey = key, Minify = minify, CacheFiles = true, AllowRemoteFiles = CruncherConfiguration.Instance.AllowRemoteDownloads, RemoteFileMaxBytes = CruncherConfiguration.Instance.MaxBytes, RemoteFileTimeout = CruncherConfiguration.Instance.Timeout }; CssCruncher cssCruncher = new CssCruncher(cruncherOptions, context); AutoPrefixerOptions autoPrefixerOptions = CruncherConfiguration.Instance.AutoPrefixerOptions; // Loop through and process each file. foreach (string path in paths) { // Local files. if (PreprocessorManager.Instance.AllowedExtensionsRegex.IsMatch(path)) { List<string> files = new List<string>(); // Try to get the file by absolute/relative path if (!ResourceHelper.IsResourceFilenameOnly(path)) { string cssFilePath = ResourceHelper.GetFilePath( path, cruncherOptions.RootFolder, context); if (File.Exists(cssFilePath)) { files.Add(cssFilePath); } } else { // Get the path from the server. // Loop through each possible directory. foreach (string cssPath in CruncherConfiguration.Instance.CSSPaths) { if (!string.IsNullOrWhiteSpace(cssPath) && cssPath.Trim().StartsWith("~/")) { DirectoryInfo directoryInfo = new DirectoryInfo(context.Server.MapPath(cssPath)); if (directoryInfo.Exists) { IEnumerable<FileInfo> fileInfos = await directoryInfo.EnumerateFilesAsync(path, SearchOption.AllDirectories); files.AddRange(fileInfos.Select(f => f.FullName)); } } } } if (files.Any()) { // We only want the first file. string first = files.FirstOrDefault(); cruncherOptions.RootFolder = Path.GetDirectoryName(first); stringBuilder.Append(await cssCruncher.CrunchAsync(first)); } } else { // Remote files. string remoteFile = this.GetUrlFromToken(path).ToString(); stringBuilder.Append(await cssCruncher.CrunchAsync(remoteFile)); } } combinedCSS = stringBuilder.ToString(); // Apply autoprefixer combinedCSS = cssCruncher.AutoPrefix(combinedCSS, autoPrefixerOptions); if (minify) { combinedCSS = cssCruncher.Minify(combinedCSS); } this.AddItemToCache(key, combinedCSS, cssCruncher.FileMonitors); } } } return combinedCSS; }
/// <summary> /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler" /> interface. /// </summary> /// <param name="context">An <see cref="T:System.Web.HttpContext" /> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param> public override void ProcessRequest(HttpContext context) { HttpRequest request = context.Request; string path = request.QueryString["path"]; string key = path.ToMd5Fingerprint(); bool fallback; bool minify = bool.TryParse(request.QueryString["minify"], out fallback); if (!string.IsNullOrWhiteSpace(path)) { minify = minify || CruncherConfiguration.Instance.MinifyCSS; string combinedCSS = (string)CacheManager.GetItem(key); if (string.IsNullOrWhiteSpace(combinedCSS)) { string[] cssFiles = path.Split('|'); StringBuilder stringBuilder = new StringBuilder(); CruncherOptions cruncherOptions = new CruncherOptions { MinifyCacheKey = path, Minify = minify, AllowRemoteFiles = CruncherConfiguration.Instance.AllowRemoteDownloads, RemoteFileMaxBytes = CruncherConfiguration.Instance.MaxBytes, RemoteFileTimeout = CruncherConfiguration.Instance.Timeout }; cruncherOptions.CacheFiles = cruncherOptions.Minify; cruncherOptions.CacheLength = cruncherOptions.Minify ? CruncherConfiguration.Instance.MaxCacheDays : 0; minify = cruncherOptions.Minify; this.cssCruncher = new CssCruncher(cruncherOptions); // Loop through and process each file. foreach (string cssFile in cssFiles) { // Local files. if (PreprocessorManager.Instance.AllowedExtensionsRegex.IsMatch(cssFile)) { // Get the path from the server. // Loop through each possible directory. List <string> files = new List <string>(); foreach (string cssFolder in CruncherConfiguration.Instance.CSSPaths) { if (!string.IsNullOrWhiteSpace(cssFolder) && cssFolder.StartsWith("~/")) { string actual = HttpContext.Current.Server.MapPath(cssFolder); if (actual != null) { files.AddRange(Directory.GetFiles(actual, cssFile, SearchOption.AllDirectories)); } } } // We only want the first file. string first = files.FirstOrDefault(); cruncherOptions.RootFolder = Path.GetDirectoryName(first); stringBuilder.Append(this.cssCruncher.Crunch(first)); } else { // Remote files. string remoteFile = this.GetUrlFromToken(cssFile).ToString(); stringBuilder.Append(this.cssCruncher.Crunch(remoteFile)); } } combinedCSS = this.cssCruncher.Minify(stringBuilder.ToString()); } if (!string.IsNullOrWhiteSpace(combinedCSS)) { IList <string> fileMonitors; // Configure response headers if (this.cssCruncher == null) { // There should always be a valid list of monitors in the cache. fileMonitors = (List <string>)CacheManager.GetItem(key + "_FILE_MONITORS"); } else { fileMonitors = this.cssCruncher.FileMonitors; } // Configure response headers this.SetHeaders(path, context, ResponseType.Css, minify, fileMonitors); context.Response.Write(combinedCSS); // Compress the response if applicable. if (CruncherConfiguration.Instance.CompressResources) { CompressionModule.CompressResponse(context); } } else { context.Response.StatusCode = (int)HttpStatusCode.NotFound; context.Response.StatusDescription = HttpStatusCode.NotFound.ToString(); } } }