脚手架是什么
创建项目基础结构,提供项目规范和约定。
在众多的项目中,我们发现他们总是有着
- 相同的组织结构
- 相同的开发范式
- 相同的模块依赖
- 相同的工具配置
- 相同的基础代码
脚手架就是用来解决这一些重复问题的。
常用的脚手架工具
我们常见的脚手架工具大都是为了特定项目类型服务的,比如vue-cli,create-react-app,只能创建对应的特定项目类型。还有通用的脚手架工具Yeoman,较为灵活易扩展。(CLI一般指命令行界面)
Yeoman
Yeoman是一款创建现代化web引用的脚手架工具。老牌,通用,强大,相比vue-cli的特定,他有更多值得我们学习的地方。它可以通过我们自定义的generator,创建自己想要的项目。
Yeoman的使用
全局范围安装yo
cnpm install -g yo
安装对应的generator (这里以想创建node项目的脚手架为例)
cnpm install generator-node -g
通过yo运行generator
mkdir my-module
yo node
最后通过命令行交互填写项目结构,一些描述,作者什么的
Sub Generator
有时候我们只是在原有的项目上添加些配置文件,例如eslint配置文件,bable配置文件等,这些文件都有些基础代码,如果自己手动配的话也容易出错,这就需要生成器自动帮我们生成,这种需求就适合通过Sub Generator来实现。
cd my-module
yo node:readme
并不是说有generator都有sub generator, 比如generator-vue就没有
总结常规使用yeoman的步骤
- 明确你的需求
- 找到合适的generator(通过yeoman官网找)
- 全局范围安装你找到的generator
- 通过Yo运行此generator
- 通过命令行交互填写项目结构
- 生成你所需要的项目结构
自定义generator,搭建自己的脚手架
比如vue官方的vue-cli,创建完成后只包含vue结构,如果我们还想集成vue-router,vuex,那我们就可以自行搭建自己的脚手架。
创建generator模块
generator本质上就是一个npm模块
如果想添加Sub Generator,目录就如下
还有Generator的模块名称必须是generator-<name>
mkdir generator-sample && cd generator-sample
创建一个package.json
npm init
这个模块会为我们提供一个generator生成器的基类,基类中提供了一些工具函数,可以让我们写生成器的时候更加便捷
npm install yeoman-generator
按照上述图的目录标准,创建generators/app/index.js文件
// index.js
// 此文件作为 Generator 的核心入口
// 需要导出一个继承自 Yeoman Generator 的类型
// Yeoman Generator 在工作时会自动调用我们在此类型中定义的一些生命周期方法
// 我们在这些方法中可以通过调用父类提供的一些工具方法实现一些功能,例如文件写入
const Generator = require('yeoman-generator')
module.exports = class extends Generator {
writing () {
// Yeoman 自动在生成文件阶段调用此方法
// 我们这里尝试往项目目录中写入文件
this.fs.write( // 这个fs不是node模块的fs,这个更强大
this.destinationPath('temp.txt'), // 绝对路径
Math.random().toString() //填入随机数
)
}
}
这样一个简单的generator就完成了。
通过命令行把这个模块链接到全局范围,使之成为一个全局模块包
npm link
mkdir my-sample && cd my-sample
yo sample
=>生成文件啦
根据模版创建文件
大部分时候我们要创建的文件较多也较复杂,所以我们使用模版,可以更便捷一些
创建template/foo.txt
// foo.txt
这是一个模板文件
内部可以使用 EJS 模板标记输出数据
例如:<%= title %>
其他的 EJS 语法也支持
<% if (success) { %>
哈哈哈
<% }%>
writing () {
// 通过模板方式写入文件到目标目录
// 模板文件路径
const tmpl = this.templatePath('foo.txt')
// 输出目标路径
const output = this.destinationPath('foo.txt')
// 模板数据上下文
const context = { title: 'Hello zce~', success: true }
this.fs.copyTpl(tmpl, output, context)
}
html也同理
接收用户输入
通过prompting方法,接收命令行交互中用户输入的数据
prompting () {
// Yeoman 在询问用户环节会自动调用此方法
// 在此方法中可以调用父类的 prompt() 方法发出对用户的命令行询问
return this.prompt([
{
type: 'input',
name: 'name',
message: 'Your project name',
default: this.appname // appname 为项目生成目录名称
}
])
.then(answers => {
// answers => { name: 'user input value' }
this.answers = answers
})
}
// 在想使用的地方 this.answer.name
Vue-generator案例
开发一个vue-cli
https://gitee.com/ericzhouhang/generator-vue-demo
generator发布
generator本质上就是一个npm模块,所以就是发布一个npm模块
npm publish
Plop
一个小型前端脚手架工具,一般用来创建项目中的同类型文件
脚手架工作原理
启动它过后,它会自动的去询问你一些预设的问题,然后将你回答的结果,结合模版文件,生成项目的内容。 核心代码:
#!/usr/bin/env node
// Node CLI 应用入口文件必须要有这样的文件头
//意思是指定用node执行脚本文件。
// 脚手架的工作过程:
// 1. 通过命令行交互询问用户问题
// 2. 根据用户回答的结果生成文件
const fs = require('fs')
const path = require('path')
const inquirer = require('inquirer') // 命令行交互模块
const ejs = require('ejs')
inquirer.prompt([
{
type: 'input',
name: 'name',
message: 'Project name?'
}
])
.then(anwsers => {
// console.log(anwsers)
// 根据用户回答的结果生成文件
// 模板目录
const tmplDir = path.join(__dirname, 'templates') // __dirname:当前模块的目录名
// 目标目录
const destDir = process.cwd() // Node.js 进程的当前工作目录。
// 将模板下的文件全部转换到目标目录
fs.readdir(tmplDir, (err, files) => {
if (err) throw err
files.forEach(file => {
// 通过模板引擎渲染文件
ejs.renderFile(path.join(tmplDir, file), anwsers, (err, result) => {
if (err) throw err
// 将结果写入目标文件路径
fs.writeFileSync(path.join(destDir, file), result)
})
})
})
})