在构build时dynamic连接和缩小JavaScript – ASP.NET MVC
作为这个问题的一个扩展在这里链接用户控件中的JavaScript库我是在人们如何在构build时dynamic或缩小JavaScript的一些例子。 我也想看看它是如何工作到您的母版页。
我不介意页面特定的文件被缩小和链接inidividually,因为他们目前是(见下文),但主要母版页上的所有JavaScript文件(我有大约5或6),我想连接和缩小。
任何人也joinCSS连接和缩小的奖励积分! 🙂
目前的母版页与我想要连接和缩小的常见JavaScript文件:
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %> <head runat="server"> ... BLAH ... <asp:ContentPlaceHolder ID="AdditionalHead" runat="server" /> ... BLAH ... <%= Html.CSSBlock("/styles/site.css") %> <%= Html.CSSBlock("/styles/jquery-ui-1.7.1.css") %> <%= Html.CSSBlock("/styles/jquery.lightbox-0.5.css") %> <%= Html.CSSBlock("/styles/ie6.css", 6) %> <%= Html.CSSBlock("/styles/ie7.css", 7) %> <asp:ContentPlaceHolder ID="AdditionalCSS" runat="server" /> </head> <body> ... BLAH ... <%= Html.JSBlock("/scripts/jquery-1.3.2.js", "/scripts/jquery-1.3.2.min.js") %> <%= Html.JSBlock("/scripts/jquery-ui-1.7.1.js", "/scripts/jquery-ui-1.7.1.min.js") %> <%= Html.JSBlock("/scripts/jquery.validate.js", "/scripts/jquery.validate.min.js") %> <%= Html.JSBlock("/scripts/jquery.lightbox-0.5.js", "/scripts/jquery.lightbox-0.5.min.js") %> <%= Html.JSBlock("/scripts/global.js", "/scripts/global.min.js") %> <asp:ContentPlaceHolder ID="AdditionalJS" runat="server" /> </body>
在这样的页面中使用(我很高兴):
<asp:Content ID="signUpContent" ContentPlaceHolderID="AdditionalJS" runat="server"> <%= Html.JSBlock("/scripts/pages/account.signup.js", "/scripts/pages/account.signup.min.js") %> </asp:Content>
更新:现在的build议(2013年底):
我会看看微软ASP.NETbuild立在捆绑和缩小 。
在专业ASP.NET 3.5的附录中,Scott Hanselman谈到了Packer for .NET 。 这将与MSBuild集成和包装生产部署的JavaScript文件等
尝试这个:
我最近完成了一些相当的研究和相应的开发工作,以提高Web应用程序前端的性能。 我想我会在这里分享基本的解决scheme。
第一个显而易见的事情就是使用雅虎的YSlow和Google的PageSpeed来为您的网站进行基准testing。 这些将突出显示“低挂果实”的性能改进。 除非你已经这样做了,否则最终的build议几乎肯定会包括合并,缩小和gzip你的静态内容。
我们要执行的步骤是:
编写一个自定义的HTTPHandler来组合和缩小CSS。 编写一个自定义HTTPHandler来组合和缩小JS。 包含一个机制,以确保上面的应用程序不处于debugging模式时,只做自己的魔力。 编写一个自定义的服务器端Web控件,以便轻松维护css / js文件包含。 在IIS 6上启用某些内容types的GZIP。让我们从实现.NET IHttpHandler接口的CSSHandler.asax开始:
using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Web; namespace WebApplication1 { public class CssHandler : IHttpHandler { public bool IsReusable { get { return true; } } public void ProcessRequest(HttpContext context) { string[] cssFiles = context.Request.QueryString["cssfiles"].Split(','); List<string> files = new List<string>(); StringBuilder response = new StringBuilder(); foreach (string cssFile in cssFiles) { if (!cssFile.EndsWith(".css", StringComparison.OrdinalIgnoreCase)) { //log custom exception context.Response.StatusCode = 403; return; } try { string filePath = context.Server.MapPath(cssFile); string css = File.ReadAllText(filePath); string compressedCss = Yahoo.Yui.Compressor.CssCompressor.Compress(css); response.Append(compressedCss); } catch (Exception ex) { //log exception context.Response.StatusCode = 500; return; } } context.Response.Write(response.ToString()); string version = "1.0"; //your dynamic version number context.Response.ContentType = "text/css"; context.Response.AddFileDependencies(files.ToArray()); HttpCachePolicy cache = context.Response.Cache; cache.SetCacheability(HttpCacheability.Public); cache.VaryByParams["cssfiles"] = true; cache.SetETag(version); cache.SetLastModifiedFromFileDependencies(); cache.SetMaxAge(TimeSpan.FromDays(14)); cache.SetRevalidation(HttpCacheRevalidation.AllCaches); } } }
好的,现在解释一下:
IsReUsable属性:
我们没有处理任何特定于实例的情况,这意味着我们可以安全地重复使用同一个处理程序实例来处理多个请求,因为我们的ProcessRequest是线程安全的。 更多信息。
ProcessRequest方法:
这里没有太忙碌的事情。 我们正在通过给予我们的CSS文件循环(参见下面的CSSControl以了解它们是如何进来的),并在将内容添加到输出响应stream之前,使用Yahoo的YUICompressor的.NET端口对每个CSS文件进行压缩。
该方法的其余部分处理设置一些HTTPcaching属性,以进一步优化浏览器客户端下载(或不,视情况而定)内容的方式。
我们在代码中设置Etags,以便它们可以在服务器场中的所有机器上相同。 我们在我们的实际文件上设置了响应和caching依赖关系,所以如果它们被replace,caching将失效。 我们设置Cacheability,这样代理可以caching。 我们VaryByParams使用我们的cssfiles属性,以便我们可以caching每个通过处理程序提交的CSS文件组。 这里是CSSControl,一个inheritance.NET LiteralControl的自定义服务器端控件。
面前:
<customcontrols:csscontrol id="cssControl" runat="server"> <CustomControls:Stylesheet File="main.css" /> <CustomControls:Stylesheet File="layout.css" /> <CustomControls:Stylesheet File="formatting.css" /> </customcontrols:csscontrol>
背部:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Web; using System.Web.UI; using System.Linq; using TTC.iTropics.Utilities; namespace WebApplication1 { [DefaultProperty("Stylesheets")] [ParseChildren(true, "Stylesheets")] public class CssControl : LiteralControl { [PersistenceMode(PersistenceMode.InnerDefaultProperty)] public List<Stylesheet> Stylesheets { get; set; } public CssControl() { Stylesheets = new List<Stylesheet>(); } protected override void Render(HtmlTextWriter output) { if (HttpContext.Current.IsDebuggingEnabled) { const string format = "<link rel=\"Stylesheet\" href=\"stylesheets/{0}\"></link>"; foreach (Stylesheet sheet in Stylesheets) output.Write(format, sheet.File); } else { const string format = "<link type=\"text/css\" rel=\"Stylesheet\" href=\"stylesheets/CssHandler.ashx?cssfiles={0}&version={1}\"/>"; IEnumerable<string> stylesheetsArray = Stylesheets.Select(s => s.File); string stylesheets = String.Join(",", stylesheetsArray.ToArray()); string version = "1.00" //your version number output.Write(format, stylesheets, version); } } } public class Stylesheet { public string File { get; set; } } }
HttpContext.Current.IsDebuggingEnabled挂钩在您的web.config中的以下设置:
<system.web> <compilation debug="false"> </system.web>
所以,基本上,如果你的网站处于debugging模式,你会得到如下的HTML标记:
<link rel="Stylesheet" href="stylesheets/formatting.css"></link> <link rel="Stylesheet" href="stylesheets/layout.css"></link <link rel="Stylesheet" href="stylesheets/main.css"></link>
但是如果你处于生产模式(debug = false),你会得到像这样的标记:
<link type="text/css" rel="Stylesheet" href="CssHandler.ashx?cssfiles=main.css,layout.css,formatting.css&version=1.0"/>
后者显然会调用CSSHandler,它将负责组合,缩小和caching – 准备好你的静态CSS内容。
上面的所有内容也可以被复制到您的静态JavaScript内容中:
`JSHandler.ashx:
using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Web; namespace WebApplication1 { public class JSHandler : IHttpHandler { public bool IsReusable { get { return true; } } public void ProcessRequest(HttpContext context) { string[] jsFiles = context.Request.QueryString["jsfiles"].Split(','); List<string> files = new List<string>(); StringBuilder response = new StringBuilder(); foreach (string jsFile in jsFiles) { if (!jsFile.EndsWith(".js", StringComparison.OrdinalIgnoreCase)) { //log custom exception context.Response.StatusCode = 403; return; } try { string filePath = context.Server.MapPath(jsFile); files.Add(filePath); string js = File.ReadAllText(filePath); string compressedJS = Yahoo.Yui.Compressor.JavaScriptCompressor.Compress(js); response.Append(compressedJS); } catch (Exception ex) { //log exception context.Response.StatusCode = 500; return; } } context.Response.Write(response.ToString()); string version = "1.0"; //your dynamic version number here context.Response.ContentType = "application/javascript"; context.Response.AddFileDependencies(files.ToArray()); HttpCachePolicy cache = context.Response.Cache; cache.SetCacheability(HttpCacheability.Public); cache.VaryByParams["jsfiles"] = true; cache.VaryByParams["version"] = true; cache.SetETag(version); cache.SetLastModifiedFromFileDependencies(); cache.SetMaxAge(TimeSpan.FromDays(14)); cache.SetRevalidation(HttpCacheRevalidation.AllCaches); } } }
和其伴随的JSControl:
面前:
<customcontrols:JSControl ID="jsControl" runat="server"> <customcontrols:Script File="jquery/jquery-1.3.2.js" /> <customcontrols:Script File="main.js" /> <customcontrols:Script File="creditcardpayments.js" /> </customcontrols:JSControl>
背部:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Web; using System.Web.UI; using System.Linq; namespace WebApplication1 { [DefaultProperty("Scripts")] [ParseChildren(true, "Scripts")] public class JSControl : LiteralControl { [PersistenceMode(PersistenceMode.InnerDefaultProperty)] public List<Script> Scripts { get; set; } public JSControl() { Scripts = new List<Script>(); } protected override void Render(HtmlTextWriter writer) { if (HttpContext.Current.IsDebuggingEnabled) { const string format = "<script src=\"scripts\\{0}\"></script>"; foreach (Script script in Scripts) writer.Write(format, script.File); } else { IEnumerable<string> scriptsArray = Scripts.Select(s => s.File); string scripts = String.Join(",", scriptsArray.ToArray()); string version = "1.0" //your dynamic version number const string format = "<script src=\"scripts/JsHandler.ashx?jsfiles={0}&version={1}\"></script>"; writer.Write(format, scripts, version); } } } public class Script { public string File { get; set; } } }
启用GZIP:
正如Jeff Atwood所说,在您的网站服务器上启用Gzip是一件容易的事。 经过一些跟踪,我决定在以下文件types上启用Gzip:
.css .js .axd(Microsoft Javascript文件).aspx(常用ASP.NET Web窗体内容).ashx(我们的处理程序)在IIS 6.0 Web服务器上启用HTTP压缩:
打开IIS,右键单击网站,服务选项卡,启用压缩应用程序文件和压缩静态文件停止IIS在记事本中打开IIS元数据库(C:\ WINDOWS \ system32 \ inetsrv \ MetaBase.xml) – 并进行备份,重新紧张这些事情定位和覆盖以下两个IIsCompressionScheme和一个IIsCompressionSchemes元素:
而就是这样! 这为我们节省了大量的带宽,并在整个过程中产生了更具响应性的Web应用程序
请享用!
为什么不使用ScriptManager? 这里是一个MVCScriptManager ,将结合和挤压。
使用YUI Compressor或Dojo压缩器。 他们都使用Rhino JSparsing引擎来标记你的代码,因此只有当代码是有效的代码时才会工作。 如果出现错误,他们会让你知道(这是一个不错的IMO!)Packer另一方面,即使它包含错误,将打包你的代码。
我通过构build脚本在我的所有项目中使用YUI。 切勿在飞行中进行压缩,这需要很长的时间。 YUI和Dojo都是基于Java的(ala Rhino),如果你这样做,你会产生后台进程来产生输出 – 不利于性能。 始终在构build时进行。
Rejuicer是一个很棒的ASP.NET新手,它引起了很多热议: http ://rejuice.me
它被configuration为一个HTTP模块,并在运行时执行缩小(一次)并caching输出。
它:
- 具有stream畅的configuration界面
- 允许您指定文件以通配符规则进行缩减
- 在Windows Azure上运行
- 有点神奇地在开发环境中自己closures,所以你可以debugging你的原始JavaScript代码(不缩小)。
configuration(在Global.asax.cs中的ApplicationStart上完成)如下所示:
OnRequest.ForJs("~/Combined.js") .Compact .FilesIn("~/Scripts/") .Matching("*.js") .Cache .Configure();
以下是我用于连接,压缩和cachingCSS和JS文件的内容: http : //gist.github.com/130913
它只需要在bin目录中的Yahoo.Yui.Compressor.dll。 它不会在编译时压缩,但是文件会被caching到一个文件依赖项,所以它们只会被加载一次,直到被修改。
然后我只是把这个代码添加到<head>中:
<link rel="stylesheet" type="text/css" href="/YuiCompressor.ashx?css=reset,style,etc" />
而这只是在</ body>之前:
<script type="text/javascript" src="/YuiCompressor.ashx?js=main,other,etc"></script>
它被devise用于处理同一path上的多个文件,但可以轻松升级以支持不同的path。
我使用基于MSBuild和Microsoft Ajax Minifier的定制解决scheme。 现有的大部分博客post都没有正确处理某些情况,如与TFS构build的集成。
对于每个Web项目,我们创build一个“wpp.targets”文件来扩展Web Publishing Pipeline。 例如,如果项目是“Website.csproj”,则在项目中创build一个名为“Website.wpp.targets”的文件。
将以下代码放置在目标文件中:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Import Project="$(MSBuildExtensionsPath32)\PATH TO YOUR MSBUILD MINIFY TARGETS" /> <!-- Hook up minification task to WPP build process --> <PropertyGroup> <OnAfterPipelineTransformPhase> $(OnAfterPipelineTransformPhase); MinifyResourceFiles; </OnAfterPipelineTransformPhase> </PropertyGroup> <!-- Define temporary location to store minified resources --> <PropertyGroup> <MinifyResourceIntermediateOutput Condition="'$(MinifyResourceIntermediateOutput)'==''">MinifyResourceFiles</MinifyResourceIntermediateOutput> <MinifyResourceIntermediateLocation Condition="'$(MinifyResourceIntermediateLocation)'==''">$(_WPPDefaultIntermediateOutputPath)$(MinifyResourceIntermediateOutput)</MinifyResourceIntermediateLocation> </PropertyGroup> <Target Name="MinifyResourceFiles" DependsOnTargets="PipelineCollectFilesPhase" Condition="'$(Configuration)' == 'Release'"> <!-- Create lists of the resources to minify --> <!-- These extract all Javascript and CSS files from the publishing pipeline "FilesForPackagingFromProject" and create two new lists. The "MinifiedFile" metadata on each item contains the temporary location where the minified file will be stored --> <ItemGroup> <JavaScriptToMinify Include="@(FilesForPackagingFromProject)" Condition="'%(FilesForPackagingFromProject.Extension)' == '.js'"> <MinifiedFile>$(MinifyResourceIntermediateLocation)\minified\%(DestinationRelativePath)</MinifiedFile> </JavaScriptToMinify> <StylesheetToMinify Include="@(FilesForPackagingFromProject)" Condition="'%(FilesForPackagingFromProject.Extension)' == '.css'"> <MinifiedFile>$(MinifyResourceIntermediateLocation)\minified\%(DestinationRelativePath)</MinifiedFile> </StylesheetToMinify> </ItemGroup> <!-- Minify resources --> <!-- These commands should be replaced with the MSBuild Tasks used to perform your minification I use my own custom tasks based on the Microsoft Ajax Minifier DLL The input of the minifier takes a source file directly from the project and outputs to a temporary location --> <MinifyJavaScript SourceFiles="@(JavaScriptToMinify)" DestinationFiles="@(JavaScriptToMinify->'%(MinifiedFile)')" Comments="None" /> <MinifyStylesheet SourceFiles="@(StylesheetToMinify)" DestinationFiles="@(StylesheetToMinify->'%(MinifiedFile)')" Comments="None" /> <!-- Remove the original source files from the packaging system and include the new minfied resources from the temporary location --> <ItemGroup> <!--Remove unminified resources from the pipeline --> <FilesForPackagingFromProject Remove="@(JavaScriptToMinify)" Condition="'@(JavaScriptToMinify)' != ''" /> <FilesForPackagingFromProject Remove="@(StylesheetToMinify)" Condition="'@(StylesheetToMinify)' != ''" /> <!--Add the minified resources at the new loction to the pipeline --> <FilesForPackagingFromProject Include="@(JavaScriptToMinify->'%(MinifiedFile)')" Condition="'@(JavaScriptToMinify)' != ''"/> <FilesForPackagingFromProject Include="@(StylesheetToMinify->'%(MinifiedFile)')" Condition="'@(StylesheetToMinify)' != ''"/> </ItemGroup> </Target> </Project>
缩小目标上的''$(Configuration')=='Release'“条件可以根据您的需要进行修改。 在发布,打包和在服务器上构build时,它会自动缩小(和validation)项目中的所有CSS和JS文件。
您可能需要为服务器构build启用WPP“CopyWebApplication”目标。 为此,请将MSBuild属性UseWP_CopyWebApplication设置为True,并将PipelineDependsOnBuild设置为False。 在包含Web应用程序目标文件之前,我们将这些设置在项目文件中。
我build议http://www.RequestReduce.com最小化和组合CSS和JavaScript以及精灵CSS背景图像,并优化其PNG压缩。; 它在运行时完成所有这些操作并caching输出。 除了添加HttpModule之外,它不需要代码或configuration。 它提供了所有caching的内容,优化了将来的头文件和ETags,以确保浏览器尽可能cachingcss / javascript / sprites。 虽然它不需要configuration,但它具有高度可configuration性,可以设置为使用CDN运行并同步Web场中的caching文件。
所有的javascript,图像和css都是通过HTTP获取的,所以它可以包含来自第三方的css和js,也是一种很好的方式来缩小/合并.axd资源,比如WebResource.axd和ScriptResource.axd。 它通过内容types决定了js和css的存在,所以目标资源可以有任何(或不)的扩展。 它运行在任何基于IIS的技术上,包括MVC的所有版本和视图引擎,Web表单和“网页”。
你可以从http://www.RequestReduce.com下载,从https://github.com/mwrock/RequestReduce下载Nuget或者fork。;