2012-08-16 5 views
88

Ich probiere die MVC4 System.Web.Optimization 1.0 ScriptBundle feature aus.Wie kann ich eine explizite ScriptBundle-Include-Reihenfolge angeben?

Ich habe folgende Konfiguration:

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); 
    } 
} 

und die folgende Ansicht:

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

wo BundlePaths.CanvasScripts"~/bundles/scripts/canvas" ist. Es macht dies:

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

So weit so gut, außer ~/Scripts/Shared/achievements.js das erste Skript in der gebündelten Quelle ist. Es hängt von jedem Skript ab, das davor in der ScriptBundle enthalten ist. Wie kann ich sicherstellen, dass die Reihenfolge beachtet wird, in der ich include-Anweisungen zum Bundle hinzufüge?

aktualisieren

Das war eine relativ neue 4 ASP.NET MVC-Anwendung, aber es war Referenzierung der Optimierung Rahmen Pre-Release-Paket. Ich entfernte es und fügte das RTM-Paket von http://nuget.org/packages/Microsoft.AspNet.Web.Optimization hinzu. Bei der RTM-Version mit debug = true in web.config rendert @Scripts.Render("~/bundles/scripts/canvas") die einzelnen Skript-Tags in der richtigen Reihenfolge.

Mit debug = false in web.config hat das kombinierte Skript zuerst das Skript achievements.js, aber da es eine Funktionsdefinition (Objektkonstruktor) ist, die später aufgerufen wird, wird es ohne Fehler ausgeführt. Vielleicht ist der Minifier schlau genug, Abhängigkeiten herauszufinden?

Ich versuchte auch die IBundleOrderer Implementierung, die Darin Dimitrov mit RTM mit beiden Debug-Optionen vorgeschlagen und es das gleiche Verhalten.

Also die verkleinerte Version ist nicht in der Reihenfolge, die ich erwarte, aber es funktioniert.

Antwort

17

Ich sehe dieses Verhalten auf den RTM-Bits nicht, verwenden Sie die Mi crosoft ASP.NET Weboptimierungs-Framework 1.0.0 Bits: http://nuget.org/packages/Microsoft.AspNet.Web.Optimization?

Ich verwendete eine ähnliche Repro zu Ihrer Probe, basierend auf einer neuen MVC4 Internet-Anwendung Website.

ich BundleConfig.RegisterBundles hinzugefügt:

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

Und dann in der Standard-Index-Seite, ich hinzugefügt:

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

Und ich festgestellt, dass in der minimierte Javascript für das Bündel, der Inhalt of achievements.js war nach der Modernisierung ...

+0

Ich habe auf die Version 1.0 aktualisiert. Siehe meine aktualisierte Frage. Die Inhalte von achievements.js sind zuerst in der verkleinerten Version enthalten, funktionieren aber seit ihrer später aufgerufenen Funktion. – jrummell

110

Sie könnten ein eigenes Bündel Besteller (IBundleOrderer) schreiben, die Bündel wird sichergestellt, in der Reihenfolge enthalten sind, können Sie sie registrieren:

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

und dann:

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); 
    } 
} 

und in der Ansicht:

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

Danke, ich werde das versuchen. – jrummell

+10

Dies sollte funktionieren, aber es sollte auch nicht notwendig sein, da der Standardorderer im Allgemeinen die Reihenfolge der Includes respektiert (es werden nur einige spezielle Dateien an die Spitze befördert, d. H. Jquery, reset.css/normalize.css, etc.). Es sollte keine Erfolge erzielen.js nach oben. –

+0

@HaoKung Ich finde den Standard-Orderer und sogar dieser AsIsBundleOrderer fördert konsequent meine benutzerdefinierte Site.js vor jquery-x.js. Wo kann ich meine Repro einreichen? – flipdoubt

50

Danke Darin. Ich habe eine Erweiterungsmethode hinzugefügt.

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; 
    } 
} 

Nutzungs

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()); 
+8

Ziemlich glatt! : D Jetzt musste ich 'FileInfo' für' BundleFile' in der Interface-Methodensignatur ändern. Sie haben es geändert. –

+0

ja, sie haben es in der Vorabversion geändert, die das Owin-Framework verwendet – Softlion

+0

kleines Off-Topic: Hat jemand mehr Informationen über diese 'BundleFile'-Klasse? Um eingebettete Ressourcen zu bündeln, versuche ich dies zu instanziieren und es erfordert einen (konkreten Kind von) 'VirtualFile' Parameter in seinem Konstruktor. – superjos

4

Sie sollten den Auftrag mit Hilfe des BundleCollection.FileSetOrderList einstellen können. Sehen Sie sich diesen Blogbeitrag an: http://weblogs.asp.net/imranbaloch/archive/2012/09/30/hidden-options-of-asp-net-bundling-and-minification.aspx. Der Code in Ihrem Beispiel wäre so etwas wie:

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); 
0

@Darin Dimitrov Antwort funktioniert perfekt für mich, aber mein Projekt ist in VB geschrieben, also hier seine Antwort

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 

VB konvertiert zu Verwenden es:

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

Ich bekomme diesen Fehler immer wieder: 'Class 'AsIsBundleOrderer' muss 'Function OrderFiles (context as ....)' für die Schnittstelle 'System.Web.Optimization.IBundleOrderer' implementieren. Irgendwelche Ideen? –

46

aktualisiert die Antwort zur Verfügung gestellt von SoftLion zu behandeln Änderungen in MVC 5 (BundleFile lesen vs Dateiinfo).

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; 
    } 
} 

Verbrauch:

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()); 

ich fließend Syntax mag mit, aber es funktioniert auch mit einem einzigen Methodenaufruf und alle als Parameter übergeben Skripten.

+2

Funktioniert in MVC 5. Danke –

+4

Ausgezeichnet. Dies sollte von MS imho – Angelo

+0

enthalten sein funktioniert wie ein Charme in Web Forms ... im Grunde sollte es gut für die neuesten Versionen funktionieren! –