我試圖把一個資源構建系統,該系統由一組目錄加載LESS文件:如何推遲LESS解析器對@import規則的評估?
Common
├─┬ sub
│ ├── A
│ └── B
├── C
└── ...
每個底部級目錄將有一個切入點,index.less。索引文件將包括@import
報表,例如@import "colors.less";
。
我想發生的事情是:
- 如果導入的文件在當前目錄存在,則使用。
- 如果該文件不存在,則使用父目錄中相同名稱的文件,遞歸到根目錄。
所以解析/Common/sub/A/index.less
時,尋找colors.less在A
,然後在sub
,然後Common
。
我已經制定了兩個階段的構建過程的前半部分:
掃描整個目錄結構和所有文件加載到一個對象:
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文件。
第二階段是我遇到過一些問題。首先,我創建一個解析器。
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)底層目錄數量很多,因此我們不得不重新加載並重新解析相同的公共文件多次。
我想要做的是解析第一階段的每個LESS文件,然後在階段二期間根據需要合併AST。
爲了做到這一點,我需要防止LESS在解析過程中評估@import
節點。然後在階段2中,我可以手動查找AST中的@import
節點併合併到已經解析的AST中(遞歸地,因爲它們可以包含它們自己的@import
)。