2012-08-15 3 views
44

Ich versuche zu bündeln kombinieren & einige CSS-Dateien zu minimieren. In meinem Global.aspx.cs Application_Start ich habe folgendes:MVC4 Bündelung CSS fehlgeschlagen Unerwartete Token, gefunden '@import'

var jsBundle = new Bundle("~/JSBundle", new JsMinify()); 
    jsBundle.AddDirectory("~/Scripts/", "*.js", false); 
    jsBundle.AddFile("~/Scripts/KendoUI/jquery.min.js"); 
    jsBundle.AddFile("~/Scripts/KendoUI/kendo.web.min.js"); 
    BundleTable.Bundles.Add(jsBundle); 

    var cssBundle = new Bundle("~/CSSBundle", new CssMinify()); 
    cssBundle.AddDirectory("~/Content/", "*.css", false); 
    cssBundle.AddDirectory("~/Content/themes/base/", "*.css", false); 
    cssBundle.AddFile("~/Styles/KendoUI/kendo.common.min.css"); 
    cssBundle.AddFile("~/Styles/KendoUI/kendo.default.min.css"); 
    BundleTable.Bundles.Add(cssBundle); 

Und in meiner .cshtml Datei habe ich die folgenden:

<link href="/CSSBundle" rel="stylesheet" type="text/css" /> 
<script src="/JSBundle" type="text/javascript"></script> 

Allerdings, wenn ich die Quelle meiner Bündel CSS-Datei anzeigen es hat die folgende:

/* Minification failed. Returning unminified contents. 
(40,1): run-time error CSS1019: Unexpected token, found '@import' 
(40,9): run-time error CSS1019: Unexpected token, found '"jquery.ui.base.css"' 

.... viel mehr

Alle Ideen, wie neu löse das?

Ich habe es eng an die folgende Zeile nach unten:

cssBundle.AddDirectory("~/Content/themes/base/", "*.css", false); 

Wenn ich diese Zeile Code nur habe ich die gleichen Fehler zu bekommen.

Antwort

44

Es gibt ein paar Probleme hier:

  1. Das CSS-Problem aufgrund einschließlich der jquery.ui.all.css ist, als die Standard-minifier nicht nach der Einfuhr nicht unterstützt, und das ist nicht das, was Sie möchten sowieso tun, da es alle jquery ui CSS-Dateien enthalten würde. Also, was Sie stattdessen tun möchten, nicht verwenden * .css und stattdessen explizit auflisten, was jQuery UI Dateien, die Sie aufnehmen möchten:

    bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
         "~/Content/themes/base/jquery.ui.core.css", 
         "~/Content/themes/base/jquery.ui.resizable.css", 
         "~/Content/themes/base/jquery.ui.selectable.css", 
         "~/Content/themes/base/jquery.ui.accordion.css", 
         "~/Content/themes/base/jquery.ui.autocomplete.css", 
         "~/Content/themes/base/jquery.ui.button.css", 
         "~/Content/themes/base/jquery.ui.dialog.css", 
         "~/Content/themes/base/jquery.ui.slider.css", 
         "~/Content/themes/base/jquery.ui.tabs.css", 
         "~/Content/themes/base/jquery.ui.datepicker.css", 
         "~/Content/themes/base/jquery.ui.progressbar.css", 
         "~/Content/themes/base/jquery.ui.theme.css")); 
    
  2. Zweitens wollen Sie das Skript/Styles.Render Methoden zu verwenden, anstatt Sie verweisen dabei explizit auf die Bundle-URL, da die Helfer im Debug-Modus nicht automatisch einzelne Verweise auf jedes Skript/Stil-Asset bündeln/verkleinern und auch einen Fingerabdruck für den Bundle-Inhalt an die URL anhängen, damit der Browser-Caching funktioniert arbeiten eigennützig.

    @Scripts.Render("~/JSBundle") and @Styles.Render("~/CSSBundle") 
    
  3. Sie können auch StyleBundle/Scriptbundle benutzen, die nur syntaxtic Zucker ist mit für nicht in neue Css/JsMinify passieren.

Sie können auch für mehr Informationen zu diesem Tutorial finden Sie unter: Bundling Tutorial

+2

Sie vermissten "~/Content/themes/base/jquery.ui.menu.css" und "~/Content/themes/base/jquery.ui.spinner.css". –

+0

FANTASTISCHE Antwort! : D Schüttet viel Licht aus ... –

+2

Nun, es schlägt auch fehl, wenn es auf Dinge wie @ -webkit-keyframes stößt, also scheitert es nicht nur an @import. – Triynko

10

Oder was können Sie tun, ist Ihre eigene BundleTransform für CssMinify zu schreiben, wenn man natürlich eine solche Flexibilität benötigen. So zum Beispiel der Code in BundleConfig.cs wie folgt aussieht:

using System; 
using System.Web.Optimization; 
using StyleBundle = MyNamespace.CustomStyleBundle; 

public class BundleConfig 
{ 
    public static void RegisterBundles(BundleCollection bundles) 
    { 
     bundles.Add(new StyleBundle("~/Content/themes/base/css") 
      .IncludeDirectory("~/Content/themes/base", "*.css")); 
    } 
} 

Was dann müssen Sie hinzufügen ist:

public class CustomStyleBundle : Bundle 
{ 
    public CustomStyleBundle(string virtualPath, IBundleTransform bundleTransform = null) 
     : base(virtualPath, new IBundleTransform[1] 
      { 
       bundleTransform ?? new CustomCssMinify() 
      }) 
    { 
    } 

    public CustomStyleBundle(string virtualPath, string cdnPath, IBundleTransform bundleTransform = null) 
     : base(virtualPath, cdnPath, new IBundleTransform[1] 
      { 
       bundleTransform ?? new CustomCssMinify() 
      }) 
    { 
    } 
} 

public class CustomCssMinify : IBundleTransform 
{ 
    private const string CssContentType = "text/css"; 

    static CustomCssMinify() 
    { 
    } 

    public virtual void Process(BundleContext context, BundleResponse response) 
    { 
     if (context == null) 
      throw new ArgumentNullException("context"); 
     if (response == null) 
      throw new ArgumentNullException("response"); 
     if (!context.EnableInstrumentation) 
     { 
      var minifier = new Minifier(); 
      FixCustomCssErrors(response); 
      string str = minifier.MinifyStyleSheet(response.Content, new CssSettings() 
      { 
       CommentMode = CssComment.None 
      }); 
      if (minifier.ErrorList.Count > 0) 
       GenerateErrorResponse(response, minifier.ErrorList); 
      else 
       response.Content = str; 
     } 
     response.ContentType = CssContentType; 
    } 

    /// <summary> 
    /// Add some extra fixes here 
    /// </summary> 
    /// <param name="response">BundleResponse</param> 
    private void FixCustomCssErrors(BundleResponse response) 
    { 
     response.Content = Regex.Replace(response.Content, @"@import[\s]+([^\r\n]*)[\;]", String.Empty, RegexOptions.IgnoreCase | RegexOptions.Multiline); 
    } 

    private static void GenerateErrorResponse(BundleResponse bundle, IEnumerable<object> errors) 
    { 
     StringBuilder stringBuilder = new StringBuilder(); 
     stringBuilder.Append("/* "); 
     stringBuilder.Append("CSS Minify Error").Append("\r\n"); 
     foreach (object obj in errors) 
      stringBuilder.Append(obj.ToString()).Append("\r\n"); 
     stringBuilder.Append(" */\r\n"); 
     stringBuilder.Append(bundle.Content); 
     bundle.Content = stringBuilder.ToString(); 
    } 
} 

Und wenn Sie einige weitere Korrekturen/Fehler benötigen, können Sie diese Logik erweitern in FixCustomCssErrors-Methode.

+3

Diese Lösung entfernt effektiv alle '@ import' von den Dateien, richtig? Das wird die Seite wahrscheinlich nicht sehr gut darstellen. – MEMark

+1

Es behandelt auch nicht die Tatsache, dass es nicht nur bei @import, sondern auch bei @ -webkit-keyframes und anderen perfekt gültigen CSS fehlschlägt, die es nicht erkennt. Nutzlos. In der Zwischenzeit löste Flash dies vor einem Jahrzehnt und lieferte eine einzige SWF-Datei, die sogar komprimiert wurde. Ich habe versucht, eine vertikal eingepackte Spalte in HTML zu erstellen (ein weiterer "Heiliger Gral", weil es so schwer ist, etwas so Einfaches zu tun), nur um zu lernen, dass "Spaltenzählung" CSS im Jahr 2001 definiert wurde, es aber 2015 ist nur halb in Chrome implementiert. Flexbox saugt auch und benötigt eine vordefinierte Höhe. – Triynko

+0

welche Bundler-Version verwenden Sie? Ich habe VS 2015 mit [Microsoft ASP.NET-Web-Optimierung 1.1.3] (https://www.nuget.org/packages/Microsoft.AspNet.Web.Optimization/1.1.3). Ich habe keine Fehler mit '@ -Webkit-Keyframes' und ich sehe es in Buundles Ausgabe. –