前端工程化-yeoman、plop
为什么要工程化?
- 部署上线机械执行,比如代码和资源文件的压缩、部署过程需要手动上传代码到服务器
- 如果使用新的特性,但是兼容可能会有问题。比如使用less/sass/postcss之类去增强css编程性,但是运行环境不能直接支持
- 可以统一代码风格,质量保证。比如:eslint、ts
- 整体依赖后端项目,比如要等待后端接口支持后才能进行调试
工程化流程
创建项目->编码->预览/测试->提交->部署
创建项目阶段可以用脚手架搭建;
编码环节:格式化代码、校验代码风格、编译/构建/打包
预览环节:web server/mock;hmr;source map
提交环节:git hooks;lint-staged;持续集成
部署:CI/CD;自动发布
脚手架工具
脚手架用于自动的创建项目基本结构、提供项目规范和约定。比如要有相同的组织结构、相同的开发范式、相同的模块依赖、相同的工具配置、相同的基础代码。(create-react-app/vue-cli…)
Yeoman
使用yeoman搭建不同的generator创建任意类型的项目,过于通用,不够定制化。
使用
全局安装yeoman和对应的generator,通过yo运行generator
yarn global add generator-node
cd path
yo node
sub generator
如果不需要创建完整的项目结构,只需要在原有的项目基础上创建特定的配置文件等,如eslint、webpack等。
使其变成cli应用
yo node:cli
将模块注册到全局范围,使其在全局都能被使用
yarn link
运行命令行测试
[模块名] --help
yeoman常规使用步骤
- 明确需求
- 找到合适的generator
- 全局范围内安装找到的generator
- 通过yo运行对应的generator
- 通过命令行交互填写选项
- 生成所需的项目结构
自定义generator
解决:官方提供的脚手架不够定制化。
注意:yeoman的generator名称必须为:generator-<name>
这种格式。
文件目录:
generators
--app
----index.js // generator的核心入口
--package.json
步骤:
yarn init
yarn add yeoman-generator 提供了一些基类,是我们在创建生成器的时候更加便捷
编写入口文件:
const Generator=require('yeoman-generator') module.exports=class extends Generator { writing(){ // yeoman 自动在生成文件阶段调用此方法 // 我们这里尝试往项目目录中写入文件 // 参数:文件路径,文件内容 this.fs.write(this.destinationPath('temp.txt'),Math.random().toString()) // 扩展了node的fs } }
当我们在外部使用这个脚手架时,就会看到temp.txt中的内容
yo sample
对应文件夹中就会有temp.txt
根据模板创建文件
在生成器的app目录下添加目录:templates,内部可以用ejs模板标记输出的数据,如:
<%- title %> 其他的ejs语法也支持 <% if (success) { %> 哈哈哈 <% }%>
我们更改启动文件index.js:
module.exports=class extends Generator { writing(){ // 通过模板方式写入文件到目标目录 // 模板文件路径 const tml=this.templatePath('foo.txt') // 输出的目标路径 const output=this.destinationPath('foo.txt') // 模板数据上下文 const context={title:'hello world',success:true} this.fs.copyTpl(tml,output,context) } }
用模板的方式要比用fs的方式手写更快
接受用户输入数据
我们常会看到很多脚手架会通过用户交互的方式来定制功能,比如:用户输入一些参数来展示渲染文件。
prompting这个成员函数就是用来生成交互实例的module.exports=class extends Generator { prompting(){ // yeoman在询问用户环节会自动调用此方法 // 在此方法中可以调用父类的prompt()方法发出对用户的命令行询问 return this.prompt([{ type:'input', // 用户交互形式 name:'name', // 字段名称 message:'Your Project Name', // 显示语句 default:this.appname // appname为当前项目生成目录名称 }]).then(answers=>{ // 用户交互结果 // answer以对象形式出现 :{name: ‘zhangsan’ } this.answers=answers }) } writing(){ // 模板文件路径 const tml=this.templatePath('foo.txt') // 输出的目标路径 const output=this.destinationPath('foo.txt') // 模板数据上下文 const context=this.answers this.fs.copyTpl(tml,output,context) }}
发布Generator
和npm public一样
Plop – 一个小而美的脚手架工具
创建项目中特定类型的小工具,类似于yeoman中的sub generator,不会独立使用,plop可集成到项目中,自动化的创建同类型的项目文件。
比如我们在项目中经常会创建相同类型的文件,比如每个组件都有相同结构的三个文件:js、css、test.js.
使用
先要建立plop的入口文件,他需要导出一个函数:
// plopfile.js
module.exports=plop=>{
// 第一个参数为生成器的名字
// 第二个参数为生成器的选项
plop.setGenerator('component',{
description:'create a component',
prompts:[ // 命令行交互
{type:'input',
name:'name',
message:'component name',
default:'MyComponent'
}
],
actions:[
{
type:'add',// 代表添加文件
path:'src/components/{{name}}/{{name}}.js', // name为命令行交互中的name
templateFile:'plop-templates/component.hbs'
}
]
})
}
plop-templates为指定模板目录,component.hbs为模板文件:
// component.hbs
import React from 'react'
export default ()=>(
<div className="{{name}}">
<h1>{{name}} Component</h1>
</div>
)
如上,可以用的方式把交互行中的数据写入到模板中。再终端中运行
yarn plop component
就可以按照命令行的提示生成指定文件啦,是不是特别方便。
脚手架的工作原理
node中安装 inquirer 模块,根据prompts指令渲染模板。