Come posso specificare un ordine di inclusione ScriptBundle esplicito?


91

Sto provando la funzione MVC4 System.Web.Optimization 1.0 ScriptBundle .

Ho la seguente configurazione:

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

e la seguente vista:

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

dove BundlePaths.CanvasScriptsè "~/bundles/scripts/canvas". Rende questo:

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

Fin qui tutto bene, tranne che ~/Scripts/Shared/achievements.jsè il primo script nel sorgente in bundle. Dipende da ogni script incluso prima di esso nel file ScriptBundle. Come posso assicurarmi che rispetti l'ordine in cui aggiungo le istruzioni include al bundle?

Aggiornare

Si trattava di un'applicazione ASP.NET MVC 4 relativamente nuova, ma faceva riferimento al pacchetto pre-rilascio del framework di ottimizzazione. L'ho rimosso e ho aggiunto il pacchetto RTM da http://nuget.org/packages/Microsoft.AspNet.Web.Optimization . Con la versione RTM con debug = true in web.config, @Scripts.Render("~/bundles/scripts/canvas")esegue il rendering dei singoli tag di script nell'ordine corretto.

Con debug = false in web.config, lo script combinato ha prima lo script realments.js, ma poiché è una definizione di funzione (costruttore di oggetti) che viene chiamata in seguito, viene eseguito senza errori. Forse il minifier è abbastanza intelligente da capire le dipendenze?

Ho anche provato l' IBundleOrdererimplementazione suggerita da Darin Dimitrov con RTM con entrambe le opzioni di debug e si è comportata allo stesso modo.

Quindi la versione minimizzata non è nell'ordine che mi aspetto, ma funziona.

Risposte:


18

Non vedo questo comportamento sui bit RTM, stai utilizzando i bit 1.0.0 di Microsoft ASP.NET Web Optimization Framework: http://nuget.org/packages/Microsoft.AspNet.Web.Optimization ?

Ho usato una riproduzione simile al tuo campione, basata su un nuovo sito Web dell'applicazione Internet MVC4.

Ho aggiunto a 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); 

E poi nella pagina dell'indice predefinita, ho aggiunto:

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

E ho verificato che nel javascript minimizzato per il pacchetto, il contenuto di successi.js era dopo modernizr ...


Ho aggiornato alla versione 1.0. Vedi la mia domanda aggiornata. I contenuti di realizzazioni.js sono inclusi per primi nella versione minimizzata, ma funziona poiché è una funzione chiamata in seguito.
jrummell

114

È possibile scrivere un IBundleOrdererordinamento di pacchetti personalizzato ( ) che garantirà che i pacchetti siano inclusi nell'ordine in cui li si registra:

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

e poi:

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

e secondo te:

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

10
Questo dovrebbe funzionare, ma non dovrebbe anche essere necessario, poiché l'ordinatore predefinito generalmente rispetta l'ordine degli include (promuove solo alcuni file speciali all'inizio, ad esempio jquery, reset.css / normalize.css, ecc.). Non dovrebbe promuovere successi.js in cima.
Hao Kung

1
@flipdoubt presenta un problema qui con la riproduzione: aspnetoptimization.codeplex.com/workitem/list/advanced
Hao Kung

1
Funziona perfettamente, grazie! Sono d'accordo però, questo non dovrebbe essere necessario.
CBarr

2
Questo funziona per me. Si stava promuovendo jQueryUI oltre bootstrap quando secondo stackoverflow.com/questions/17367736/... ho bisogno capovolto.
Sethcran

1
@Hao Kung possiamo ordinare i file nella directory include ?
shaijut

52

Grazie Darin. Ho aggiunto un metodo di estensione.

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

Utilizzo

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
Abbastanza lucido! : D In questo momento ho dovuto cambiare FileInfoper BundleFilela firma del metodo di interfaccia. L'hanno cambiato.
Leniel Maccaferri

sì, l'hanno cambiato nella versione prerelease che utilizza il framework
Owin

little Off-Topic: qualcuno ha maggiori informazioni su questo corso BundleFile? Per raggruppare le risorse incorporate, sto cercando di istanziarlo e richiede un VirtualFileparametro (figlio concreto di) nel suo costruttore.
superjos

Ho la stessa domanda, ho bisogno di istanziare BundleFile, ma non so come
Rui

2
@superjos So che è piuttosto vecchio ma risponderò nel caso qualcun altro abbia il problema. Fa parte di System.Web.Optimization.
Talon

47

Aggiornata la risposta fornita da SoftLion per gestire le modifiche in MVC 5 (BundleFile vs FileInfo).

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

Utilizzo:

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

Mi piace usare una sintassi fluente ma funziona anche con una singola chiamata al metodo e tutti gli script passati come parametri.


2
Lavora in MVC 5. Grazie
Pascal Carmoni

4
Eccellente. Questo dovrebbe essere incluso da MS imho
Angelo

funziona alla grande anche in Web Forms ... fondamentalmente dovrebbe funzionare bene per tutte le ultime versioni!
Sunny Sharma

Soluzione molto pulita e semplice. Molte grazie.
bunjeeb

5

Dovresti essere in grado di impostare l'ordine con l'aiuto di BundleCollection.FileSetOrderList. Dai un'occhiata a questo post del blog: http://weblogs.asp.net/imranbaloch/archive/2012/09/30/hidden-options-of-asp-net-bundling-and-minification.aspx . Il codice nella tua istanza sarebbe qualcosa del tipo:

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

Si dovrebbe considerare l'utilizzo di Cassette http://getcassette.net/ Supporta il rilevamento automatico delle dipendenze degli script in base ai riferimenti agli script trovati all'interno di ogni file.

Se preferisci attenersi alla soluzione MS Web Optimization ma ti piace l'idea di organizzare gli script in base ai riferimenti agli script, dovresti leggere il mio post sul blog all'indirizzo http://blogs.microsoft.co.il/oric/2013/12/27/building-single -page-application-bundle-orderer /


1

La risposta di @Darin Dimitrov funziona perfettamente per me, ma il mio progetto è scritto in VB, quindi ecco la sua risposta convertita in 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

Per usarlo:

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

Continuo a ricevere questo errore: Class 'AsIsBundleOrderer' must implement 'Function OrderFiles(context as ....)' for interface 'System.Web.Optimization.IBundleOrderer'qualche idea?
Mark Pieszak - Trilon.io
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.