编写自己的Yeoman生成器-6.使用文件系统

位置上下文和路径

Yeoman文件实用程序基于您在磁盘上始终有两个位置上下文的想法。这些上下文是您的生成器最有可能读取和写入的文件夹。

目标上下文

第一个上下文是目标上下文。目标是Yeoman将脚手架新应用程序的文件夹。它是您的用户项目文件夹,它是您编写大部分脚手架的地方。

目标上下文定义为当前工作目录或包含.yo-rc.json文件的最近父文件夹。该.yo-rc.json文件定义了Yeoman项目的根。此文件允许您的用户在子目录中运行命令并让它们在项目上工作。这确保了最终用户的一致行为。

你可以得到的目标路径使用this.destinationRoot()或通过加入一个路径this.destinationPath('sub/path')

1
2
3
4
5
6
7
8
9
// Given destination root is ~/projects
class extends Generator {
paths() {
this.destinationRoot();
// returns '~/projects'

this.destinationPath('index.js');
// returns '~/projects/index.js'
}

您可以使用手动设置它this.destinationRoot('new/path')。但为了保持一致性,您可能不应该更改默认目标。

如果您想知道用户在哪里运行yo,那么您可以获取路径this.contextRoot。这是yo从中调用的原始路径; 在我们确定项目根目录之前.yo-rc.json。

模板上下文

模板上下文是存储模板文件的文件夹。它通常是您将从中读取和复制的文件夹。

模板上下文默认定义为./templates/。您可以使用覆盖此默认值this.sourceRoot('new/template/path')

您可以使用this.sourceRoot()或通过使用加入路径来获取路径值this.templatePath(‘app/index.js’)。

1
2
3
4
5
6
7
8
9
class extends Generator {
paths() {
this.sourceRoot();
// returns './templates'

this.templatePath('index.js');
// returns './templates/index.js'
}
};

“内存”文件系统

在覆盖用户文件时,Yeoman非常小心。基本上,在预先存在的文件上发生的每个写入都将经历冲突解决过程。此过程要求用户验证将内容覆盖到其文件的每个文件写入。

此行为可防止出现意外错误并限制出错的风险。另一方面,这意味着每个文件都异步写入磁盘。

由于异步API更难使用,Yeoman提供了一个同步文件系统API,其中每个文件都被写入内存文件系统,并且只有在Yeoman运行完毕后才会写入磁盘一次。

此内存文件系统在所有组合的生成器之间共享。

文件工具

生成器公开所有文件方法this.fs,这是mem-fs编辑器的一个实例- 确保检查所有可用方法的模块文档

值得注意的是,虽然this.fs暴露commit,但你不应该在你的发电机中调用它。Yeoman在运行循环的冲突阶段之后在内部调用它。

示例:复制模板文件

这是我们想要复制和处理模板文件的示例。

鉴于内容./templates/index.html是:

1
2
3
4
5
<html>
<head>
<title><%= title %></title>
</head>
</html>

然后,我们将使用该copyTpl方法复制文件,同时将内容作为模板处理。copyTpl正在使用ejs模板语法

1
2
3
4
5
6
7
8
9
class extends Generator {
writing() {
this.fs.copyTpl(
this.templatePath('index.html'),
this.destinationPath('public/index.html'),
{ title: 'Templating with Yeoman' }
);
}
}

一旦生成器运行完毕,public/index.html将包含:

1
2
3
4
5
<html>
<head>
<title>Templating with Yeoman</title>
</head>
</html>

一个非常常见的场景是在提示阶段存储使用用户答案并将其用于模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class extends Generator {
async prompting() {
this.answers = await this.prompt([{
type : 'input',
name : 'title',
message : 'Your project title',
}]);
}

writing() {
this.fs.copyTpl(
this.templatePath('index.html'),
this.destinationPath('public/index.html'),
{ title: this.answers.title } // user answer `title` used
);
}

通过流转换输出文件

生成器系统允许您在每个文件写入上应用自定义过滤器。自动美化文件,规范化空白等是完全可能的。

根据Yeoman进程,我们将每个修改过的文件写入磁盘。这个过程通过一个vinyl对象流(就像gulp一样)。任何生成器作者都可以注册transformStream来修改文件路径和/或内容。

通过该registerTransformStream()方法注册新修改器。这是一个例子:

1
2
var beautify = require('gulp-beautify');
this.registerTransformStream(beautify({indent_size: 2 }));

请注意,任何类型的每个文件都将通过此流传递。确保任何转换流都将通过它不支持的文件。像gulp-ifgulp-filter这样的工具将有助于过滤无效类型并传递它们。

您基本上可以使用任何带有Yeoman转换流的gulp插件来处理在写入阶段生成的文件。

提示:更新现有文件的内容

更新预先存在的文件并不总是一项简单的任务。最可靠的方法是解析文件AST(抽象语法树)并对其进行编辑。这个解决方案的主要问题是编辑AST可能很冗长,有点难以掌握。

一些流行的AST解析器是:

使用RegEx解析代码文件是一条危险的路径,在此之前,您应该阅读此CS人类学答案并掌握RegEx解析的缺陷。如果您确实选择使用RegEx而不是AST树编辑现有文件,请注意并提供完整的单元测试。 - 请,请不要破坏用户的代码。

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2021 朝着牛逼的道路一路狂奔 All Rights Reserved.

访客数 : | 访问量 :