脚手架工具
脚手架工具作用:创建项目基础结构、提供项目规范和约定等,像一些成熟的脚手架工具:vue-cli、create-react-app、anaular-cli等
Yeoman简介
Yeoman是一个通用的脚手架工具,可以快速构建web应用程序的工具和框架,Yeoman搭配 Generator 使用可以创建属于自己的脚手架,每一个Generator 都是基于 nodeJs 开发的 npm 模块,可以发布供其他人使用
Yeoman主要有三部分组成:yo(脚手架工具)、grunt/gulp(构建工具)、bower(包管理器)。这三个工具是分别独立开发的,但是需要配合使用,来实现我们高效的工作流模式
安装步骤
全局安装yo
yarn global add yo
yeoman搭配generator才能使用,安装对应的generator生成器
yarn global add generator-node
进入指定目录,运行generator,将generator-前缀去掉
yo node
即可-
生成的项目结构如下
Sub Generator
在已有项目结构上创建特定类型配置文件,如Eslint、babel的配置文件,手写可能会有错误,所以可以通过Sub Generator生成器自动生成
运行sub generator方式,使用generator-node中的子集的生成器,即cli生成器,它可以生成cli所需要的一些文件
yo node:cli
将当前项目链接到全局范围,就可以当作全局命令行模式使用
yarn link
,全局依赖在以下目录,yarn link
和yarn unlink
用于链接和取消链接
安装项目依赖
yarn
安装完成可以全局使用
my-module --help
Yeoman使用步骤
- 明确需求,需要做什么类型项目
- 根据需求找到合适的Generator
- 全局范围安装找到的Generator
- 通过Yo运行对应的Generator
- 通过命令行交互填写选项
- 生成你所需要的项目结构
自定义Generator
基于Yeoman搭建自己的脚手架,创建自己的Generator生成项目
-
创建Generator模块
Generator本质是一个Npm模块,下面为Generator基础目录
-
步骤
创建文件夹generator-sample
创建package.json文件
yarn init --yes
安装yeoman-generator模块,此模块提供一些工具函数,创建生成器时更加便捷
yarn add yeoman-generator
-
进入项目目录,创建generator/app/index.js文件 Generator的核心入口文件
// 此文件作为Generator的核心入口 // 需要导出继承自Yeoman Generator的类型 // Yeoman Generator在工作时会自动调用我们在此类型中定义的一些生命周期方法 // 我们在这些方法中可以通过调用父类提供的一些工具方法实现一些功能,例如文件写入等 const Generator = require('yeoman-generator') module.exports = class extends Generator { writing() { // Yeoman自动在生成文件阶段调用此方法 // 尝试在项目目录中写入文件 this.fs.write( this.destinationPath('temp.txt'), Math.random().toString() ) } }
将当前模块链接到全局范围,使之成为全局功能包
yarn link
使用yo运行此模块
yo sample
,就会在当前文件夹创建temp.txt文件
-
根据模板创建文件
app目录下创建templates文件夹放模板文件
-
修改通过模板方式导入文件
// 此文件作为Generator的核心入口 // 需要导出继承自Yeoman Generator的类型 // Yeoman Generator在工作时会自动调用我们在此类型中定义的一些生命周期方法 // 我们在这些方法中可以通过调用父类提供的一些工具方法实现一些功能,例如文件写入等 const Generator = require('yeoman-generator') module.exports = class extends Generator { writing() { // 通过模板方式写入文件到目标目录 const temp = this.templatePath('foo.txt') const output = this.destinationPath('foo.txt') // 模板上下文 const context = { title: '123', success: true } this.fs.copyTpl(temp, output, context) } }
使用yo sample运行,就会在当前目录创建一个foo.text的文件,并根据context中的值生成文件内容
相对于手动创建文件,模板的方式大大提高了效率
-
接收用户输入
就像Vue或React这样的脚手架,在创建项目时会根据用户输入生成特定内容,在这里可以模拟一下
-
首先需要在app/templates文件夹中创建模板文件,此处创建为bar.html文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title><%= name %></title> </head> <body> <h1><%= name %></h1> </body> </html>
-
接着修改以上Generator入口文件,添加prompt接收用户输入
// Yeoman在询问用户环节调用此方法 // 在此方法中可以调用父类的prompt() 方法发出对用户的命令行询问 // 返回为Promise return this.prompt([ // 每个对象包括一个问题 type:输入方式 name用户输入的值保存的键 message提示用户 { type: 'input', name: 'name', message: 'Your project name', default: this.appname, // appname 父类当中自动拿到的目录文件夹名字 为项目生成目录名称 }, ]).then((answer) => { // answer => { name: 'user input value' } 用户输入 this.answer = answer // writing传入此answer }) // 在writing中 const temp = this.templatePath('bar.html') const output = this.destinationPath('bar.html') // 模板上下文 用户输入的键值 const context = this.answer //{ title: 'Hello', success: false } this.fs.copyTpl(temp, output, context)
-
-
模拟 vue-cli 创建 vue-generator
-
实现思路
- 实现与用户交互,提供是否创建特定文件目录,更具用户输入生成内容
- 拷贝 Vue 模板文件到 app/tempaltes 下,通过拷贝的方式复制到新创建的项目中
-
初始化项目
创建 generator-wang-vue 项目,并初始化 package.json,安装 yeoman-generator
-
生成模板文件
将 vue-cli 生成的初始化项目所有文件导入到 templates 文件夹,并修改项目需动态生成的文件,如项目名称(index.html、README.md、pageage.json)
-
生成用户输入
return this.prompt([ { type: 'input', name: 'name', message: 'Your project name', defualt: this.appname, }, { type: 'list', name: 'projectRoute', message: 'whether to create the router', choices: [ { name: 'Yes', value: 'yes', checked: true, }, { name: 'No', value: 'no', }, ], }, { type: 'list', name: 'projectVuex', message: 'whether to create the vuex', choices: [ { name: 'Yes', value: 'yes', checked: true, }, { name: 'No', value: 'no', }, ], }, ]).then((answer) => { this.answer = answer })
-
模板拷贝
// 把每个文件通过模板转换到目标路径 // 遍历 writing() { const templates = [ '.browserslistrc', '.editorconfig', '.env.development', '.env.production', '.eslintrc.js', '.gitignore', 'babel.config.js', 'package.json', 'postcss.config.js', 'README.md', 'public/favicon.ico', 'public/index.html', 'src/App.vue', 'src/main.js', 'src/router.js', 'src/assets/logo.png', 'src/components/HelloWorld.vue', 'src/store/actions.js', 'src/store/getters.js', 'src/store/index.js', 'src/store/mutations.js', 'src/store/state.js', 'src/utils/request.js', 'src/views/About.vue', 'src/views/Home.vue', ] const { name, projectRoute, projectVuex } = this.answer for (let temp of templates) { // 是否创建router vuex同理 if (temp !== 'src/router.js') { this.fs.copyTpl( this.templatePath(temp), this.destinationPath(temp), { name } ) } else { if (projectRoute === 'yes') { this.fs.copyTpl( this.templatePath(temp), this.destinationPath(temp), { name } ) } else { continue } } } }
发布Generator
发布之前,首先将代码托管到github,当前项目源码
创建npm账号,并登陆
-
验证本地是否登陆,返回npm的用户名则说明正常,如果报错,则使用
npm adduser
添加npm who am i // wang1xiang
-
yarn publish或npm publish,发布之前需要将仓库设置为npm官方仓库
// 如果安装有nvm命令 nvm use npm // 没有 npm config set registry https://registry.npmjs.org/
-
发布成功
-