ウェブサイト全体の大規模な JS/jQuery コードベースをどのように整理しますか? コードの断片を整理する方法に関する優れたリソースはたくさんありますが、すべてをまとめて各断片を適切に配置する方法 (横長のコード整理、同じコードを使用する複数のページ、疎結合による DRY の維持など) に関するリソースはほとんどありません。
以下は私が対処する方法です。私は、このようにコードを整理することにあまり満足していません。なぜなら、それはずさんで保守性やスケーリングの問題につながる可能性があると思うからです。しかし、他に良い方法はよくわかりません。
誰もが独自の要件を持っており、ターンキーソリューションは存在しないことは承知していますが、私が何を間違っているのか、なぜ間違っているのか、そしてより保守しやすいコードを書く方法についての提案などについて、ご意見を伺いたいと思っています。
私が本当に言いたいのは、次のことです。
複数のページ、複数の場所で使用する必要があるロジックをどのように処理しますか?
ページ固有のコードをどのように整理しますか? 各ページをグローバル オブジェクトに名前空間化するのは良い考えですか?1.
アプリがどんどん大きくなっても、組織パターンを何度も書き直さなくて済むようにするには、最初から何をすればよいでしょうか? 私はおそらく、このコードを 4 回目の書き直しをしているところです。2.
各ページはメインの application.js ファイルを受け取ります。各追加ページには独自の application.pagename.js ファイルがあります。サーバー側のロジックを使用してファイルをインクルードし (最初にページにファイルが存在するかどうかを確認します。一部のページでは JS は必要ありません)、次にファイルを順番に初期化します。
私のホームページは次のようになります:
<script src="js/application.js"></script>
<script src="js/application.index.js"></script>
<script>
MyApp.init();
MyApp.index.init();
</script>
私の URL 規則は /page/subpage/id/ です。約 10 ページと多数のサブページがあり、各サブページには独自のロジックが必要です。この投稿の最後の例を参照してください。
私のコードのほとんどはすでに jQuery UI ウィジェットまたは jQuery プラグインにモジュール化されているため、これらのファイル内のコードの 75% はウィジェットを require() して初期化していると言えます。
必要に応じてウィジェットを取得するために requireJS を使用します。
// application.js
var MyApp = {
init: function(){
var self = this;
// these widgets are available on every single page
// notice the call to jquery.deparam.js - i'll use this later to init subpage logic.
require(['js/widget1.js', 'js/widget2.js', 'js/widget3.js', 'js/jquery.deparam.js'], function(){
// deparam the query string. I'll use this later.
self.querystring = $.deparam.querystring();
// init widgets once the document is ready
$(function(){
$("#widget1").widget1();
$("#widget2").widget2();
// make these bindings available immediately as well.
self.rebindable();
});
});
},
// I use jQuery UI Dialog extensively as a window manager, and each dialog is loaded
// via an AJAX request. I'll call this method after each AJAX request to
// rebind some key widgets.
rebindable: function(){
$("#widget3").widget3();
}
};
// application.index.js
// home page specific stuff. this file is only included on the home page.
MyApp.index = {
// my convention is that init is automatically called after the script
// is included in a page, outside of a doc.ready statement.
init: function(){
var self = this;
require(['js/widget4.js'], function(){
$(function(){
self.widget4( $("#foo") );
});
});
},
// passing elements to each method allows me to call this init code
// outside of the index page. I can require() this file, and only init
// widget4, and even use a different element.
widget4: function( element ){
var config = {
something: "custom to the home page"
};
element.widget4( config );
}
};
// application.foo.js
// page "foo" stuff
MyApp.foo = {
init: function(){
var self = this;
// this page happens to use the same widget3 and configuration present
// in MyApp.index. this is where things can get sloppy and unmaintainable
// really quickly.
require(['js/application.index.js'], function(){
$(function(){
MyApp.index.widget3( $("#bar") );
});
});
// page "foo" has three subpages (or actions) and require
// their own logic. url convention: /foo/subpage1/
// init whichever page we're on...
switch( self.querystring.subpage ){
case "subpage1":
self.subpage1.init();
break;
case "subpage2":
self.subpage2.init();
break;
case "subpage3":
self.subpage3.init();
break;
}
},
subpage1: function(){
init: function(){
var self = this;
// once the DOM is ready init dialog.
$(function(){
self.dialog( $("#openDialog") );
});
},
dialog: function( element ){
element.bind("click", function(){
$('<div></div>').dialog({
open: function(){
// see what i'm doing here?
MyApp.rebindable();
// maybe more bindings specific to this
// dialog here
}
});
});
}
},
subpage2: function(){
init: function(){
}
},
subpage3: function(){
init: function(){
}
}
};
ベストアンサー1
具体的なご質問にお答えするために、少しお話しさせてください。JavaScriptMVCの機能:
コントローラセットアップ/ティアダウン、拡張性を考慮しながら、jQuery ウィジェットを改善します。
ビューアプリに組み込むことができるクライアント側テンプレートを追加します。
モデルサービス/データ層を抽象化し、サーバーが変更された場合の JS の変更を最小限に抑えてローカライズします。
窃盗依存関係の管理、圧縮、コードのクリーニングを行います。また、すべてのページのすべてのスクリプトを取得し、共有依存関係を把握し、スクリプトを最適なペイロードに結合します。
機能ユニットアプリのテストが可能な限り簡単になります。
ドキュメントJS...そうですね...コードを文書化します
。
さて、具体的な質問ですが、
複数の場所で使用されるロジックをどのように処理しますか?
私は StealJS の依存関係管理システムを使用して、必要な機能をページに読み込みます。依存関係の管理は、ある程度の規模のアプリでは絶対に必要です。簡単に構築できる場合は、RequireJS が適しています。
ページ固有のコードをどのように整理するか
ページ固有のコードは、できるだけ小さくする必要があります。通常、依存関係と「MainController」の読み込みが含まれます。メイン コントローラーは、そのページの機能要件やビジネス要件に従うようにページを構成します。通常、名前空間は次のようになります。
App.Controllers.Main
同じパターンを書くのを止めるにはどうすればいいですか
そうですね、開発には安定したパターンを持つフレームワークを使用することをお勧めします。また、モジュール/プラグイン/ウィジェットをできるだけ小さく(そしてテスト可能に)してください。こうすることで、これらの部分が変更される可能性が大幅に低くなります。
ついに ....
あなたの最大の葛藤は次のようなもののようです:
- 共有機能
- 複数ページ
- タイムリーな読み込み時間
したがって、信頼できる依存関係管理ツールを選択することが非常に重要です。StealJS を使用すると、読み込み時間を最適化できますが、ページ数が多いため、JavaScriptMVC の標準フォルダー構成から外れる必要があります。
RequireJS はより柔軟ですが、多くのファイルを読み込む必要があります。これは遅くなるだけでなく、整理されていない大きな JS ファイルを大量に作成することになります。
読み込み時間に満足しており、コードを不適切なファイルに押し込むようなことがないように感じられる場合は、現在のソリューションが機能すると思われます。
メンテナンス可能な開発の秘訣は、システム/フレームワークで懸念事項をいかに簡単に分離できるかだと思います。アプリをできるだけ小さなパーツに分割することが重要です。さらに、これらのパーツをテストする必要があります。ページの機能について考えると、人は気が散ってしまいます。しかし、開発を本当にスケールさせるには、アプリを小さなパーツに分割し、それらのパーツを簡単に読み込み、何とかして本番環境でアプリを高速に実行できるような何かが本当に必要です。