私は現在、多数のJSファイルを管理しており、依存関係の問題が頭を悩ませています。現在、各関数は別々のファイルにあり、関数間の依存関係を調べるためにデータベースを手動で管理しています。
これを自動化したい。たとえば、関数fがある場合
Array.prototype.f = function() {};
別の関数で参照されているg
MyObject.g = function() {
var a = new Array();
a.f();
};
Gがfを参照していることを検出できるようにしたい。
どうすればこれを行うことができますか?どこから始めればいいですか?実際にコンパイラを作成する必要がありますか、それともたとえばSpidermonkeyを微調整できますか?他の誰かがすでにこれをしましたか?
私を始めるためのポインタは非常に高く評価されています
ありがとうDok
理論的には、MyObject
の使用など、他のファイルで定義されたグローバルの使用を検出する静的分析ツールを作成できますが、prototype
拡張メソッドの使用を現実的に追跡することはできません。
JavaScriptは動的に型付けされた言語であるため、a
関数から渡された場合にg
がArray
であることをツールが知る実用的な方法はありません。したがって、 f()
が呼び出され、依存関係があります。実行時にどの変数がどのタイプを保持するかが決定されるだけなので、インタプリタが必要であり、チューリング完全な問題になっていることがわかります。
角括弧表記によるプロパティのフェッチ、恐ろしいeval
、タイムアウトやイベントハンドラー属性の文字列など、静的分析に完全に反するJavaScriptの他の動的な側面は言うまでもありません。
私はそれが本当に少し初心者ではないと思います。依存関係を手動で追跡する方がおそらく良いでしょうが、依存関係追跡の基本単位となるモジュールに関連する関数をグループ化することにより、依存関係を単純化します。 OK、技術的に必要ないくつかの機能を追加しますが、多すぎないことを願っています。
また、各モジュールに名前空間を付けることもお勧めします。これにより、各呼び出しがどこに行くのかが非常に明確になり、依存関係を手動で(たとえば、// uses: ThisModule, ThatModule
上部のコメント)。
組み込みのプロトタイプの拡張機能は追跡が難しいため、最小限に抑えてください。例を拡張します。 Array
ECMAScript Fifth Editionメソッド(indexOf
など)をまだ持っていないブラウザーに含めることは、すべてのスクリプトが使用する基本的な修正として行うのが良いことです。既存のプロトタイプにまったく新しい任意の機能を追加することには疑問があります。
RequireJS または LabJS のような依存関係マネージャーを使用してみましたか?このスレッドで誰もそれらについて言及していないことに気づきました。
から http://requirejs.org/docs/start.html :
Main.js内で、require()を使用して、実行する必要のある他のスクリプトをロードできます。
require(["helper/util"], function(util) {
//This function is called when scripts/helper/util.js is loaded.
//If util.js calls define(), then this function is not fired until
//util's dependencies have loaded, and the util argument will hold
//the module value for "helper/util".
});
これらの依存関係をネストすることもできるため、helper/utilはそれ自体の中に他のファイルを要求する可能性があります。
@bobinceがすでに示唆しているように、JavaScriptプログラムで静的分析を行うことは、クラックするのがほぼ不可能な問題です。 Google Closureコンパイラ ある程度は実行しますが、 JSDoc コメントからの外部ヘルプにも依存します。
以前のプロジェクトでJSファイルを連結する順序を見つけるという 同様の問題 がありました。JSファイルがたくさんあるため、包含順序を手動で更新するのは面倒に思えました。代わりに、私は自分の目的のために依存関係を構成するものの特定の規則に固執し、それに基づいて単純な regexp :)を使用して正しい包含順序を生成することができました。
このソリューションでは、 トポロジカルソート アルゴリズムを使用して 依存関係グラフ を生成し、すべての依存関係を満たすために含める必要のある順序でファイルを一覧表示しました。各ファイルは基本的に MooTools 構文を使用した疑似クラスであったため、私の状況で依存関係を作成する方法は3つしかありませんでした。
new
キーワードを使用して他のクラスのオブジェクトをインスタンス化したとき。それは単純で、一般的な使用法では間違いなく壊れた解決策でしたが、私にはうまくいきました。このソリューションに興味がある場合は、 コードはこちら -Rubyにあります。
依存関係がより複雑な場合は、コメントと次のような独自の構文を使用して、各JSファイル自体の依存関係を手動で一覧表示できます。
// requires: Array
// requires: view/TabPanel
// requires: view/TabBar
次に、各JSファイルを読み取り、requiresコメントを解析して、必要な包含順序を示す依存関係グラフを作成します。
これらの依存関係を自動的に検出し、それらのロード方法を選択できるツールがあれば便利です。しかし、今日の最良の解決策は少し粗雑です。リストに追加したい特定のニーズに合わせて依存関係マネージャーを作成しました( Pyramid Dependency Manager )。いくつかのユニークなユースケースを解決するいくつかの重要な機能があります。
開発中にどのように機能するかを示すサンプルコード。
ファイル:dependencyLoader.js
//Set up file dependencies
Pyramid.newDependency({
name: 'standard',
files: [
'standardResources/jquery.1.6.1.min.js'
]
});
Pyramid.newDependency({
name:'lookAndFeel',
files: [
'styles.css',
'customStyles.css',
'applyStyles.js'
]
});
Pyramid.newDependency({
name:'main',
files: [
'createNamespace.js',
'views/buttonView.view', //contains just html code for a jquery.tmpl template
'models/person.js',
'init.js'
],
dependencies: ['standard','lookAndFeel']
});
Htmlファイル
<head>
<script src="standardResources/pyramid-1.0.1.js"></script>
<script src="dependencyLoader.js"></script>
<script type="text/javascript">
Pyramid.load('main');
</script>
</head>
依存関係を管理するために単一のファイルを維持する必要があります。ヘッダーのインクルードに基づいてローダーファイルを自動的に生成できるプログラムを作成することを考えていますが、さまざまな種類の依存関係を処理するため、実際にはそれらを1つのファイルに保持する方がよい場合があります。
JSAnalyseは、静的コード分析を使用してjavascriptファイル間の依存関係を検出します。 http://jsanalyse.codeplex.com/
また、許可された依存関係を定義し、たとえばビルド中にそれを保証することもできます。もちろん、JavaScriptは動的な解釈言語であり、すでに述べたようにタイプセーフではないため、すべての依存関係を検出することはできません。しかし、少なくともjavascriptの依存関係グラフを認識し、それを制御し続けるのに役立ちます。
私はこのようなことをするためのツールを書きました: http://github.com/damonsmith/js-class-loader
Java webappがあり、JSコードをJavaスタイルで構造化する場合に最も役立ちます。そうすると、すべてのコードを検出できます。依存関係をバンドルし、実行時と解析時の両方の依存関係をサポートします。