2013-02-08 12 views
14

Sto tentando di eseguire il rendering di un pacchetto di file css, ma l'output è nell'ordine sbagliato. Ho provato la soluzione @MVC4 Beta Minification and Bundling: Ordering files and debugging in browser, ma non ha aiutato. Ecco il bundle:MVC4 StyleBundle non esegue il rendering del pacchetto nell'ordine corretto

bundles.Add(new StyleBundle("~/stylesheet") 
    .Include("~/css/main.css") 
    .Include("~/css/mvc.css") 
    .Include("~/js/jquery.thickbox.css") 
    .Include("~/js/jquery.rating.css") 
    .Include("~/css/ProductListing.css") 
    .Include("~/css/dropdown/dropdown.css") 
    .Include("~/css/dropdown/dropdown.vertical.css") 
    .Include("~/js/fancybox/jquery.fancybox-1.3.1.css") 
    .Include("~/css/scartpopup.css") 
    .Include("~/css/ShoppingCart.css") 
    .Include("~/css/ceebox.css") 
    .Include("~/css/tooltip.css") 
    .Include("~/css/recent_blog_posts.css") 
    .Include("~/css/ProductDetail.css") 
    .Include("~/css/jquery-ui-1.7.3.custom.css") 
    .Include("~/css/filter_box.css") 
    .Include("~/css/custom_page.css") 
    .Include("~/css/Checkout.css") 
    .Include("~/css/CheckoutButton.css") 
); 

Ed ecco il risultato, come si può vedere la jquery-ui tratta di top.

<link href="/css/jquery-ui-1.7.3.custom.css" rel="stylesheet"/> 
<link href="/css/main.css" rel="stylesheet"/> 
<link href="/css/mvc.css" rel="stylesheet"/> 
<link href="/js/jquery.thickbox.css" rel="stylesheet"/> 
<link href="/js/jquery.rating.css" rel="stylesheet"/> 
<link href="/css/ProductListing.css" rel="stylesheet"/> 
<link href="/css/dropdown/dropdown.css" rel="stylesheet"/> 
<link href="/css/dropdown/dropdown.vertical.css" rel="stylesheet"/> 
<link href="/js/fancybox/jquery.fancybox-1.3.1.css" rel="stylesheet"/> 
<link href="/css/scartpopup.css" rel="stylesheet"/> 
<link href="/css/ShoppingCart.css" rel="stylesheet"/> 
<link href="/css/ceebox.css" rel="stylesheet"/> 
<link href="/css/tooltip.css" rel="stylesheet"/> 
<link href="/css/recent_blog_posts.css" rel="stylesheet"/> 
<link href="/css/ProductDetail.css" rel="stylesheet"/> 
<link href="/css/filter_box.css" rel="stylesheet"/> 
<link href="/css/custom_page.css" rel="stylesheet"/> 
<link href="/css/Checkout.css" rel="stylesheet"/> 
<link href="/css/CheckoutButton.css" rel="stylesheet"/> 

Come posso essere sicuro che i fogli di stile siano resi nell'ordine corretto?

+0

Ho avuto questo problema quando avevo il riferimento CSS specifico in più di un pacchetto o quando lo includevo direttamente in _Layout.cshtml. – da7rutrak

+0

Non è referenziato in più di un pacchetto. Devo metterlo in _layout.cshtml, è usato in tutte le pagine. Stranamente, se rinominare il file in qualcos'altro, come jqui.css, il problema scompare. –

+0

Intendo che hai fatto riferimento al file CSS direttamente nel _Layout.cshtml, non che hai incluso il bundle nel file come deve succedere. – da7rutrak

risposta

21

Il bundling non deve eseguire il rendering dei file CSS nello stesso ordine, ma segue una logica diversa. Se avete bisogno di rendere loro come definito, allora si dovrebbe creare un custom IBundleOrderer e impostarlo al fascio come il committente richieste:

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

E

var bundle = new StyleBundle("~/stylesheet"); 
bundle.Orderer = new AsDefinedBundleOrderer(); 
bundles.Add(bundle); 

Allora questo non farà nulla con la lista quindi Render li renderà esattamente nello stesso ordine.

Aggiornamento sulla Ordinamento predefinito

impacchettatriciLe utilizza il concetto di IBundleOrderer per ordinare gli elementi all'interno di un Bundle. La classe Bundle ha il Orderer proprietà che assomiglia a questo:

public IBundleOrderer Orderer 
{ 
    get 
    { 
    if (this._orderer == null) 
     return (IBundleOrderer) DefaultBundleOrderer.Instance; 
    else 
     return this._orderer; 
    } 
    set 
    { 
    this._orderer = value; 
    this.InvalidateCacheEntries(); 
    } 
} 

Così il committente di default è in realtà un DefaultBundleOrderer fino a quando si sovrascrive con il committente personalizzato.

Il IBundleOrderer ha la seguente firma:

public interface IBundleOrderer 
{ 
    IEnumerable<FileInfo> OrderFiles(BundleContext context, IEnumerable<FileInfo> files); 
} 

La DefaultBundleOrderer attuazione della presente ordina i file in base alla BundleContext, ecco un frammento di dall'attuazione di OrderFiles:

foreach (BundleFileSetOrdering ordering in (IEnumerable<BundleFileSetOrdering>) context.BundleCollection.FileSetOrderList) 
    DefaultBundleOrderer.AddOrderingFiles(ordering, (IEnumerable<FileInfo>) list, fileMap, foundFiles, result); 

Così il diverso il risultato succede perché questo. Questo è, naturalmente, non è un algoritmo di ordinamento casuale :) Le regole sono definite nella classe BUndleCollection:

public static void AddDefaultFileOrderings(IList<BundleFileSetOrdering> list) 
{ 
    if (list == null) 
    throw new ArgumentNullException("list"); 
    BundleFileSetOrdering bundleFileSetOrdering1 = new BundleFileSetOrdering("css"); 
    bundleFileSetOrdering1.Files.Add("reset.css"); 
    bundleFileSetOrdering1.Files.Add("normalize.css"); 
    list.Add(bundleFileSetOrdering1); 
    BundleFileSetOrdering bundleFileSetOrdering2 = new BundleFileSetOrdering("jquery"); 
    bundleFileSetOrdering2.Files.Add("jquery.js"); 
    bundleFileSetOrdering2.Files.Add("jquery-min.js"); 
    bundleFileSetOrdering2.Files.Add("jquery-*"); 
    bundleFileSetOrdering2.Files.Add("jquery-ui*"); 
    bundleFileSetOrdering2.Files.Add("jquery.ui*"); 
    bundleFileSetOrdering2.Files.Add("jquery.unobtrusive*"); 
    bundleFileSetOrdering2.Files.Add("jquery.validate*"); 
    list.Add(bundleFileSetOrdering2); 
    BundleFileSetOrdering bundleFileSetOrdering3 = new BundleFileSetOrdering("modernizr"); 
    bundleFileSetOrdering3.Files.Add("modernizr-*"); 
    list.Add(bundleFileSetOrdering3); 
    BundleFileSetOrdering bundleFileSetOrdering4 = new BundleFileSetOrdering("dojo"); 
    bundleFileSetOrdering4.Files.Add("dojo.*"); 
    list.Add(bundleFileSetOrdering4); 
    BundleFileSetOrdering bundleFileSetOrdering5 = new BundleFileSetOrdering("moo"); 
    bundleFileSetOrdering5.Files.Add("mootools-core*"); 
    bundleFileSetOrdering5.Files.Add("mootools-*"); 
    list.Add(bundleFileSetOrdering5); 
    BundleFileSetOrdering bundleFileSetOrdering6 = new BundleFileSetOrdering("prototype"); 
    bundleFileSetOrdering6.Files.Add("prototype.js"); 
    bundleFileSetOrdering6.Files.Add("prototype-*"); 
    bundleFileSetOrdering6.Files.Add("scriptaculous-*"); 
    list.Add(bundleFileSetOrdering6); 
    BundleFileSetOrdering bundleFileSetOrdering7 = new BundleFileSetOrdering("ext"); 
    bundleFileSetOrdering7.Files.Add("ext.js"); 
    bundleFileSetOrdering7.Files.Add("ext-*"); 
    list.Add(bundleFileSetOrdering7); 
} 

Così, quando si chiama questo da Application_Start:

BundleConfig.RegisterBundles(BundleTable.Bundles); 

In realtà si passa il default BundleCollection definito nella biblioteca.

Così abbiamo la BundleFileSetOrdering casi passati uno per uno in:

private static void AddOrderingFiles(BundleFileSetOrdering ordering, IEnumerable<FileInfo> files, Dictionary<string, HashSet<FileInfo>> fileMap, HashSet<FileInfo> foundFiles, List<FileInfo> result) 
{ 
    foreach (string key in (IEnumerable<string>) ordering.Files) 
    { 
    if (key.EndsWith("*", StringComparison.OrdinalIgnoreCase)) 
    { 
     string str = key.Substring(0, key.Length - 1); 
     foreach (FileInfo fileInfo in files) 
     { 
     if (!foundFiles.Contains(fileInfo) && fileInfo.Name.StartsWith(str, StringComparison.OrdinalIgnoreCase)) 
     { 
      result.Add(fileInfo); 
      foundFiles.Add(fileInfo); 
     } 
     } 
    } 
    else if (fileMap.ContainsKey(key)) 
    { 
     List<FileInfo> list = new List<FileInfo>((IEnumerable<FileInfo>) fileMap[key]); 
     list.Sort((IComparer<FileInfo>) FileInfoComparer.Instance); 
     foreach (FileInfo fileInfo in list) 
     { 
     if (!foundFiles.Contains(fileInfo)) 
     { 
      result.Add(fileInfo); 
      foundFiles.Add(fileInfo); 
     } 
     } 
    } 
    } 
} 

Conclusione

Se vogliamo semplificare il processo si può dire che la biblioteca preferisce un qualche tipo di file e rende l'ordinamento sugli altri file se sono state trovate più possibilità. Questo è il comportamento atteso per la maggior parte del tempo ma, come puoi vedere, è facilmente sostituibile con lo AsDefinedBundleOrderer, quindi non fa nulla con il set di file specificato in modo che l'ordine resti originale.

+0

Perfetto, grazie :) –

+1

"Il raggruppamento non è pensato per rendere i file CSS nello stesso ordine". Dove hai trovato questa informazione? Sto leggendo il tutorial [qui] (http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification) e fa sembrare l'approccio preferito per assicurarti di ottenere il corretto l'ordine è aggiungendo esplicitamente i file nell'ordine desiderato. – bbak

+0

E per chiarire, stavo avendo lo stesso problema e la tua risposta lo ha risolto per me. Voglio solo capire come funziona l'ordinamento di StyleBundles e perché sembra funzionare diversamente dall'ordinamento per ScriptBundles. Tutti i miei ScriptBundles ordinano i file nel modo in cui definisco senza dover utilizzare l'IBundleOrderer personalizzato – bbak

Problemi correlati