46

ここでのこの質問の拡張として、ユーザーコントロールでのJavaScriptライブラリのリンク私は、人々がJavaScriptをオンザフライで、またはビルド時にどのように連結および縮小しているかの例をいくつか見てきました。また、マスターページでどのように機能するかを確認したいと思います。

ページ固有のファイルが現在のように個別に縮小およびリンクされていてもかまいませんが(以下を参照)、メインマスターページのすべてのJavaScriptファイル(約5または6)を連結して縮小したいと思います。

CSSの連結と縮小も組み込んでいる人にはボーナスポイントがあります!:-)

連結して縮小したい一般的な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>


更新:今のところ推奨事項(2013年後半):

MicrosoftASP.NETに組み込まれているBundlingandMinificationを見てみましょう。

4

8 に答える 8

41

これを試して:

私は最近、Web アプリケーションのフロントエンドのパフォーマンスを大幅に改善するために、かなりの量の調査とそれに伴う開発を完了しました。ここで基本的な解決策を共有したいと思いました。

最初にやるべきことは、Yahoo の YSlow と Google の PageSpeed を使用してサイトのベンチマークを行うことです。これらは、実現すべき「簡単に達成できる」パフォーマンスの改善を強調します。まだ行っていない限り、結果として得られる提案には、静的コンテンツの結合、縮小、および gzip がほぼ確実に含まれます。

実行する手順は次のとおりです。

カスタム HTTPHandler を作成して、CSS を組み合わせて縮小します。カスタム HTTPHandler を作成して、JS を組み合わせて縮小します。アプリケーションがデバッグモードでない場合にのみ上記の魔法が行われるようにするメカニズムを含めます。カスタムのサーバー側 Web コントロールを記述して、css/js ファイルのインクルードを簡単に維持します。IIS 6 で特定のコンテンツ タイプの 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 を参照してください)、Yahoo の YUICompressor の .NET ポートを使用して各ファイルを圧縮してから、コンテンツを発信応答ストリームに追加します。

メソッドの残りの部分では、いくつかの HTTP キャッシュ プロパティを設定して、ブラウザ クライアントがコンテンツをダウンロードする (場合によってはダウンロードしない) 方法をさらに最適化します。

サーバー ファーム内のすべてのマシンで同じになるように、コードで Etag を設定します。実際のファイルに Response と Cache の依存関係を設定するため、それらが置き換えられると、キャッシュが無効になります。プロキシがキャッシュできるように Cacheability を設定します。cssfiles 属性を使用して VaryByParams を実行し、ハンドラーを介して送信された CSS ファイル グループごとにキャッシュできるようにします。これは、.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>

したがって、基本的に、サイトがデバッグ モードの場合、次のような 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 を呼び出します。これにより、静的 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 が言うように、Web サイト サーバーで Gzip を有効にするのは簡単です。いくつかのトレースの後、次のファイル タイプで Gzip を有効にすることにしました。

.css .js .axd (Microsoft Javascript ファイル) .aspx (通常の ASP.NET Web フォーム コンテンツ) .ashx (当社のハンドラー) IIS 6.0 Web サーバーで HTTP 圧縮を有効にするには:

IIS を開き、[Web サイト] の [サービス] タブを右クリックして、[アプリケーション ファイルの圧縮] と [静的ファイルの圧縮] を有効にします IIS を停止します IIS メタベースをメモ帳 (C:\WINDOWS\system32\inetsrv\MetaBase.xml) で開きます。 2 つの IIsCompressionScheme 要素と 1 つの IIsCompressionSchemes 要素を見つけて、次のように上書きします。

以上です!これにより帯域幅が大幅に節約され、Web アプリケーション全体の応答性が向上しました。

楽しみ!

于 2009-11-11T22:44:19.247 に答える
14

ScriptManager を使用しないのはなぜですか? AND squishを組み合わせるMVCScriptManagerを次に示します。

于 2009-05-26T22:07:40.637 に答える
7

Professional ASP.NET 3.5の付録で、 Scott Hanselman がPacker for .NETについて語っています。これは、MSBuild と統合され、運用環境などのために javascript ファイルをパックします。

于 2009-05-20T22:41:01.100 に答える
6

YUI Compressor または Dojo Compressor のいずれかを使用します。どちらもコードをトークン化する Rhino JS 解析エンジンを使用するため、コードが有効なコードである場合にのみ機能します。エラーがある場合、彼らはあなたに知らせます (これは素晴らしいボーナス IMO です!) 一方、Packer は、エラーが含まれていてもコードをパックします。

私はすべてのプロジェクトでビルド スクリプトを介して YUI を使用しています。オンザフライで実行しないでください。圧縮には時間がかかりすぎます。YUI と Dojo はどちらも Java ベース (ala Rhino) であり、オンザフライで実行すると、バックグラウンド プロセスを生成して出力を生成することになり、パフォーマンスが低下します。ビルド時に必ず実行してください。

于 2009-05-27T03:17:44.800 に答える
4

Rejuicer は、多くの話題を呼んでいる ASP.NET の優れた新しいミニファイアです: http://rejuice.me

HTTP モジュールとして構成され、実行時に (1 回) 縮小を実行し、出力をキャッシュします。

これ:

  • 構成のための流暢なインターフェースを備えています
  • ワイルドカード ルールを使用して縮小するファイルを指定できます
  • Windows Azure で実行
  • 開発環境ではやや魔法のようにオフになるため、元の JavaScript コード (縮小されていない) をデバッグできます。

構成 (global.asax.cs の ApplicationStart で実行) は次のように単純です。

OnRequest.ForJs("~/Combined.js")
            .Compact
            .FilesIn("~/Scripts/")
              .Matching("*.js")
            .Cache
            .Configure();
于 2011-07-06T10:48:43.293 に答える
2

CSSファイルとJSファイルの連結、圧縮、キャッシュに使用したものは次のとおりです。http: //gist.github.com/130913

binディレクトリにYahoo.Yui.Compressor.dllが必要です。コンパイル時に圧縮されませんが、ファイルはファイル依存関係でキャッシュされるため、変更されるまで1回だけロードされます。

次に、このコードを<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>

すべて同じパスにある複数のファイルで動作するように設計されていますが、異なるパスをサポートするように簡単にアップグレードできます。

于 2009-06-16T21:43:43.087 に答える
2

CSS と JavaScript を最小化して結合し、CSS 背景画像をスプライトし、PNG 圧縮を最適化するhttp://www.RequestReduce.comをお勧めします。これはすべて実行時に行われ、出力がキャッシュされます。HttpModule を追加する以外のコードや構成は必要ありません。キャッシュされたすべてのコンテンツを最適化された遠い将来のヘッダーと ETag で提供し、ブラウザーが css/javascript/sprite を可能な限り長くキャッシュするようにします。構成は必要ありませんが、高度な構成が可能であり、CDN を使用して実行し、Web ファーム全体でキャッシュされたファイルを同期するようにセットアップできます。

すべての JavaScript、画像、および CSS は HTTP 経由で取得されるため、サードパーティの CSS および JS を含めることができます。また、WebResource.axd や ScriptResource.axd などの .axd リソースを縮小/結合する優れた方法でもあります。content-type を介して js と css の存在を判断するため、ターゲット リソースに任意の拡張子を付ける (または付けない) ことができます。MVC、Web フォーム、および「Web ページ」のすべてのバージョンとビュー エンジンを含む IIS ベースのテクノロジで実行されます。

http://www.RequestReduce.comから、Nuget またはhttps://github.com/mwrock/RequestReduceからフォークをダウンロードできます。

于 2011-11-10T17:35:26.730 に答える
2

MSBuild と Microsoft Ajax Minifier に基づくカスタマイズされたソリューションを使用しています。既存のブログ投稿の多くは、TFS ビルドとの統合などの特定のケースを正しく処理していません。

Web プロジェクトごとに、「wpp.targets」ファイルを作成して、Web パブリッシング パイプラインを拡張します。たとえば、プロジェクトが「Website.csproj」の場合、プロジェクトに「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'" 条件は、必要に応じて変更できます。サーバー上で公開、パッケージ化、およびビルドするときに、プロジェクト内のすべての CSS および JS ファイルを自動的に縮小 (および検証) します。

サーバー ビルド用に WPP "CopyWebApplication" ターゲットを有効にする必要がある場合があります。これを行うには、MSBuild プロパティ UseWP_CopyWebApplication を True に設定し、PipelineDependsOnBuild を False に設定します。これらは、Web アプリケーションのターゲット ファイルが含まれる前に、プロジェクト ファイルで設定します。

于 2011-07-22T17:18:24.433 に答える