【发布时间】:2013-10-04 10:04:37
【问题描述】:
所以只是为了给你一些背景信息,我正在尝试创建一个生成器,它将创建一些文件(当然基于用户输入)以及更新项目中的一些现有文件(例如添加一条新路线)。
使用this.template 创建文件没问题...问题是:有没有什么方法可以用 Yeoman 做到这一点,而不必使用 Node 读取文件并进行一些奇特的查找和替换?
【问题讨论】:
所以只是为了给你一些背景信息,我正在尝试创建一个生成器,它将创建一些文件(当然基于用户输入)以及更新项目中的一些现有文件(例如添加一条新路线)。
使用this.template 创建文件没问题...问题是:有没有什么方法可以用 Yeoman 做到这一点,而不必使用 Node 读取文件并进行一些奇特的查找和替换?
【问题讨论】:
好的,所以我找到了问题的答案。
Addy Osmani 向我展示了在 this thread on twitter 中的位置,然后我找到了 this link,这正是我所需要的。
它的要点归结为两个函数:readFileAsString 和 write。用法如下:
var path = "/path/to/file.html",
file = this.readFileAsString(path);
/* make modifications to the file string here */
this.write(path, file);
编辑:我也在博客上写过这个on my blog。
正如 Toilal 在 cmets 中提到的:
write方法已不存在,必须替换为writeFileFromString(参数也颠倒过来)——Toilal
然后,正如 ivoba 在 cmets 中提到的那样:
this.writeFileFromString和this.readFileAsString已弃用,现在应该使用 github.com/yeoman/html-wiring,情况有所改变 :) – ivoba
【讨论】:
hooks,它也只会应用第二个修改。
html-wiring 也已弃用。
Yeoman 还使用mem-fs-editor 提供了一种更优雅的 fs 操作方式。
您可以使用this.fs.copy,传递一个流程函数作为选项来对内容进行任何修改:
this.fs.copy(path, newPath, {
process: function(content) {
/* Any modification goes here. Note that contents is a Buffer object */
var regEx = new RegExp('old string', 'g');
var newContent = content.toString().replace(regEx, 'new string');
return newContent;
}
});
这样您还可以利用mem-fs-editor 功能。
【讨论】:
结合@sepans 的出色回答,可以使用一些解析器,而不是使用正则表达式。
来自约曼documentation:
提示:更新现有文件的内容
更新预先存在的文件并不总是一项简单的任务。最可靠的方法是解析文件AST 并对其进行编辑。此解决方案的主要问题是编辑 AST 可能很冗长且有点难以掌握。
一些流行的 AST 解析器是:
- Cheerio 用于解析 HTML。
- Esprima 用于解析 JavaScript - 您可能对 AST-Query 感兴趣,它提供了较低级别的 API 来编辑 Esprima 语法树。
- 对于 JSON 文件,您可以使用原生的JSON object methods。
用正则表达式解析代码文件是危险的,在这样做之前,你应该阅读CS anthropological answers并掌握正则表达式解析的缺陷。如果您确实选择使用 RegEx 而不是 AST 树来编辑现有文件,请小心并提供完整的单元测试。 - 请不要破坏您用户的代码。
更具体地说,当使用 esprima 时,您很可能还需要一些生成器,例如 escodegen 来生成 js。
var templatePath = this.destinationPath(...);
this.fs.copy(templatePath, templatePath, {
process: function (content) {
// here use the parser
return ...
}
});
请注意,您可以在 from、to 参数中使用相同的路径来替换现有文件。
另一方面,这种解析器的缺点是在某些情况下它可能会过多地改变原始文件,虽然安全,但更具侵入性。
【讨论】:
您可以使用mem-fs-editor,并调用fs.append(filepath, contents, [options]) 方法。
例如
this.fs.append(this.contextRoot + "/index.html", " <p>Appended text</p>");
【讨论】:
html太复杂,无法使用append来获得有效结果。我会建议更简单的文件类型,例如这里。例如.gitignore
使用var text = this.fs.read(filePath) 读取文件,使用this.fs.write(filePath, content) 写入某个位置的文件。
【讨论】: