明示的なScriptBundleインクルード順序を指定するにはどうすればよいですか?


91

私はアウトしようとしているMVC4 System.Web.Optimization 1.0 ScriptBundle機能を

次の設定があります。

public class BundleConfig
{
    public static void RegisterBundles(BundleCollection bundles)
    {
        // shared scripts
        Bundle canvasScripts =
            new ScriptBundle(BundlePaths.CanvasScripts)
                .Include("~/Scripts/modernizr-*")
                .Include("~/Scripts/json2.js")
                .Include("~/Scripts/columnizer.js")
                .Include("~/Scripts/jquery.ui.message.min.js")
                .Include("~/Scripts/Shared/achievements.js")
                .Include("~/Scripts/Shared/canvas.js");
        bundles.Add(canvasScripts);
    }
}

そして次のビュー:

<script type="text/javascript" src="@Scripts.Url(BundlePaths.CanvasScripts)"></script>

はどこBundlePaths.CanvasScriptsですか"~/bundles/scripts/canvas"。これをレンダリングします:

<script type="text/javascript" src="/bundles/scripts/canvas?v=UTH3XqH0UXWjJzi-gtX03eU183BJNpFNg8anioG14_41"></script>

これまでのところ~/Scripts/Shared/achievements.js、バンドルされたソースの最初のスクリプトを除いて、これで十分です。それは、その前に含まれるすべてのスクリプトに依存しScriptBundleます。バンドルにincludeステートメントを追加する順序を尊重するようにするにはどうすればよいですか?

更新

これは比較的新しいASP.NET MVC 4アプリケーションでしたが、最適化フレームワークのプレリリースパッケージを参照していました。私はそれを削除し、RTMパッケージをhttp://nuget.org/packages/Microsoft.AspNet.Web.Optimizationから追加しました。web.configにdebug = trueを指定したRTMバージョンを使用@Scripts.Render("~/bundles/scripts/canvas")すると、個々のスクリプトタグが正しい順序でレンダリングされます。

web.configでdebug = falseを使用すると、結合されたスクリプトは最初にachievements.jsスクリプトを持ちますが、後で呼び出される関数定義(オブジェクトコンストラクター)があるため、エラーなしで実行されます。おそらく、ミニファイアは依存関係を理解するのに十分スマートですか?

またIBundleOrderer、Darin DimitrovがRTMで両方のデバッグオプションを使用して提案した実装も試しましたが、動作は同じでした。

そのため、縮小版は期待どおりの順序ではありませんが、機能します。

回答:


18

RTMビットでこの動作が見られません。MicrosoftASP.NET Web最適化フレームワーク1.0.0ビットを使用していますか。http//nuget.org/packages/Microsoft.AspNet.Web.Optimization

新しいMVC4インターネットアプリケーションWebサイトに基づいて、サンプルと同様の再現を使用しました。

BundleConfig.RegisterBundlesに追加しました:

        Bundle canvasScripts =
            new ScriptBundle("~/bundles/scripts/canvas")
                .Include("~/Scripts/modernizr-*")
                .Include("~/Scripts/Shared/achievements.js")
                .Include("~/Scripts/Shared/canvas.js");
        bundles.Add(canvasScripts); 

そして、デフォルトのインデックスページに、私は追加しました:

<script src="@Scripts.Url("~/bundles/scripts/canvas")"></script>

バンドルの縮小されたJavaScriptでは、achievements.jsのコンテンツがmodernizrの後であることを確認しました...


1.0バージョンにアップグレードしました。私の更新された質問を参照してください。achievements.jsの内容は最初に縮小版に含まれていますが、後で呼び出される関数から機能します。
jrummell 2012

114

カスタムバンドル注文者(IBundleOrderer)を作成して、登録した順序にバンドルが含まれるようにすることができます。

public class AsIsBundleOrderer : IBundleOrderer
{
    public virtual IEnumerable<FileInfo> OrderFiles(BundleContext context, IEnumerable<FileInfo> files)
    {
        return files;
    }
}

その後:

public class BundleConfig
{
    public static void RegisterBundles(BundleCollection bundles)
    {
        var bundle = new Bundle("~/bundles/scripts/canvas");
        bundle.Orderer = new AsIsBundleOrderer();
        bundle
            .Include("~/Scripts/modernizr-*")
            .Include("~/Scripts/json2.js")
            .Include("~/Scripts/columnizer.js")
            .Include("~/Scripts/jquery.ui.message.min.js")
            .Include("~/Scripts/Shared/achievements.js")
            .Include("~/Scripts/Shared/canvas.js");
        bundles.Add(bundle);
    }
}

そしてあなたの見解では:

@Scripts.Render("~/bundles/scripts/canvas")

10
これは機能するはずですが、デフォルトの順序付け子は一般的にインクルードの順序を尊重するため、これも不要である必要があります(jquery、reset.css / normalize.cssなどのいくつかの特別なファイルのみを上位に昇格します)。これは、achievements.jsをトップに宣伝するものではありません。
Hao Kung

1
@flipdoubtが問題をここに再現で提出:aspnetoptimization.codeplex.com/workitem/list/advanced
Hao Kung

1
これは完璧に機能します、ありがとう!ただし、これは必要ないはずです。
CBarr 2013

2
これでうまくいきます。stackoverflow.com/questions/17367736/によれば、ブートストラップよりもjqueryuiを促進していました… フリップする必要があります。
Sethcran 2014年

1
@Hao Kung インクルードディレクトリのファイルを注文できますか?
shaijut 2016年

52

ダリンさん、ありがとうございます。拡張メソッドを追加しました。

internal class AsIsBundleOrderer : IBundleOrderer
{
    public virtual IEnumerable<FileInfo> OrderFiles(BundleContext context, IEnumerable<FileInfo> files)
    {
        return files;
    }
}

internal static class BundleExtensions
{
    public static Bundle ForceOrdered(this Bundle sb)
    {
        sb.Orderer = new AsIsBundleOrderer();
        return sb;
    }
}

使用法

bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                    "~/Scripts/jquery-{version}.js",
                    "~/Scripts/jquery-migrate-{version}.js",

                    "~/Scripts/jquery.validate.js",
                    "~/Scripts/jquery.validate.messages_fr.js",
                    "~/Scripts/moon.jquery.validation-{version}.js",

                    "~/Scripts/jquery-ui-{version}.js"
                    ).ForceOrdered());

9
かなり滑らかです!:D今は、インターフェイスメソッドのシグネチャを変更する必要FileInfoがありBundleFileました。彼らはそれを変えた。
Leniel Maccaferri 2013

はい、
Owin

少しオフトピック:誰かがこのBundleFileクラスについてもっと情報を持っていますか?埋め込みリソースをバンドルするために、それをインスタンス化しようとしていますがVirtualFile、コンストラクターに(の具体的な子)パラメーターが必要です。
superjos 2013

同じ質問があります。BundleFileをインスタンス化する必要がありますが、方法がわかりません
Rui

2
@superjosこれはかなり古いことを知っていますが、他の誰かが問題を抱えている場合に備えて回答します。これはSystem.Web.Optimizationの一部です。
Talon、2015年

47

MVC 5の変更(BundleFileとFileInfo)を処理するためにSoftLionが提供する回答を更新しました。

internal class AsIsBundleOrderer : IBundleOrderer
{
    public virtual IEnumerable<BundleFile> OrderFiles(BundleContext context, IEnumerable<BundleFile> files)
    {
        return files;
    }
}

internal static class BundleExtensions
{
    public static Bundle ForceOrdered(this Bundle sb)
    {
        sb.Orderer = new AsIsBundleOrderer();
        return sb;
    }
}

使用法:

    bundles.Add(new ScriptBundle("~/content/js/site")
        .Include("~/content/scripts/jquery-{version}.js")
        .Include("~/content/scripts/bootstrap-{version}.js")
        .Include("~/content/scripts/jquery.validate-{version}")
        .ForceOrdered());

私は流暢な構文を使用するのが好きですが、単一のメソッド呼び出しとパラメーターとして渡されるすべてのスクリプトでも機能します。


2
MVC 5で動作します。ありがとう
Pascal Carmoni 2014

4
優れた。これはMS imhoによって含まれる必要があります
アンジェロ

Webフォームの魅力のようにも動作します...基本的に、すべての最新バージョンで正常に動作するはずです!
Sunny Sharma 2016年

非常にクリーンでシンプルなソリューション。どうもありがとう。
bunjeeb 2016年

5

BundleCollection.FileSetOrderListを使用して順序を設定できるはずです。このブログ投稿をご覧くださいhttp : //weblogs.asp.net/imranbaloch/archive/2012/09/30/hidden-options-of-asp-net-bundling-and-minification.aspx。インスタンスのコードは次のようになります。

BundleFileSetOrdering bundleFileSetOrdering = new BundleFileSetOrdering("js");
bundleFileSetOrdering.Files.Add("~/Scripts/modernizr-*");
bundleFileSetOrdering.Files.Add("~/Scripts/json2.js");
bundleFileSetOrdering.Files.Add("~/Scripts/columnizer.js");
bundleFileSetOrdering.Files.Add("~/Scripts/jquery.ui.message.min.js");
bundleFileSetOrdering.Files.Add("~/Scripts/Shared/achievements.js");
bundleFileSetOrdering.Files.Add("~/Scripts/Shared/canvas.js");
bundles.FileSetOrderList.Add(bundleFileSetOrdering);

1

Cassetteの使用を検討する必要がありますhttp://getcassette.net/これは、各ファイル内にあるスクリプト参照に基づくスクリプト依存関係の自動検出をサポートしています。

MS Web最適化ソリューションにこだわりたいが、スクリプト参照に基づいてスクリプトを配置するアイデアが好きな場合は、http://blogs.microsoft.co.il/oric/2013/12/27/building-singleにある私のブログ投稿を読んでください。-page-application-bundle-orderer /


1

@Darin Dimitrovの答えは私には完璧に機能しますが、私のプロジェクトはVBで書かれているので、彼の答えはVBに変換されます

Public Class AsIsBundleOrderer
    Implements IBundleOrderer

    Public Function IBundleOrderer_OrderFiles(ByVal context As BundleContext, ByVal files As IEnumerable(Of FileInfo)) As IEnumerable(Of FileInfo) Implements IBundleOrderer.OrderFiles
        Return files
    End Function
End Class

それを使用するには:

Dim scriptBundleMain = New ScriptBundle("~/Scripts/myBundle")
scriptBundleMain.Orderer = New AsIsBundleOrderer()
scriptBundleMain.Include(
    "~/Scripts/file1.js",
    "~/Scripts/file2.js"
)
bundles.Add(scriptBundleMain)

このエラーが発生し続けます:Class 'AsIsBundleOrderer' must implement 'Function OrderFiles(context as ....)' for interface 'System.Web.Optimization.IBundleOrderer'何かアイデアはありますか?
Mark Pieszak-Trilon.io 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.