Всем известно, что «большая часть времени уходит на загрузку компонентов страницы: картинок, таблиц стилей, скриптов, flash… Уменьшение количества этих компонентов уменьшает количество запросов к серверу, необходимых до того, как клиентское приложение может отрендерить страницу.» Я всегда сжимал и объединял *.js и *.css файлы вручную, но последнее время меня это стало немного доставать, и я решил упростить этот процесс. Для этого я перерыл кучу всего на гугле и тематических форумах в поисках нужной мне информации, а потом просто собрал всё вместе.
Для сжатия javascript'a я использовал jscompress, немного изменённый для моих нужд.
Вот что получилось:
Для его использования достаточно добавить в web.config всего пару строчек:
Фактически это наборы файлов для объединения и сжатия.
И само использование:
Для сжатия javascript'a я использовал jscompress, немного изменённый для моих нужд.
Вот что получилось:
<%@ WebHandler Language="C#" Class="StaticFilesCombiner" %>
using System;
using System.Net;
using System.IO;
using System.IO.Compression;
using System.Text;
using System.Web;
using JSCompress;
public class StaticFilesCombiner: IHttpHandler {
private readonly static TimeSpan CACHE_DURATION = TimeSpan.FromDays(30);
private const string JQuery = "jquery-1.2.6.min.js";
public void ProcessRequest (HttpContext context) {
HttpRequest request = context.Request;
// Считывает Имя, contentType и версию.
// используются для ключа кэша
string setName = request["s"] ?? string.Empty;
string contentType = request["t"] ?? string.Empty;
string version = request["v"] ?? string.Empty;
bool isCompressed = CanGZip(context.Request);
bool isJS = contentType.Contains("java");
UTF8Encoding encoding = new UTF8Encoding(false);
if (!WriteFromCache(context, setName, version, isCompressed, contentType))
{
using (MemoryStream memoryStream = new MemoryStream(5000))
{
using (Stream writer = isCompressed ?
(Stream)(new GZipStream(memoryStream, CompressionMode.Compress)) :
memoryStream)
{
// Считываем файлы из <appSettings> и обрабатываем
string setDefinition =
System.Configuration.ConfigurationManager.AppSettings[setName] ?? "";
string[] fileNames = setDefinition.Split(new[] { ',' },
StringSplitOptions.RemoveEmptyEntries);
foreach (string fileName in fileNames)
{
byte[] fileBytes = GetFileBytes(context, fileName.Trim(), encoding, isJS);
writer.Write(fileBytes, 0, fileBytes.Length);
}
writer.Close();
}
byte[] responseBytes = memoryStream.ToArray();
context.Cache.Insert(GetCacheKey(setName, version, isCompressed),
responseBytes, null, System.Web.Caching.Cache.NoAbsoluteExpiration,
CACHE_DURATION);
WriteBytes(responseBytes, context, isCompressed, contentType);
}
}
}
/// <summary>
/// Сжатие CSS.
/// </summary>
public static string MinifyCss(string body)
{
StringBuilder builder = new StringBuilder(body);
builder = builder.Replace(" ", string.Empty);
builder = builder.Replace(Environment.NewLine, string.Empty);
builder = builder.Replace("\t", string.Empty);
builder = builder.Replace(" {", "{");
builder = builder.Replace(" :", ":");
builder = builder.Replace(": ", ":");
builder = builder.Replace(", ", ",");
builder = builder.Replace("; ", ";");
builder = builder.Replace(";}", "}");
return builder.ToString();
}
/// <summary>
/// Сжатие js.
/// </summary>
private static string MinifyJS(string notCompressedString, string virtualPath)
{
// Не сжимаем JQuery, так как он уже сжат.
if (virtualPath.Contains(JQuery))
{
return notCompressedString;
}
JSCompressor jsCOmpressor = new JSCompressor(true)
{
CompressVariableNames = false,
LineFeedRemoval = true
};
return jsCOmpressor.Compress(notCompressedString);
}
private static byte[] GetFileBytes(HttpContext context, string virtualPath, Encoding encoding, bool isJS)
{
string compressedString;
string notCompressedString;
if (virtualPath.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase))
{
using (WebClient client = new WebClient())
{
notCompressedString = client.DownloadString(virtualPath);
compressedString = isJS ? MinifyJS(notCompressedString, virtualPath) : MinifyCss(notCompressedString);
return encoding.GetBytes(compressedString);
}
}
string physicalPath = context.Server.MapPath(virtualPath);
notCompressedString = File.ReadAllText(physicalPath);
compressedString = isJS ? MinifyJS(notCompressedString, physicalPath) : MinifyCss(notCompressedString);
return encoding.GetBytes(compressedString);
}
private static bool WriteFromCache(HttpContext context, string setName, string version,
bool isCompressed, string contentType)
{
byte[] responseBytes = context.Cache[GetCacheKey(setName, version, isCompressed)] as byte[];
if (null == responseBytes || 0 == responseBytes.Length) return false;
WriteBytes(responseBytes, context, isCompressed, contentType);
return true;
}
private static void WriteBytes(byte[] bytes, HttpContext context,
bool isCompressed, string contentType)
{
HttpResponse response = context.Response;
response.AppendHeader("Content-Length", bytes.Length.ToString());
response.ContentType = contentType;
if (isCompressed)
response.AppendHeader("Content-Encoding", "gzip");
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetExpires(DateTime.Now.Add(CACHE_DURATION));
context.Response.Cache.SetMaxAge(CACHE_DURATION);
context.Response.Cache.AppendCacheExtension("must-revalidate, proxy-revalidate");
response.OutputStream.Write(bytes, 0, bytes.Length);
response.Flush();
}
private static bool CanGZip(HttpRequest request)
{
string acceptEncoding = request.Headers["Accept-Encoding"];
if (!string.IsNullOrEmpty(acceptEncoding) &&
(acceptEncoding.Contains("gzip") || acceptEncoding.Contains("deflate")))
return true;
return false;
}
private static string GetCacheKey(string setName, string version, bool isCompressed)
{
return "StaticFilesCombiner." + setName + "." + version + "." + isCompressed;
}
public bool IsReusable
{
get
{
return true;
}
}
}
* This source code was highlighted with Source Code Highlighter.
Для его использования достаточно добавить в web.config всего пару строчек:
<appSettings>
<add key="Main_Css" value="~/styles/styles.css"/>
<add key="Set_Css" value="~/styles/Compare.css,~/styles/anycss.css,~/styles/ImageGallery.css,~/styles/styles.css,~/styles/thickbox.css"/>
<add key="Set_Javascript" value="~/js/jquery-1.2.6.min.js,~/js/basket.js,~/js/jquery.galleria.js,~/js/thickbox-compressed.js"/>
<add key="SiteName" value="stirka.spb.ru"/>
</appSettings>
* This source code was highlighted with Source Code Highlighter.
Фактически это наборы файлов для объединения и сжатия.
И само использование:
<link type="text/css" rel="Stylesheet" href="StaticFilesCombiner.ashx?s=Main_Css&t=text/css&v=13" />
* This source code was highlighted with Source Code Highlighter.