2013-03-12 14 views
11

私はちょっと気になりません。 ASPにRick Andersons Blogpost about bundling and minificationに示すように、まず私は、インストール・パッケージドットなしASP.NET MVC4 Appは、デベロッパーで動作している間、本番環境でBootstrap.LESSをコンパイルできません

その後

と同様Bootstrap.less

インストール・パッケージにnugetを使用しました.net mvc、私はLessTransformクラスを作成しました。私は2つの空の無限のファイルを設定し、それらをパッケージ化した新しいバンドルを作成しました...

var lessBundle = new Bundle("~/MyLess").IncludeDirectory("~/Content/MyLess", "*.less", true); 
    lessBundle.Transforms.Add(new LessTransformer()); 
    lessBundle.Transforms.Add(new CssMinify()); 
    bundles.Add(lessBundle); 

それはうまくいきました。それから私は、ブートストラップのJavaScriptへ

bundles.Add(new StyleBundle("~/Bootstrap").Include("~/Content/Bootstrap/less/bootstrap.less")); 

とScriptBundle ...(基本的には船をbootstrap.less他のすべての.lessのファイルを含めるように@importを使用しています)、メインbootstrap.lessファイルに新しいStyleBundleを追加しました...

bundles.Add(new ScriptBundle("~/bundles/Bootstrap").Include("~/Scripts/bootstrap/js/bootstrap-*")); 

すべての出荷されたブートストラップ - * .jsファイルとTADAAがすべて正常に機能しました。インポートされたすべてのJavaScriptファイルが適切に読み込まれたことを含むCSSがコンパイルされました。

しかし...のみとすぐに私は1つのファイルにバンドルし、縮小は、私が問題に遭遇した正常に動作するかどうかを確認するために、デバッグを無効にするよう

<compilation debug="true" targetFramework="4.5"/> 

で開発モードのために働いているすべての。

バンドルプロセスも私をboggles縮小さbootstrap.javascriptバンドルを見たbootstrap.less

/* Minification failed. Returning unminified contents. 
(11,1): run-time error CSS1019: Unexpected token, found '/' 
(11,2): run-time error CSS1019: Unexpected token, found '/' 
(12,1): run-time error CSS1031: Expected selector, found '@import' 
(12,1): run-time error CSS1025: Expected comma or open brace, found '@import' 
(12,27): run-time error CSS1019: Unexpected token, found '/' 
(12,28): run-time error CSS1019: Unexpected token, found '/' 

... here go many many lines like these 

(60,25): run-time error CSS1019: Unexpected token, found ';' 
(62,1): run-time error CSS1019: Unexpected token, found '/' 
(62,2): run-time error CSS1019: Unexpected token, found '/' 
(63,1): run-time error CSS1031: Expected selector, found '@import' 
(63,1): run-time error CSS1025: Expected comma or open brace, found '@import' 
(63,27): run-time error CSS1019: Unexpected token, found '/' 
(63,28): run-time error CSS1019: Unexpected token, found '/' 
: run-time error CSS1067: Unexpected end of file encountered 
*/ 
/*! 
* Bootstrap v2.3.1 
* 
* Copyright 2012 Twitter, Inc 
* Licensed under the Apache License v2.0 
* http://www.apache.org/licenses/LICENSE-2.0 
* 
* Designed and built with all the love in the world @twitter by @mdo and @fat. 
*/ 

// Core variables and mixins 
@import "variables.less"; // Modify this for custom colors, font-sizes, etc 
@import "mixins.less"; 

... and the rest of the original bootstrap.less... no style definitions 

にインポートされたすべてのものを.lessファイルをインポートするために失敗しているようです。 dev内、ページをロードした後、今bootstrap.javascriptにはJavaScriptコンソールが

Uncaught TypeError: Cannot read property 'Constructor' of undefined 

私は密接に私の問題に関連したように見えたいくつかのトピックを見て持っていたと述べてグーグルにバンドルし、縮小された後に全く問題ありませんでした私はいくつかのことを試みましたが、これまでに成功していませんでした。

私の状況に若干の光を当て、私が逃していることや間違っていることを指摘してくれる人には、前もって感謝します。 Ingo

+0

これは素晴らしいです!どうもありがとう。ちょうど一thougth。 nugetのブートストラップをインストールしないと、少ないファイルで変更を上書きするアソシエーションが作成されますか?それはあなたが変更を必要としていると仮定しています。 –

+0

こんにちは、Bootstrap.lessをインストールするだけで.lessと.jsファイルがアプリケーションのcontent/scriptsフォルダにインストールされます。 dotlessをインストールすると、web.configにいくつかのエントリが追加されます。 – Ingo

+0

その上、ナゲットは何も上書きしません。どのように使用するかはあなた次第です。 .lessファイルをcssにプリコンパイルできますが、これは私がやりたいことではありません。以下の解決策は、あなたのアプリケーションで、just-in-timeをlessからコンパイルすることができます。私のわずかな変更により、.less-filesのソースとして複数のディレクトリを持つことができます。 – Ingo

答えて

10

ブートストラップをless-fileとして使用し、開発マシンと本番マシンでのバンドルと縮小について心配しないようにするには、次の方法を検討することがあります。

注:DEBUGgingが有効な場合にLess-Filesで再生する場合は、このすべてを実行する必要はありません。しかし、アプリケーションをWindows Azureのようなプロダクションサーバー上で稼働させたいと思ったらすぐに、束縛と縮小の手順に注意を払うことなく、少ないファイルを変更したいと思っています。私は私がしようと思いました「BundleSource」(さらにポスト下の変形例2を参照)私は違った問題にアプローチしなければならなかったし、修正しなければならなかった、で少し立ち往生感じた問題点を解決するために、そう

を働きます持っているように。

この回答の最後に2番目の変更/警告を読んでください。


変形例1)

だから、仕事の最初と大きな部分は、ブートストラップレスのファイルが作業のバンドルを取得することです。これを行うために、Webで見つけたコードを自由にフォークするようにしました(ファイルが少ないバンドルを1つだけ必要とするならば)、自分自身で問題を解決します。あなたが使用したり、いくつかのベースディレクトリで複数のあまりのバンドル...だから私は実際に私をたくさん助けたアプローチを見つけたことがある...

は...それゆえ私は、ASP.NETバンドリングの使用」Kristof Claes for his Blog-Entryに多くの感謝を授与します私は偶然、喜んで偶然に遭遇しました。

Scott Hanselmanがスピーチで示したLessMinify.csを使用して、1つのディレクトリにすべての単一ファイルをLESSファイルでまとめておくのではなく、1つのLESSファイルで作業するようにしました。

しかし、彼は彼のBlog-Entryに示すように、バンドル手順全体を少しずつ拡張しなければならなかった。そうすれば、彼が提案するソリューションは、インポートを使用して1つ少ないファイルをバンドルして、他の少ないファイルをロードすることができます。しかし、ソースディレクトリに追加されたパスを静的に実装することで、少ないファイルを見つけることができます。同じディレクトリ内の少ないバンドルファイルを選択する必要があります。

私は彼のソリューションをもう少し拡張するために自由を取った。 LessBundlingというファイルを作成しました。以下の内容のCS:

using dotless.Core.configuration; 
using dotless.Core.Input; 
using MvcApplication2.Utils; 
using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Runtime.CompilerServices; 
using System.Web; 
using System.Web.Hosting; 
using System.Web.Optimization; 

namespace MvcApplication2.Extensions 
{ 
    // create Less-Minifier (use Type to define source directory of less files [see below at BootstrapFileReader]) 
    public class LessMinify<TFileReader> : CssMinify 
     where TFileReader : IFileReader 
    { 
     public LessMinify() {} 

     public override void Process(BundleContext context, BundleResponse response) 
     { 
      var config = new DotlessConfiguration() 
      { 
       MinifyOutput = true, 
       ImportAllFilesAsLess = true, 
       CacheEnabled = false, 
       LessSource = typeof(TFileReader) 
      }; 

      response.Content = dotless.Core.Less.Parse(response.Content, config); 
      base.Process(context, response); 
     } 
    } 

    // create a LessStyleBundler to allow initializing LessBundle with a single less file that uses imports 
    public class LessStyleBundle<TFileReader> : Bundle 
     where TFileReader : IFileReader 
    { 
     public LessStyleBundle(string virtualPath) 
      : base(virtualPath, new LessMinify<TFileReader>()) {} 

     public LessStyleBundle(string virtualPath, string cdnPath) 
      : base(virtualPath, cdnPath, new LessMinify<TFileReader>()) { } 
    } 

    // create abstract VirtualFileReader from dotless-IFileReader as a Base for localized 
    internal abstract class VirtualFileReader : IFileReader 
    { 
     public byte[] GetBinaryFileContents(string fileName) 
     { 
      fileName = GetFullPath(fileName); 
      return File.ReadAllBytes(fileName); 
     } 

     public string GetFileContents(string fileName) 
     { 
      fileName = GetFullPath(fileName); 
      return File.ReadAllText(fileName); 
     } 

     public bool DoesFileExist(string fileName) 
     { 
      fileName = GetFullPath(fileName); 
      return File.Exists(fileName); 
     } 


     public string GetFullPath(string path) 
     { 
      return HostingEnvironment.MapPath(SourceDirectory + path); 
     } 

     public abstract string SourceDirectory {get;} 
     // implement to return Path to location of less files 
     // e. g. return "~/Content/bootstrap/less/"; 
    } 

    // create BootstrapFileReader overwriting the Path where to find the Bootstrap-Less-Files 
    internal sealed class BootstrapFileReader : VirtualFileReader 
    { 
     public override string SourceDirectory 
     { 
      get { return "~/Content/bootstrap/less/"; } 
     } 
    } 

} 

これは実際に何をしていますか?

  1. LessMinifyがCssMinifyクラスを拡張し、したがって、「通常の」バンドルへの重要な違いは、あなたがtypeof演算(TFileReader)のように定義LessSourceで新しいドットなし・コンフィギュレーションを作成することであるCSSファイルに
    • を縮小化するために必要なすべてのものをもたらします...あなたはバンドラーは/ minifierは以下のファイルを検索しますれているソースディレクトリが含まれていますクラスを定義することができますTFileReader > <を使用することにより
    • を考慮しなければ
  2. LessStyleBundleがバンドルを拡張し、したがって、すべてが、これはLessMinify(ER)がインスタンス化される場所であるように私は再びTFileReaderを使用し、このクラスでは、ファイルに
    • をバンドルするために必要なもたらします
  3. VirtualFileReaderは、ドットなしのインタフェースであるIFileReaderを実装しますより少ないファイルを解析するために必要なすべてのメソッドを定義し、インポートするファイルを見つける場所を指定する
    • クリストフのソリューションを問題に拡張するために、抽象的なプロパティSourceDirectoryを追加しました。VirtualFileReader抽象クラスを作成する必要があります。

これで、必要な数のLessFileReadersを作成できます。あなただけのBootstrapFileReaderはBootstrapFileReaderの唯一の目的は、バンドラ/ minifierが見つかりますするSourceDirectoryためのプロパティのゲッターを持つことであるVirtualFileReader

  • を拡張

    1. に見られるように抽象VirtualFileReaderを拡張する必要があります私の場合、あなたが「TWIをインストールする場合は〜/コンテンツ/ストラップ/以下に横たわっていることは、デフォルトの場所であるべきブートストラップレス・ファイルでまあ

をインポートする以下のファイルtter.bootstrap.less "-nugget。

もう一度あなただけVirtualFileReaderを拡張する新しいクラスを作成し、SourceDirectoryは

対応するパスを返すためのプロパティゲッターを定義する複数の輸入を持っている以下のファイルが含まれ、アプリケーション内の別のディレクトリを、持っていたい場合

あなたが実際にあなただけのBundlerConfig.csにLessStyleBundle-instantionを追加し、本番環境で以下のファイルをバンドルして縮小化するために、このバンドルのメソッドを使用する場合:

bundles.Add(new LessStyleBundle<BootstrapFileReader>("~/bundles/BootstrapCSS") 
    .Include("~/Content/bootstrap/less/bootstrap.less")); 

そしてもちろんあなたの_layout。CSHTMLも容易に調製バンドルを認識しておく必要があり

@Styles.Render("~/bundles/BootstrapCSS") 

変形例2)

今私もこの作業

Inを取得するために追加する必要がありましたマイナーな修正ブートストラップをバンドルする私の最初の試み。私はこれを使用しました。私はこれを使用しませんでした。

bundles.Add(new LessStyleBundle<BootstrapFileReader>("~/Content/BootstrapCSS") 
    .Include("~/Content/bootstrap/less/bootstrap.less")); 

私はJavascriptのルートでCSS/LessとBundlesのルートでContentを使用すると考えました。

しかし、それはそのままでは機能しません。 ASP.netは〜/ Contentで始まるバンドルの作成を許可しません。 403認可が失敗します。私はあなたがさえずりを統合する予定がある場合、これはあなたの少なくとも一部を助けることを願っています。この問題にはない多くの真の解決策があるので

bundles.Add(new LessStyleBundle<BootstrapFileReader>("~/bundles/BootstrapCSS") 
    .Include("~/Content/bootstrap/less/bootstrap.less")); 

:したがってそれに最も簡単な解決策は、〜/バンドルの代わりにを使用することですあなたのasp.net mvc4アプリケーションへのブートストラップ。

よろしく、 インゴ

+0

素晴らしい、あなたは私の日を救った(または仕事の1日を節約した) - ありがとう! –

+0

"〜/ Content"で始めることができないバンドルについてのヒント。 –

2

私は今日同じ問題を抱えていましたが、私は回避策を見つけましたが、より良い解決策も望みます。私はまたあなたが持っているもののようなドットレスとカスタム変換を使用しようとしていました。

回避策:

ビルド前イベント:

"$(SolutionDir)packages\dotless.1.3.1.0\tool\dotless.compiler.exe" "$(ProjectDir)Content\less\bootstrap.less" 

あなたが定期的にCSSの代わりLESSとして含めることができbootstrap.cssファイルを作成します。

このソリューションは、ドットレスを更新するたびにビルドイベントを更新し、バンドルハンドルをきれいにする必要があるため、理想的ではありません。

+0

私はすでにそれをプリコンパイルすることを考えましたが、もし誰かがビルトインビヘイビアを修正する方法を知っていたら本当に好きです。私は実際にasp.net-mvcにバンドルされており、私のためにその仕事をするための小型化が期待されていました。私はセットアップを変更するたびに "私は覚えておく必要がある"というファンではありません。これまでのところ、私はこれを動作させることなく、試し続けます。 回避策をもう一度おねがいします! – Ingo

0

は、私は本当に、本当に代わりWebEssentials 2012をインストールすることをお勧めし。

これは、あなたの.lessからCSSファイルと縮小されたCSSファイルを生成し、代わりにCSSを参照することができます。あなたが.lessに変更するたびにcssを自動的に更新して、ビルド前のステップなどを覚えておく必要はありません。

WebEssentialsをインストールすると、 CoffeeScript、TypeScript、およびLESS。 JSHint、自動minificationとたくさんのより多くの "グッズ"!

+0

はい、WebEssentials 2012はそれを行いますが、私の解決策では私が "LESS"ファイルを変更することを許可している間に、私は何かをしなくてもcssを参照する必要があります...私のソリューションは完璧ですか?おそらく、それはエレガントですか?多分、私はそれを私の怠惰のスケールで多くの点を授与することができます:-) ...しかし、私は完全に最終的な生産システムで私はプリコンパイルされたCSSファイルを使用することを好むことに完全に同意します – Ingo

+1

私はあなたの解決策はエレガント。私はカスタムコードとNuGetパッケージがない別の方法があると言っているだけです。私はそれが開発者としての私たちの性質に反していることを知っていますが、あなたが店で買うことができるとき(またはこの場合は無料で1つ買うことができます)、ドアを開ける必要はありません。 ;-) – RickardN

+0

+1:真実:-) – Ingo

3

各ディレクトリのカスタムクラスを削除するために、Ingoの回避策を変更しました。 また、適切な例外出力を追加しました(そうしないと、すべての例外がサイレントであり、エラーが発生した場合にはファイルが空になります)。

public class LessTransform : IItemTransform 
{ 
    [ThreadStatic] 
    internal static string CurrentParsedFileDirectory; 


    public string Process (string includedVirtualPath, string input) 
    { 
     CurrentParsedFileDirectory = Path.GetDirectoryName (includedVirtualPath); 

     var config = new DotlessConfiguration 
     { 
      MinifyOutput = false, 
      CacheEnabled = false, 
      MapPathsToWeb = true, 
      ImportAllFilesAsLess = true, 
      LessSource = typeof (VirtualFileReader), 
      Logger = typeof (ThrowExceptionLogger) 
     }; 

     return Less.Parse (input, config); 
    } 
} 


internal class VirtualFileReader : IFileReader 
{ 
    public bool UseCacheDependencies 
    { 
     get { return false; } 
    } 


    public byte[] GetBinaryFileContents (string fileName) 
    { 
     return File.ReadAllBytes (GetFullPath (fileName)); 
    } 


    public string GetFileContents (string fileName) 
    { 
     return File.ReadAllText (GetFullPath (fileName)); 
    } 


    public bool DoesFileExist (string fileName) 
    { 
     return File.Exists (GetFullPath (fileName)); 
    } 


    public string GetFullPath (string path) 
    { 
     if (string.IsNullOrEmpty (path)) 
      return string.Empty; 

     return HostingEnvironment.MapPath (path[0] != '~' && path[0] != '/' 
               ? Path.Combine (LessTransform.CurrentParsedFileDirectory, path) 
               : path); 
    } 
} 


public class ThrowExceptionLogger : Logger 
{ 
    public ThrowExceptionLogger (LogLevel level) : base (level) 
    { 
    } 


    protected override void Log (string message) 
    { 
     if (string.IsNullOrEmpty (message)) 
      return; 

     if (message.Length > 100) 
      message = message.Substring (0, 100) + "..."; 

     throw new LessTransformException (message); 
    } 
} 


[Serializable] 
public sealed class LessTransformException : Exception 
{ 
    public LessTransformException (string message) : base (message) 
    { 
    } 
} 

使用法:

bundles.Add (new StyleBundle ("~/styles-bundle/common") 
    .Include ("~/content/bootstrap/bootstrap.less", new LessTransform())); 
+0

素敵な、感謝:-)特に例外処理を追加するアイデア...何とか私は忘れている必要があります - umm - 私はすでにあまりにも空のless-filesを確認するために使用されていたと思う;-) – Ingo

+0

それだけで動作します:) –

関連する問題