2013-03-21 66 views
4

我試圖把一個資源構建系統,該系統由一組目錄加載LESS文件:如何推遲LESS解析器對@import規則的評估?

Common 
├─┬ sub 
│ ├── A 
│ └── B 
├── C 
└── ... 

每個底部級目錄將有一個切入點,index.less。索引文件將包括@import報表,例如@import "colors.less";

我想發生的事情是:

  • 如果導入的文件在當前目錄存在,則使用。
  • 如果該文件不存在,則使用父目錄中相同名稱的文件,遞歸到根目錄。

所以解析/Common/sub/A/index.less時,尋找colors.less在A,然後在sub,然後Common

我已經制定了兩個階段的構建過程的前半部分:

  1. 掃描整個目錄結構和所有文件加載到一個對象:

    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';", ... } } 
          } 
    
  2. 構建導致每個底層目錄的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)。

回答

0

一個有趣的問題。 沒有深入鑽研欠解析器(我假設你想避免像我一樣在這個時刻做)的執行爲什麼不直接添加預解析步:閱讀所有.LESS文件和註釋掉進口?

因此,對通過解析器運行不太文件之前,你可以自己閱讀並寫入文件,註釋掉@import線,並考慮他們的筆記,你做的。然後通過分析器運行它,你會得到一個AST來,你可以附上你剛纔搶到了進口信息。

現在你可以編織所有的AST在任何方式,你已經準備到了一起。

請確保保持較少的文件處於您找到它們的狀態。或者取消註釋這些行,或者稍微好一點的方法是複製要處理的每個文件,註釋掉導入,解析它,然後刪除。這樣你就不用擔心污染原始文件。

好像規避問題的快捷方式。除非你寧願做這樣的事情告訴少解析器本身忽略@import令牌。 (只需要在這裏隨機刺戳,但也許如果你編輯1252行的lib/less/parser.js中的「導入」函數返回new(tree.Comment)(dir);它可能只是將每個@import標記解析爲註釋