2013-03-21 65 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标记解析为注释