ディレクトリのセットからLESSファイルをロードするリソースビルドシステムをまとめようとしています:
Common
├─┬ sub
│ ├── A
│ └── B
├── C
└── ...
最下層の各ディレクトリには、index.less というエントリ ポイントがあります。インデックス ファイルには @import
、たとえば@import "colors.less";
.
私がしたいことは次のとおりです。
- インポートしたファイルが現在のディレクトリに存在する場合は、それを使用します。
- ファイルが存在しない場合は、親ディレクトリにある同じ名前のファイルをルートまで再帰的に使用します。
したがって、解析するとき/Common/sub/A/index.less
は、colors.less を で、A
次に で探します。sub
Common
2 段階のビルド プロセスの前半は既に開発済みです。
ディレクトリ構造全体をスキャンし、すべてのファイルをオブジェクトにロードします。
common = { files: { "colors.less": "/* LESS file contents */", ... }, sub: { files: { ... }, A: { files: { "index.less": "@import 'colors.less';", ... } }, B: { files: { "index.less": "@import 'colors.less';", ... } } }, C: { files: { "index.less": "@import 'colors.less';", ... } } }
最下位ディレクトリごとに結果の CSS ファイルを作成します。
フェーズ 2 では、いくつかの問題に遭遇しました。まず、パーサーを作成します。
var parser = new less.Parser({
filename: 'index.less'
});
次に、ファイルを解析します。
parser.parse(common.sub.A.files['index.less'], function(e, tree) {
// `tree` is the AST
});
これにより、コールバックに配信される抽象構文ツリー (AST) が取得されます。問題は、LESS パーサー@import
が独自のファイル インポーターで見つけたすべてのステートメントを解決し、インポートされたファイルを現在の AST にマージすることです。
これを回避するために、現在インポーターをオーバーロードしてパスを書き換えています。
// before starting anything:
var importer = less.Parser.importer;
less.Parser.importer = function(path, currentFileInfo, callback, env) {
var newPath;
// here, use the object from phase 1 to resolve the path nearest file
// matching `path` (which is really just a filename), and set `newPath`
importer(newPath, currentFileInfo, callback, env);
};
ただし、LESS インポーターは引き続きディスクからファイルを読み取ります。これは、(A) ファイルの内容が既にメモリ内にあり、(B) 多数の下位レベルのディレクトリがあるため、パフォーマンスの観点からは悪いことです。したがって、同じ共通ファイルを再ロードして再解析する必要があります。ファイルを複数回。
私がやりたいことは、フェーズ 1 ですべての LESS ファイルを解析し、フェーズ 2 で必要に応じて AST をマージすることです。
これを行うには、@import
解析中に LESS がノードを評価しないようにする必要があります。次に、フェーズ 2 で、AST 内のノードを手動で見つけて@import
、既に解析済みの AST にマージします (独自@import
の を含めることができるため、再帰的に)。