2013-02-08 14 views
14

Próbuję renderować pakiet plików CSS, ale dane wyjściowe są w złej kolejności. Próbowałem rozwiązania @MVC4 Beta Minification and Bundling: Ordering files and debugging in browser, ale to nie pomogło. Oto pakiet:MVC4 StyleBundle nie renderuje pakietu w prawidłowej kolejności

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

I oto wynik, jak widać jquery-ui dochodzi do góry.

<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"/> 

Jak mogę się upewnić, że arkusze stylów są renderowane w prawidłowej kolejności?

+0

Doświadczyłem tego, kiedy miałem określony kod CSS wymieniony w więcej niż jednym pakiecie lub gdy włączałem go bezpośrednio do _Layout.cshtml. – da7rutrak

+0

Nie ma odniesienia w więcej niż jednym pakiecie. Musisz umieścić go na _layout.cshtml, jest używany na wszystkich stronach. Co dziwne, jeśli zmienię nazwę pliku na coś innego, np. Jqui.css, problem zniknie. –

+0

Chodzi mi o to, że odwołujesz się do pliku CSS bezpośrednio w _Layout.cshtml, a nie że zawarłeś pakiet w pliku, ponieważ to musi się stać. – da7rutrak

Odpowiedz

21

Łączenie w pary nie ma na celu renderowania plików CSS w dokładnie tej samej kolejności, a wynika z innej logiki. Jeśli potrzebujesz, aby uczynić je zgodnie z definicją, to należy utworzyć niestandardowy IBundleOrderer i ustawić ją na wiązce jako wymagane Zamawiającego:

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

I

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

Wtedy to zrobić nic z listy więc Render wyrenderuje je dokładnie w tej samej kolejności.

Aktualizacja domyślnie zamawiającego

Bundling wykorzystuje koncepcję IBundleOrderer do sortowania elementów w Bundle. Klasa Bundle ma to Orderer nieruchomość, która wygląda następująco:

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

Więc domyślny zamawiający jest rzeczywiście DefaultBundleOrderer aż nadpisać go z niestandardowego zamawiającego.

IBundleOrderer ma następujący podpis:

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

Realizacja DefaultBundleOrderer tego nakazuje plików według BundleContext, oto fragment z realizacji OrderFiles:

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

Więc różni wynik dzieje, ponieważ to. To oczywiście nie jest losowy algorytm sortowania :) Reguły są zdefiniowane w klasie 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); 
} 

Więc kiedy nazywają to od Application_Start:

BundleConfig.RegisterBundles(BundleTable.Bundles); 

Właściwie przekazać domyślne BundleCollection zdefiniowanego w bibliotece.

więc mamy BundleFileSetOrdering przypadki przeszły jeden po drugim do:

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

Zawarcie

Jeśli chcemy, aby uprościć proces możemy powiedzieć, że biblioteka preferuje jakąś plików i dokonuje sortowania na innych plikach, jeśli znaleziono wiele możliwości. Jest to oczekiwane zachowanie przez większość czasu, ale jak widać, można go łatwo zastąpić przez AsDefinedBundleOrderer, więc nie robi nic z podanym zbiorem plików, więc zamówienie pozostaje oryginałem.

+0

Doskonale, dziękuję :) –

+1

"Łączenie w pary nie powinno renderować plików CSS w dokładnie takiej samej kolejności". Gdzie znalazłeś tę informację? Czytam tutorial [tutaj] (http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification) i sprawia, że ​​brzmi to jak preferowane podejście, aby upewnić się, że otrzymujesz poprawne Zamawianie polega na jawnym dodawaniu plików w kolejności, w jakiej mają one być. – bbak

+0

I dla wyjaśnienia, miałem ten sam problem, a twoja odpowiedź go rozwiązała. Chcę tylko zrozumieć, jak działa porządkowanie StyleBundles i dlaczego wydaje się funkcjonować inaczej niż kolejność w składniku ScriptBundles. Wszystkie moje moduły skryptowe zamawiają pliki w sposób zdefiniowany bez potrzeby używania niestandardowego IBundleOrderer – bbak