脚手架工具
一、脚手架工具的本质作用
创建项目基础结构,提供项目规范和约定
二、一些常用的前端脚手架工具
React项目 ==> create-react-app
Vue.js项目 ==> vue-cli
angular项目 ==> angular-cli
这些脚手架工具都大同小异,都是根据信息创建对应的项目基础结构
不过以上这些一般只适用于自身所服务的框架的项目
还有一类就是以Yeoman为代表的通用型脚手架工具,它们可以根据一套模板,生成一套对应的项目结构,这种类型的脚手架工具一般都很灵活,也很容易扩展
还有一类在项目开发过程中使用的脚手架工具,代表是Plop,用于创建一些特定类型的文件,例如创建一个组件/模块所需要的文件
三、Yeoman
3.1、Yeoman基本使用
全局安装Yeoman
npm i -g yo
Yeoman是搭配generator使用的,所以我们需要安装对应的generator
npm i -g generator-node
新建一个文件件,在该目录下运行命令行
yo node
会提示一些问题需要回答,回答完问题就会创建出一套项目结构。
3.2、sub generator
有时候我们并不需要去创建完整的项目结构,而是在现有项目基础上去创建一些特定类型的文件。例如在项目上添加eslint或者babel的配置文件,这些配置文件都有一些基础代码,我们手动配置可能会配错。我们就可以通过生成器去帮我们生成,以此来提高我们的效率。
有上述需求的话我们就能通过yeoman所提供的sub generator特性来实现。
// 假设我们要将一个项目变成一个cli项目
yo node:cli // 利用generator-node中提供的自己生成器cli去生成一个cli项目需要的文件
// 执行后会提示是否重写package.json,输入y,回车
// 提示重写了package.json文件,并新建了一个lib/cli文件
// 有了这些我们就可以将我们的模块作为一个全局的命令行模块去使用
npm link // 将本地模块放到全局
npm i // 根据重写的package.json将依赖重新安装
study-one --help // study-one就是我的项目名
3.3、Yeoman使用步骤总结
1、明确需求
2、找到合适的generator(在Yeoman官网中查找)
3、全局范围安装找到的generator
4、通过yo运行对应的generator
5、通过命令行交互填写选项
6、生成所需要的项目结构
四、创建generator模块
4.1、注意事项
generator本质上就是一个npm模块,需要注意的是,generator有特定的结构
如果需要添加多个sub generator,则需要在app的统计同级目录下添加一个component目录
Yeoman的generator模块名称必须是generator-name格式,如果没使用这种名称,后续Yeoman在工作的时候就没有办法找到我们所提供的generator模块。
4.2、开始创建
新建一个generator-sample文件夹作为模块目录
在该目录下运行 npm init -y 创建package.json文件
执行 npm i yeoman-generator 这个模块提供了生成器的基类,这些基类当中提供了一些工具函数,这些工具函数可以让我们在创建生成器的时候更加便捷,模块目录结构如下:
// index.js
// 此文件作为Generator的核心入口
// 需要导出一个继承自Yeoman Generator的类型
// Yeoman在工作时会自动调用我们在此类型中定义的一些生命周期方法
// 我们在这些方法中可以通过调用父类提供的一些工具方法实现一些功能,例如文件写入
const Generator = require('yeoman-generator')
module.exports = class extends Generator{
writing(){
// Yeoman 自动生成文件阶段调用此方法
// 我们这里尝试往项目目录中写入文件
// 注意:这里的fs与node当中的fs模块是不一样的,这是一个高度封装的fs模块,相较于原生的会更加强大一些
// 有两个参数,一个是写入文件的绝对路径,一个是写入内容
this.fs.write(
this.destinationPath('temp.txt'), // 设置输出文件路径
Math.random().toString()
)
}
}
执行 npm link 将模块链接到全局范围,使之成为一个全局模块包
执行 yo sample,当前目录中就多了一个temp.txt文件
以上就是一个最基本的generator模块开发过程。
五、根据模板创建文件
在app文件下新建templates/test.txt
// test.txt内容
这是一个模板文件
内部可以使用EJS模板标记输出数据
例如:<%= title %>
其他的EJS语法也支持
<% if(success){ %>
哈哈哈
<% } %>
根据模板文件写入
// index.js
const Generator = require('yeoman-generator')
module.exports = class extends Generator{
writing(){
// 通过模板方式写入文件到目录
// 借助于fs中专门使用模板引擎的方法--copyTpl
// 模板文件路径
const tmpl = this.templatePath('test.txt')
// 输出目标路径
const output = this.destinationPath('test.txt')
// 模板文件上下文
const context = {title: "hello hu", success: true}
this.fs.copyTpl(tmpl, output, context)
}
}
六、接收用户输入内容
首先我们在tamplates目录下新建一个html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 需要用户输入的就是这两个 -->
<%= projectname %>
<%= username %>
</body>
</html>
然后在index.js中实现获取用户输入并写入文件的操作
const Generator = require('yeoman-generator')
module.exports = class extends Generator{
prompting(){
// Yeoman在询问用户阶段会自动调用此方法
// 在此方法中可以调用父类的 prompt() 方法发出对用户的命令行询问
// prompt()返回的是一个Promise对象
return this.prompt([
{
type:'input',
name:"projectname",
message:"input project name",
default: this.appname // appname为项目生成目录名称
},
{
type:'input',
name:"username",
message:"input user name",
default: 18
}
])
.then(answers => { // 因为返回的是一个 Promise对象,所以可以使用then方法
// answers => {name: value} answers是以对象的形式出现,键就是我们上面设置的name,值就是用户输入的内容
this.answers = answers
})
}
writing(){
const tmpl = this.templatePath('input.html')
const output = this.destinationPath('input.html')
const context = this.answers
this.fs.copyTpl(tmpl, output, context)
}
}
最终效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
hhh
19
</body>
</html>
七、实现一个Vue Generator模块
新建一个generator-vuesample文件夹,到时候我们要通过yo运行的generator就是vuesample。
npm init -y
npm i yeoman-generator
将vue项目所需要的文件复制一份到app/templates下
根据需要修改点内容
public/index.html
这里需要注意:link标签内的 BASE_URL 必须原封不动的返回,想要实现也很简单,就是将<%= %>改成<%%= %>,下面的strong标签内的也是一样
README.md
package-lock.json
package.json
接下来开始写generator的核心文件
const Generator = require('yeoman-generator')
module.exports = class extends Generator{
prompting () {
return this.prompt([
{
type:'input',
name: 'projectname',
message:"please input projectname",
default:this.appname
}
])
.then(answers => {
this.answers = answers
})
}
writing () {
// 把每一个文件都通过模板转换到目标路径
const templates = [
'public/favicon.ico',
'public/index.html',
'src/assets/logo.png',
'src/components/Add.vue',
'src/components/Back.vue',
'src/router/index.js',
'src/store/store.js',
'src/App.vue',
'src/main.js',
'babel.config.js',
'package-lock.json',
'package.json',
'README.md',
'vue.config.js'
]
templates.forEach(item => {
this.fs.copyTpl(
this.templatePath(item),
this.destinationPath(item),
this.answers
)
})
}
}
npm link // 将generator模块链接到全局范围
// 然后新建一个文件夹
yo vuesample // 通过yo运行generator,生成想要的目录结构