Yeoman 是一个通用的脚手架系统,允许创建任何类型的应用程序。可以用任何语言生成项目。
Yeoman 本身不会做什么。它的每一个决策都是由 Generator 来操作的。Generator 可以说是 Yeoman 中的插件。
创建 React 项目时,我们会使用 create-react-app ;创建 Vue 项目时,会使用 vue/cli ;创建 Angular 项目时,会使用 angular-cli 。这些脚手架子只能够创建对应的项目,Yeoman 通过使用不同的 Generator,可以创建同的项目。
通过 Yeoman ,可以搭建任何项目(我是不用,官网打不开的Generator找不到)。可以自定义一个 Generator ,然后就可以使用自己的脚手架搭建项目。
npm install -g yo
npm install -g generator-fountain-webapp
mkdir my-project && cd my-project
npm init -y
yo fountain-webapp
yo fountain-webapp 也可以直接命令行执行yo,然后会出来相应选项,选择你所需要的生成器。
搭建项目过程中会提示你去操作,和vue create创建项目类似。然后就会生成基础的项目模板了,以下是我生成的:
npm install
npm run serve
安装相应依赖后,就可以启动项目了。
启动时间有点久,具体原因可以不用管,这里就是让你知道 Yeoman 的使用。然后就可以在浏览器查看了。使用步骤是不是和使用其他脚手架一模一样。
有时需要一个特别的脚手架,那么就可以使用 Yeoman 来自定义一个。
这个操作需要在之前3.2设置开发环境的基础上操作。
mkdir generator-my-cli && cd generator-my-cli
npm init -y
npm install -g yeoman-generator
// 此文件作为 Generator 的核心入口
// 需要导出一个继承自 Yeoman Generator 的类型
// Yeoman Generator 在工作时会自动调用我们在此类型中定义的一些生命周期方法
// 我们在这些方法中可以通过调用父类提供的一些工具方法实现一些功能,例如文件写入
const Generator = require('yeoman-generator')
module.exports = class extends Generator{
writing(){
// Yeoman 自动生成文件阶段调用此方法
// 我们这里往执行yo 的文件夹写入一个temp.txt文件,文件内容是一个随机数。 这个fs不是node的fs
this.fs.write(
this.destinationPath('temp.txt'),
Math.random().toString()
)
}
}
上面的核心入口是往一个目录写入一个文件,如果是往目录写入一个模板,那么就是下面这样
const Generator = require('yeoman-generator')
module.exports = class extends Generator{
writing(){
// 通过模板方式写入文件到目标目录
// 模板文件路径
const tmp1 = this.templatePath('bar.html')
// 输出目标路径
const output = this.destinationPath('bar.html')
// 模板数据上下文
const context = this.answers
this.fs.copyTpl(tmp1, output, context)
}
}
在使用脚手架创建项目时,需要根据命令行提示,输如某些信息,如项目名,版本号等;这个在yeoman里也是靠这个核心入口文件来处理的
const Generator = require('yeoman-generator')
module.exports = class extends Generator{
prompting(){
// Yeoman 在询问用户环节会自动调用此方法
// 在此方法中可以调用父类的 prompt() 方法发出对用户的命令行询问,询问多次就在数组里添加一个对像
// 用户输入后,就会有一个{title: xx, key: xx}的对象,在templates里面使用EJS模板标记来获取这个
return this.prompt([
{
type: 'input',
name: 'title', // 接收值的建
message: 'Your project namezz',
default: this.appname // appname 为项目生成目录名称
},
{
type: 'input',
name: 'ke', // 接收值的建
message: 'Your project namezz',
default: this.appname // appname 为项目生成目录名称
}
])
.then(answers => {
// answers => {name: 'user input value'}
this.answers = answers
})
}
writing(){
...
}
}
上面对prompting函数就是用来接收用户输入的,在templates里面可以用EJS模板标记来获取
<%= title%>
<% if(success) {%>
条件判断
<% }%>
通过以下命令,将生成器(Generator)发布到全局范围,使之成为全局模块包。注意mac电脑权限不够的话,下面命令前面加上sudo
npm link
在电脑的任意地方执行以下命令,会根据编写的核心入口的操作,生成相应的文件。
yo
注意:yo 后面的生成器在当前命令里不需要前面的generator-
按照上面的操作,在你执行yo 的文件夹里现在应该会出现一个temp.txt文件,内容为一个随机数
现在来模拟一个生成器,使用这个生成器后会生成和 vue/cli 创建的项目一样。
使用yo 后生成的项目结构如下(图片加不进来)
my-demo
|-- public
|-- favicon.ico
|-- index.html
|-- src
|-- assets
|-- logo.png
|-- components
|-- HelloWorld.vue
|-- app.vue
|-- main.js
|-- babel.config.js
|-- package.json
|-- package-lock.json
|-- README.md
创建一个文件夹 generator-my-cli
初始化文件夹生成package.json
npm init -y
根目录下创建 generators/app/index.js (这个一定要是这么写),app里创建templates文件夹,在templates文件夹里面编写上面需要的模板(你想要什么样的模板就编写怎样的模板);我这里直接用vue/cli脚手架创建了一个,然后拷贝过来。
如果是脚手架拷贝过来的要注意一下public/index.html这个文件
如果你要使用生成器后生成的index.html保留这样子的代码,就要在第一个%哪里加一个%
const Generator = require("yeoman-generator");
module.exports = class extends Generator{ // 导出继承自Generator的一个类
prompting(){
return this.prompt([
{
type: 'input',
name: 'projectName',
message: 'your project-name is:',
default: '123'
},
{
type: 'input',
name: 'version',
message: 'your project version is:',
default: '123'
}
]).then(answer => {
this.answer = answer
})
}
writing(){ // Generator将文件写入本地的方法
const templates = [
'public/favicon.ico',
'public/index.html',
'src/assets/logo.png',
'src/components/HelloWorld.vue',
'src/App.vue',
'src/main.js',
'babel.config.js',
'package.json',
'package-lock.json',
'README.md'
]
templates.forEach(item => {
this.fs.copyTpl(
this.templatePath(item),
this.destinationPath(item),
this.answer
)
})
}
}
使用方法和其它生成器一样,在相应文件夹下执行 yo my-cli (这个生成器名字为my-cli,上面我们创建目录是generator-my-cli),成功后再当前文件夹下就会生成最开始那样的目录结构。
当然,上面的 Yeoman 自定义 Generator 生成器现在和 vue/cli还是差别好多,只生成了一个壳子,npm run serve这样的操作还是没有的。之后再给他加上(这个之后。。。)