/// <summary> /// Returns a minified version of a given CSS. /// </summary> /// <param name="resource">CSS to be minified</param> /// <returns>Minified CSS</returns> public string Minify(string resource) { if (String.IsNullOrEmpty(resource)) { return resource; } try { CssParser parser = new CssParser(); // Parse the resource string parsed = parser.Parse(resource); if (!String.IsNullOrEmpty(parsed)) { resource = parsed; } } catch (Exception ex) { // Parse throws null reference exception on some ocasions EventLogProvider.LogException("CSS Compression", "MINIFYCSS", ex); resource = "/* Minification failed: " + ex.Message + "*/\r\n\r\n" + resource; } return resource; }
public string Compile(IEnumerable<string> files) { var sb = new StringBuilder(); foreach (string file in files) { string compressed = new CssParser().Parse(File.ReadAllText(file)); sb.Append(compressed); sb.Append(Environment.NewLine); } return sb.ToString(); }
public override CombinedFileResult Parse(params string[] files) { var combined = CombineFiles(files); var razorResult = Razor.Parse(combined); var cssParser = new CssParser(); cssParser.Settings.CommentMode = CssComment.Important; var minResult = cssParser.Parse(razorResult); string key = GenerateKey(minResult); return new CombinedFileResult { Content = minResult, Key = key, }; }
public void ProcessRequest(HttpContext context) { HttpRequest request = context.Request; // Read setName, contentType and version. All are required. They are // used as cache key string setName = request["s"] ?? string.Empty; string contentType = request["t"] ?? string.Empty; string version = request["v"] ?? string.Empty; // Decide if browser supports compressed response bool isCompressed = DO_GZIP && this.CanGZip(context.Request); // Response is written as UTF8 encoding. If you are using languages like // Arabic, you should change this to proper encoding UTF8Encoding encoding = new UTF8Encoding(false); // If the set has already been cached, write the response directly from // cache. Otherwise generate the response and cache it if (!this.WriteFromCache(context, setName, version, isCompressed, contentType)) { using (MemoryStream memoryStream = new MemoryStream(5000)) { // Decide regular stream or GZipStream based on whether the response // can be cached or not using (Stream writer = isCompressed ? (Stream)(new GZipStream(memoryStream, CompressionMode.Compress)) : memoryStream) { // Load the files defined in and process each file string setDefinition = GetFilelist(setName) ?? ""; string[] fileNames = setDefinition.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); string minifiedString = string.Empty; var minifier = new Minifier(); StringBuilder allScripts = new StringBuilder(); if (contentType == JS_TYPE) { foreach (string fileName in fileNames) { byte[] fileBytes = this.GetFileBytes(context, fileName.Trim(), encoding); allScripts.Append(Encoding.UTF8.GetString(fileBytes)); //writer.Write(fileBytes, 0, fileBytes.Length); } var codeSettings = new CodeSettings(); codeSettings.MinifyCode = true; codeSettings.OutputMode = OutputMode.SingleLine; //codeSettings.OutputMode = OutputMode.MultipleLines; codeSettings.InlineSafeStrings = true; codeSettings.MacSafariQuirks = true; codeSettings.RemoveUnneededCode = true; codeSettings.LocalRenaming = LocalRenaming.CrunchAll; codeSettings.EvalTreatment = EvalTreatment.MakeAllSafe; //codeSettings.CombineDuplicateLiterals = true; codeSettings.PreserveFunctionNames = false; minifiedString = minifier.MinifyJavaScript(allScripts.ToString(), codeSettings); } if (contentType == CSS_TYPE) { CssParser parser = new CssParser(); foreach (string fileName in fileNames) { byte[] fileBytes = this.GetFileBytes(context, fileName.Trim(), encoding); string crunchedStyles = parser.Parse(Encoding.UTF8.GetString(fileBytes)); allScripts.Append(crunchedStyles); } var cssSettings = new CssSettings(); cssSettings.CommentMode = CssComment.None; cssSettings.ColorNames = CssColor.Strict; //cssSettings.ExpandOutput = true; cssSettings.TermSemicolons = true; minifiedString = minifier.MinifyStyleSheet(allScripts.ToString(), cssSettings); } byte[] rikiki = Encoding.UTF8.GetBytes(minifiedString); writer.Write(rikiki, 0, rikiki.Length); writer.Close(); } // Cache the combined response so that it can be directly written // in subsequent calls byte[] responseBytes = memoryStream.ToArray(); context.Cache.Insert( GetCacheKey(setName, version, isCompressed), responseBytes, null, Cache.NoAbsoluteExpiration, CACHE_DURATION); // Generate the response this.WriteBytes(responseBytes, context, isCompressed, contentType); } } }
/// <summary> /// Returns a minified version of a given CSS. /// </summary> /// <param name="resource">CSS to be minified</param> /// <returns>Minified CSS</returns> public string Minify(string resource) { if (String.IsNullOrEmpty(resource)) { return resource; } // Reset error minificationError = null; try { CssParser parser = new CssParser(); // Ignore error: 'An underscore is not a valid CSS1 or CSS2 identifier character' parser.Settings.IgnoreErrorList = "CSS1008"; parser.Settings.AllowEmbeddedAspNetBlocks = true; parser.CssError += parser_CssError; // Parse the resource string parsed = parser.Parse(resource); if (!String.IsNullOrEmpty(parsed) && (minificationError == null)) { resource = parsed; } } catch (CssException ex) { minificationError = ex; } if (minificationError != null) { if (LogMinifierParseError) { // Log exception to event log if allowed EventLogProvider.LogException("CSS Compression", "MINIFYCSS", minificationError); } // Add the error info to the end of non-minified resource resource += string.Format("\r\n\r\n/* Minification failed (line {0}, error number {1}): {2} */", minificationError.Line, minificationError.Error, minificationError.Message); } return resource; }
/// <summary> /// Minifies the CSS stylesheet passes to it using the given settings, returning the minified results /// The ErrorList property will be set with any errors found during the minification process. /// </summary> /// <param name="source">CSS Source</param> /// <param name="settings">CSS minification settings</param> /// <param name="scriptSettings">JS minification settings to use for expression-minification</param> /// <returns>Minified StyleSheet</returns> public string MinifyStyleSheet(string source, CssSettings settings, CodeSettings scriptSettings) { // initialize some values, including the error list (which shoudl start off empty) string minifiedResults = string.Empty; m_errorList = new List<ContextError>(); // create the parser object and if we specified some settings, // use it to set the Parser's settings object CssParser parser = new CssParser(); parser.FileContext = FileName; if (settings != null) { parser.Settings = settings; } if (scriptSettings != null) { parser.JSSettings = scriptSettings; } // hook the error handler parser.CssError += new EventHandler<CssErrorEventArgs>(OnCssError); // try parsing the source and return the results try { minifiedResults = parser.Parse(source); } catch (Exception e) { m_errorList.Add(new ContextError( true, 0, null, null, null, this.FileName, 0, 0, 0, 0, e.Message)); throw; } return minifiedResults; }
/// <summary> /// Returns a minified version of a given CSS. /// </summary> /// <param name="resource">CSS to be minified</param> /// <returns>Minified CSS</returns> public string Minify(string resource) { if (String.IsNullOrEmpty(resource)) { return resource; } // Reset error minificationError = null; try { CssParser parser = new CssParser(); parser.CssError += parser_CssError; // Parse the resource string parsed = parser.Parse(resource); if (!String.IsNullOrEmpty(parsed) && (minificationError == null)) { resource = parsed; } } catch (CssException ex) { minificationError = ex; } if (minificationError != null) { if (LogMinifierParseError) { // Log exception to event log if allowed EventLogProvider.LogException("CSS Compression", "MINIFYCSS", minificationError); } // Add error info in front of non-minified resource resource += "\r\n\r\n/* Minification failed (line " + minificationError.Line.ToString() + "): " + minificationError.Message + " */"; } return resource; }
/// <summary> /// Produces code minifiction of CSS content by using /// Microsoft Ajax CSS Minifier /// </summary> /// <param name="content">CSS content</param> /// <param name="isInlineCode">Flag whether the content is inline code</param> /// <param name="encoding">Text encoding</param> /// <returns>Minification result</returns> public CodeMinificationResult Minify(string content, bool isInlineCode, Encoding encoding) { if (string.IsNullOrWhiteSpace(content)) { return new CodeMinificationResult(string.Empty); } string newContent; var errorReporter = new MsAjaxCssErrorReporter(); var cssParser = new CssParser { Settings = isInlineCode ? GetInlineCssParserSettings() : GetEmbeddedCssParserSettings() }; cssParser.CssError += errorReporter.CssMinificationErrorHandler; try { newContent = cssParser.Parse(content); } finally { cssParser.CssError -= errorReporter.CssMinificationErrorHandler; } return new CodeMinificationResult(newContent, errorReporter.Errors, errorReporter.Warnings); }
/// <summary> /// In addition to combining, also minifies the given CSS. /// </summary> /// <returns>The combined and minified CSS code for this bundle.</returns> public override string Combine() { var combined = base.Combine(); // Step 1: Bubble the @import directives to the top var pattern = @"@import url\(.*?\);"; var importList = new StringBuilder(); combined = Regex.Replace(combined, pattern, m => { var url = m.Groups[0].Value; url = url.Substring(12, url.Length - 13).Replace("\"", "").Replace("'", ""); if (url.Contains(" ")) importList.Append("@import url('" + url + "');\r\n"); else importList.Append("@import url(" + url + ");\r\n"); return string.Empty; }, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled); combined = importList.ToString() + combined; // Step 2: The actual CSS minification var result = string.Empty; var errorLines = string.Empty; var hasError = false; try { var cssParser = new CssParser(); cssParser.Settings.CommentMode = CssComment.None; cssParser.Settings.MinifyExpressions = true; cssParser.Settings.OutputMode = OutputMode.SingleLine; cssParser.Settings.TermSemicolons = false; cssParser.CssError += delegate(object sender, CssErrorEventArgs args) { // The 0 severity means errors. // We can safely ignore the rest. if (args.Error.Severity == 0) { hasError = true; errorLines += string.Format("\r\n/* CSS Parse error when processing the bundle.\r\nLine {0} column {1}.\r\nError message: {2}, severity: {3} */", args.Error.StartLine, args.Error.StartColumn, args.Error.Message, args.Error.Severity); } }; result = cssParser.Parse(combined); } catch (Exception exc) { hasError = true; Logger.WriteException(exc); } // If there were errors, use the non-minified version and append the errors to the bottom, // so that the portal builder can debug it. if (hasError) result = combined + "\r\n\r\n" + errorLines; return result; }
private int ProcessCssFile(string sourceFileName, string encodingName, ResourceStrings resourceStrings, StringBuilder outputBuilder, ref long sourceLength) { int retVal = 0; // blank line before WriteProgress(); try { // read the input file var source = ReadInputFile(sourceFileName, encodingName, ref sourceLength); // process input source... CssParser parser = new CssParser(); parser.CssError += new EventHandler<CssErrorEventArgs>(OnCssError); parser.FileContext = string.IsNullOrEmpty(sourceFileName) ? "stdin" : sourceFileName; parser.Settings.CommentMode = m_cssComments; parser.Settings.ExpandOutput = m_prettyPrint; parser.Settings.IndentSpaces = m_indentSize; parser.Settings.TermSemicolons = m_terminateWithSemicolon; parser.Settings.ColorNames = m_colorNames; parser.Settings.MinifyExpressions = m_minifyExpressions; parser.Settings.AllowEmbeddedAspNetBlocks = m_allowAspNet; parser.ValueReplacements = resourceStrings; // if the kill switch was set to 1 (don't preserve important comments), then // we just want to set the comment mode to none, regardless of what the actual comment // mode may be. if ((m_killSwitch & 1) != 0) { parser.Settings.CommentMode = CssComment.None; } // crunch the source and output to the string builder we were passed string crunchedStyles = parser.Parse(source); if (crunchedStyles != null) { Debug.WriteLine(crunchedStyles); } else { // there was an error and no output was generated retVal = 1; } if (m_echoInput) { // just echo the input to the output outputBuilder.Append(source); } else if (!string.IsNullOrEmpty(crunchedStyles)) { // send the crunched styles to the output outputBuilder.Append(crunchedStyles); } } catch (IOException e) { // probably an error with the input file retVal = 1; System.Diagnostics.Debug.WriteLine(e.ToString()); WriteError("AM-IO", e.Message); } return retVal; }
private void InnerMinify(IAsset asset, CssParser cssParser) { string newContent; string assetUrl = asset.Url; cssParser.FileContext = assetUrl; cssParser.CssError += ParserErrorHandler; try { newContent = cssParser.Parse(asset.Content); } catch (MicrosoftAjaxParsingException e) { throw new AssetMinificationException( string.Format(CoreStrings.Minifiers_MinificationSyntaxError, CODE_TYPE, assetUrl, MINIFIER_NAME, e.Message), e); } catch (Exception e) { throw new AssetMinificationException( string.Format(CoreStrings.Minifiers_MinificationFailed, CODE_TYPE, assetUrl, MINIFIER_NAME, e.Message), e); } finally { cssParser.CssError -= ParserErrorHandler; cssParser.FileContext = null; } asset.Content = newContent; asset.Minified = true; }
/// <summary> /// Produces a code minifiction of CSS-assets by using Microsoft Ajax Minifier /// </summary> /// <param name="assets">Set of CSS-assets</param> /// <returns>Set of CSS-assets with minified text content</returns> public override IList<IAsset> Minify(IList<IAsset> assets) { if (assets == null) { throw new ArgumentException(CoreStrings.Common_ValueIsEmpty, "assets"); } if (assets.Count == 0) { return assets; } var assetsToProcessing = assets.Where(a => a.IsStylesheet && !a.Minified).ToList(); if (assetsToProcessing.Count == 0) { return assets; } var cssParser = new CssParser { Settings = _cssParserConfiguration }; foreach (var asset in assetsToProcessing) { InnerMinify(asset, cssParser); } return assets; }
/// <summary> /// Produces a code minifiction of CSS-asset by using Microsoft Ajax Minifier /// </summary> /// <param name="asset">CSS-asset</param> /// <returns>CSS-asset with minified text content</returns> public override IAsset Minify(IAsset asset) { if (asset == null) { throw new ArgumentException(CoreStrings.Common_ValueIsEmpty, "asset"); } if (asset.Minified) { return asset; } var cssParser = new CssParser { Settings = _cssParserConfiguration }; InnerMinify(asset, cssParser); return asset; }