2012-08-15 5 views
44

Sto cercando di utilizzare il raggruppamento per combinare & minify alcuni file CSS. Nel mio Global.aspx.cs Application_Start Ho il seguente:MVC4 bundling CSS failed Token inaspettato, trovato '@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); 

E nel mio file .cshtml Ho la seguente:

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

Tuttavia, quando ho visualizzare l'origine del mio file CSS fasci , si ha la seguente:

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

.... molto altro ancora

Tutte le idee su come ri risolvi questo?

ho fatto stretto verso il basso per la seguente riga:

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

Se ho solo quella riga di codice ottengo gli stessi errori.

risposta

44

Ci sono alcuni problemi qui:

  1. Il problema css è dovuto tra cui il jquery.ui.all.css, come il minifier di default non supporta seguenti importazioni, e questo non è ciò che vuoi fare comunque perché raddoppierà includere tutti i file ui css jQuery. Quindi, ciò che si vuole fare, invece, non è usare * css, e invece esplicitamente elencare ciò che jQuery file ui si desidera includere:

    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. In secondo luogo si vuole essere con i metodi di script/Styles.Render piuttosto che facendo riferimento esplicito all'URL dei bundle come si fa, in quanto gli helper non raggruppano automaticamente/ridimensionano e rendono i singoli riferimenti a ciascun oggetto script/stile quando si trova in modalità di debug e aggiungono un'impronta digitale per il contenuto del bundle nell'URL in modo che il caching del browser possa lavorare in modo propositivo

    @Scripts.Render("~/JSBundle") and @Styles.Render("~/CSSBundle") 
    
  3. È inoltre possibile utilizzare StyleBundle/ScriptBundle che è lo zucchero appena syntaxtic per non dover passare nuova Css/JsMinify.

È anche possibile controllare questo tutorial per maggiori informazioni: Bundling Tutorial

+2

Ti sei perso "~/Content/themes/base/jquery.ui.menu.css" e "~/Content/themes/base/jquery.ui.spinner.css". –

+0

risposta IMPRESSIONANTE! : D Shed un sacco di luce ... –

+2

Beh, non riesce anche a raggruppare quando incontra cose come @ -webkit-keyframes, quindi non è solo fallire su @import. – Triynko

10

O che cosa si può fare è quello di scrivere il proprio BundleTransform per CssMinify se naturalmente è necessario un tale flessibilità. Così, per esempio il codice in BundleConfig.cs assomiglia:

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

Allora che cosa è necessario aggiungere è:

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

E se avete bisogno di qualche altro correzioni/errori è possibile estendere questa logica a Metodo FixCustomCssErrors.

+3

Questa soluzione rimuove efficacemente tutti i '@ import' dai file, corretto? Questo probabilmente non renderà la pagina molto bene. – MEMark

+1

Inoltre, non affronta il fatto che non solo non riesce su @import, ma anche su @ -webkit-keyframes e altri CSS perfettamente validi che non riconosce. Inutili. Nel frattempo, Flash ha risolto questo problema dieci anni fa, fornendo un singolo file SWF, che è stato persino compresso. Ho provato a creare una colonna avvolta verticalmente in HTML (un altro 'Holy Grail', perché è così difficile fare qualcosa di così semplice), solo per imparare che sebbene il CSS 'conteggio colonne' sia stato definito nel 2001, è il 2015 ed è ancora solo parzialmente implementato in Chrome. Anche Flexbox fa schifo, richiedendo un'altezza predefinita per funzionare. – Triynko

+0

quale versione di Bundler usi? Ho VS 2015 con [Microsoft ASP.NET Web Optimization 1.1.3] (https://www.nuget.org/packages/Microsoft.AspNet.Web.Optimization/1.1.3). Non ho errori con '@ -webkit-keyframes' e lo vedo nell'output di buundle. –