ASP.NETを使用したExt JSおよびSencha Touchアプリケーションの最小化

ExtJS WebアプリケーションをASP.NET MVCと組み合わせて記述し、ソースファイルを縮小したいが、何らかの理由でこのために標準のSenchaCmdを使用したくない場合は、catにようこそ。 時間がなくて既に試してみたい人のために、記事の最後にライブラリへのリンクがありますが、今のところ、問題が何であるかを理解し、そのようなミニファイヤを自分で書きます。



結果はどうなりますか
public class BundleConfig { public static void RegisterBundles(BundleCollection bundles) { bundles.Add( new SenchaBundle("~/bundles/my-sencha-app") .IncludeDirectory("~/Scripts/my-sencha-app", "*.js", true) ); } }
      
      







イントロ



したがって、ExtJS 4またはSenchaTouch 2ライブラリを使用して開発しており、Webアプリケーションはライブラリ開発者自身の推奨に従って構成されています。 アプリケーションの成長に伴い、ソースの数が増加し、おそらくロードの遅延につながります。または、beautiful索好きな目から美しいソースコードを隠したいだけです。



最初に思い浮かぶのは、Senchaチームが推奨する製品であるSenchaCmdを使用することです。 彼はindex.htmlファイルまたはアプリケーションURLをフィードすることができます。彼は素直にページを取得し、ソースがダウンロードされた順序を追跡し、それをミニファイヤに渡します。



不便は何ですか? ここでは意見が異なる場合がありますが、私見はSenchaCmdファイルを圧縮するために少し重いです。 このプロセスには、Javaアプリケーション、nodejsおよびphantomjsが含まれます。 原則として、サーバーにアップロードする前の縮小などのまれな操作では機能する場合がありますが、まだ微妙な違いがあります。 たとえば、彼に渡さないIndex.cshtml:Razorマークアップのあるセクションは理解できません。 アプリケーションのURLを指定できますが、通過する前にアプリケーション全体がダウンロードされるわけではない認証を使用する場合、すべてのソースが縮小ファイルに含まれるわけではありません。 そして、Windows認証の場合、一般に、すべてが悪いです。



「ここにフォルダがあります。自分で見つけて、圧縮ファイルをください。」と言う方がはるかに簡単です。 インターネットでは、ミニファイヤでいっぱいですが、ソースファイル間の依存関係を確立できる人ではありません。 修正してみましょう。



さあ始めましょう



ASP.NETスタックには、連結と縮小のためのツールが既にバンドルされています。 彼はほんの少しの助けを必要とします-つまり、ソースを接着する順序を伝えるためです。



Bundleconfig.cs
 public class BundleConfig { public static void RegisterBundles(BundleCollection bundles) { bundles.Add( new ScriptBundle("~/bundles/my-sencha-app") { Orderer = // ? } .IncludeDirectory("~/Scripts/my-sencha-app", "*.js", true); ); } }
      
      





必要なもの! Ordererを見てみましょう。



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





入力時、出力時のファイルのコレクション-また、ソートのみ。 それらの配置方法について考えてみましょう。 ExtJSには、依存関係を定義する方法がいくつかあります。



明示的:



暗黙的(構成プロパティのみ):



前者の場合、苦情はありません-コード内の意味はコード内です。 残りは分析に非常に適しています。



プログラムの構造を決定します。 手始めに、JSファイルがあります。 内部にいくつかのクラスを持つことができ、それぞれが他のクラスに依存することができます:



SenchaFile.cs
 public class SenchaFile { /// <summary> ///    /// </summary> public IEnumerable<SenchaClass> Classes { get; set; } /// <summary> ///   /// </summary> public virtual IEnumerable<SenchaFile> Dependencies { get; set; } }
      
      





SenchaClass.cs
 public class SenchaClass { /// <summary> ///   /// </summary> public string ClassName { get; set; } /// <summary> ///   /// </summary> public IEnumerable<string> DependencyClassNames { get; set; } }
      
      





ここで、ファイルに記述されているクラスを何らかの方法で決定する必要があります。 たとえば、常連を検索できますが、このスキルは後で延期します。 特に、Microsoft.Ajax.UtilitiesのJSParserがあるためです。 JSファイルの内容をブロックのツリー形式で提供します。各ブロックは、たとえば、関数呼び出し、プロパティ呼び出しなどです。 ファイル(Ext.application)でアプリケーションインスタンスが作成される場所、クラスが定義または再定義される場所(Ext.define、Ext.override)を見てみましょう。



SenchaFile.cs
 public class SenchaFile { // .. /// <summary> ///  ,    /// </summary> protected virtual IEnumerable<SenchaClass> GetClasses() { var extApps = this.RootBlock.OfType<CallNode>() .Where(cn => cn.Children.Any()) .Where(cn => cn.Children.First().Context.Code == "Ext.application") .Select(cn => cn.Arguments.OfType<ObjectLiteral>().First()) .Select(arg => new SenchaClass(arg) { IsApplication = true }); var extDefines = this.RootBlock.OfType<CallNode>() .Where(cn => cn.Arguments.OfType<ConstantWrapper>().Any()) .Where(cn => cn.Arguments.OfType<ObjectLiteral>().Any()) .Where(cn => { var code = cn.Children.First().Context.Code; return code == "Ext.define" || code == "Ext.override"; }) .Select(cn => { var className = cn.Arguments.OfType<ConstantWrapper>().First().Value.ToString(); var config = cn.Arguments.OfType<ObjectLiteral>().First(); return new SenchaClass(config) { ClassName = className }; }); foreach (var cls in extApps.Union(extDefines)) { yield return cls; } } }
      
      





次のステップは、各クラスの依存関係を決定することです。 これを行うには、同じJSParserを使用して、上記の依存関係決定(明示的および暗黙的)のすべてのケースを実行します。 記事をダウンロードしないようにコードを提供することはしませんが、本質は同じです。必要なプロパティを探してブロックツリーをソートし、使用するクラスの名前を選択します。



これでファイルのリストができました。各ファイルにはクラスが記述されており、各クラスには依存関係があります。 そして、どういうわけかそれらを優先度順に並べる必要があります。 このために、いわゆるトポロジカルソートがあります。 アルゴリズムはシンプルで、興味がある人のためにオンラインデモがあります







SenchaOrderer.cs
 public class SenchaOrderer { /// <summary> ///     /// </summary> /// <param name="node">,   </param> /// <param name="resolved">    </param> protected virtual void DependencyResolve<TNode>(TNode node, IList<TNode> resolved) where TNode: SenchaFile { //        node.Color = SenchaFile.SortColor.Gray; //     foreach (TNode dependency in node.Dependencies) { //        ( ),   if (dependency.Color == SenchaFile.SortColor.White) { DependencyResolve(dependency, resolved); } //    (),   :    else if (dependency.Color == SenchaFile.SortColor.Gray) { throw new InvalidOperationException(String.Format( "Circular dependency detected: '{0}' -> '{1}'", node.FullName ?? String.Empty, dependency.FullName ?? String.Empty) ); } } //  ,    ... //        ,      . node.Color = SenchaFile.SortColor.Black; resolved.Add(node); } /// <summary> ///      /// </summary> /// <param name="files">  </param> /// <returns>  SenchaFileInfo</returns> public virtual IEnumerable<TNode> OrderFiles<TNode>(IEnumerable<TNode> files) where TNode: SenchaFile { var filelist = files.ToList(); //        IList<TNode> unresolved = filelist; IList<TNode> resolved = new List<TNode>(); TNode startNode = unresolved .Where(ef => ef.Color == SenchaFile.SortColor.White) .FirstOrDefault(); while (startNode != null) { DependencyResolve(startNode, resolved); startNode = unresolved .Where(ef => ef.Color == SenchaFile.SortColor.White) .FirstOrDefault(); } return resolved; } }
      
      







それだけです。 いくつかのサービスファイルを使用できます。



Bundleconfig.cs

 public class BundleConfig { public static void RegisterBundles(BundleCollection bundles) { bundles.Add( new SenchaBundle("~/bundles/my-sencha-app") .IncludeDirectory("~/Scripts/my-sencha-app", "*.js", true) ); } }
      
      







Index.cshtml

 ... <script src="@Url.Content("~/bundles/my-sencha-app")" type="text/javascript"></script>
      
      







合計



そのような決定の利点は何ですか? 明らかだと思います。ASP.NETフレームワークが提供する標準機能を使用します。 欠点は何ですか? 彼らも持っています:



このようなミニファイヤはいくつかのプロジェクトで使用されており、そのうちの1つには独特のファイル構造があります。 基本的に、接続すると問題なく起動しましたが、その独特の方法で、ソースを少し調整してスパゲッティの依存関係を削除する必要がありました。



試してみる



  1. NuGet。 SenchaMinifyパッケージ
  2. デモ付きのGitHubプロジェクト


githubには、コマンドライン用のスタンドアロンexeファイル( SenchaMinify.Cmd )も含まれていました。 したがって、希望する人はお気に入りの自動化ツールを使用できます。



私は建設的なアイデアやプルリクエストを喜んでいます。



All Articles