yeoman

176 阅读4分钟

工程化定义

前端工程化,遵循一定的标准和规范,通过工具提高效率、降低开发成本、被关注和探讨,是互联网时代不可或缺技术,前端占据整个互联网开发的半壁江山,从传统网站到h5到桌面应用再到小程序 无所不能全面覆盖。前端行业对开发人员的要求发生翻天覆的变换,前端工程化被提出,成为前端开发必备的手段。node.js,让js有新舞台,让前端行业进行一次工业革命,很多工具都是使用node.js 开发。工程化是一个庞大概念,不管如何发展,始终为了解决问题,切莫为了技术而技术。

工程化解决问题

  • 传统语言弊端,使用es6、es7新特性,提高编码效率、实际用会发现兼容有问题,使用less、sass、postcss 提高css的编程性 但是在运行环境中不被支持
  • 模块化组织代码,使用模块化、组件化、提高项目的可维护性
  • 大量重复机械操作,部署上线需要手动压缩代码,重复性工作,手动将项目上传到服务器,容易出现问题,机器取代人做重复性操作,不会犯错
  • 统一代码风格,保障仓库代码质量,多人协同开发,不能保证代码风格,代码质量
  • 依赖后端服务接口,整体依赖后端项目,开发具体功能需要等待接口服务完成才可以做编码,以上都是没有工程化所面临的典型问题

工程化特点

  • 相同的组织结构
  • 相同的开发范式
  • 相同的模块依赖
  • 相同的工具配置
  • 相同的基础代码

项目工程化表现方式

一切重复的工作都应该被自动化

  • 创建项目:创建固定项目结构,创建特定类型文件,脚手架搭建基础结构
  • 编码:格式化代码,校验代码风格,编译/构建/打包,提交之前做代码风格验证,保证项目质量,对gitlog做严格模式限制,开发阶段使用新特性,将编写的代码和运行的代码进行转换
  • 预览测试:web-server、mock,传统的预览环节使用apache、nginx运行项目,没有热更新,工程化实现编码完成之后在浏览器直接看到结构,无需刷新
  • 提交:Git-Hooks、Lint-staged、持续集成
  • 部署:CI/CD 、 自动发布,代替上传到ftp

脚手架工具

  • vue=>vue-vli
  • react=>create-react-app
  • angular=>angular-cli

yeoman简介

脚手架运行平台,有自己的仓库,已经实现了很多脚手架yeoman官网generators库,yeoman搭配不同generator创建任何类型项目,可以通过创建自己的generator,从而创建我们自己的脚手架。每一个generator都是一个单独的npm

yeoman基础用法

  • 在全局范围安装yo
$ npm install yo -g
  • 安装对应generator
$ npm install fenerator-node -g
  • 通过yeom 运行generator
$ cd path/to/project-dir
$ mkdir my-module
$ yo node

简单使用

sub-generator

项目目录,运行特定的subgenerator

使用步骤

  1. 明确需求
  2. 找到合适的Generator
  3. 全局范围安装找到Generator
  4. 通过Yo 运行对应的generator
  5. 通过命令行交互填写选项
  6. 生成需要的项目结构

自定义generator

不同的generator可以用来生成不同的项目,创建自己的generator,生成自定义的项目结构,市面上的generator是通用的,但是在我们开发过程中,需要生成一部分基础代码和一部分业务代码,,把公共部分放在脚手架生成,例如项目中用到的sso。generator本质上是一个npm模块。

名称规范

采用generator-<name>规范

generator基本结构

$ mkdir test-customize-generator
$ cd test-customize-generator
$ npm init

|-- part2-前端工程化      
    |-- package.json      模块包配置文件
    |-- generators        生成器目录
        |-- app           默认生成器目录
        |   |-- index.js  默认生成器实现
        |-- component     其他生成器目录
            |-- index.js  其他生成器实现

基础用法

  • 安装Generator生成器
# 创建目录
$ mkdir generator-gxrtestdemo
# 进入目录
$ cd generator-gxrtestdemo
# init项目
$ npm init
# 安装基类生成器
$ npm install yeoman-generator -d
  • 创建生成器实现目录
$ mkdir generators
$ cd generators
$ mkdir app
$ cd app
$ touch index.js
  • 编写generators/app/index.js核心文件

此文件是generator的核心入口文件,需要导出一个继承自 Yeoman Genarator的类型,Yeoman Generator 在工作时会自动调用我们此类型中定义的一些生命周期,我们在这些方法中通过调用父类提供的一些工具方法实现一些功能,例如文件写入

const Generator = require("yeoman-generator");
module.exports = class extends (
  Generator
) {
  writing() {
    // yeoman自动在生成文件阶段调用这个方法
    // 我们这里尝试往项目目录中写入文件
    this.fs.write(this.destinationPath("test.txt"),
    Math.random().toString());
  }
};
  • 在当前目录中运行npm link,会自动创建一个package-lock.json文件
{
  "name": "generator-gxrtestdemo",
  "version": "1.0.0",
  "lockfileVersion": 1
}
  • 当前项目运行 yoe run gxrtestdemo
create test.txt
  • 项目目录下生成
|-- part2-前端工程化
    |-- package-lock.json
    |-- package.json
    |-- test.txt
    |-- generators
        |-- app
            |-- index.js
0.1643974097348393

用法:模板文件

  • 创建模板文件
$ cd generators
$ cd app
$ mkdir templates
$ cd templates
$ touch template.txt

内部可以使用EJS语法

我是测试模板文件<%= title %>
  • 编写generators/app/index.js核心文件
const Generator = require("yeoman-generator");
module.exports = class extends (
  Generator
) {
  writing() {
    // 通过模板方式写入文件到目标目录
    // 模板文件目录
    const tmpl = this.templatePath("template.txt");
    // 输出目标路径
    const output = this.destinationPath("test-template.txt");
    // 模板数据上下文
    const context = {
      title: "我是标题",
      // success: false,
    };
    this.fs.copyTpl(tmpl, output, context);
  }
};
  • 当前项目运行 yoe run gxrtestdemo
create test-template.txt
我是测试模板文件我是标题

用法:接受用户输入

  • 创建模板文件
$ cd generators
$ cd app
$ mkdir templates
$ cd templates
$ touch input.txt
接受用户输入的name <%= name %>
  • 编写generators/app/index.js核心文件
const Generator = require("yeoman-generator");

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) => {
      // answers = {name:'user input value'}
      this.answers = answers;
    });
  }
  writing() {
    // 通过模板方式写入文件到目标目录
    // 模板文件目录
    const tmpl = this.templatePath("input.txt");
    // 输出目标路径
    const output = this.destinationPath("test-input.txt");
    // 模板数据上下文
    const context = this.answers;
    this.fs.copyTpl(tmpl, output, context);
  }
};
  • 当前项目运行 yoe run gxrtestdemo
? your project name (generator gxrtestdemo) gxrtestdemo1231231
create test-input.txt
接受用户输入的name:generator gxrtestdemo1231231

发布generator

  • 当前项目目录
// 忽略`node_modules`的提交
$ echo node_modules > .gitignore  
// 初始化仓库
$ git init
// 暂存代码
$  git add ./
// 提交代码到本地仓库
$ git commit -m '提交代码'
// 关联远程仓库
$ git remote add origin 远程github仓库
// 提交代码
$ git push origin master
// 查看当前镜像源
$ npm config get registry
https://registry.npm.taobao.org/
// 发布代码
$ npm publish
结果401 Unauthorized - PUT https://registry.npm.taobao.org/generator-gxrtestdemo - [unauthorized] Login first
说明:淘宝镜像源是可读镜像源,不可像上传入代码。必需使用官方经镜像源
// 切换镜像源
$ npm config set registry http://www.npmjs.org
// 查看当前镜像源
$ npm config get registry
http://www.npmjs.org/
// 发布代码 
$ npm publish
 + generator-gxrtestdemo@1.0.0
  • 说明:npm publish 发布到仓库必需有github用户,如果没有就去创建一个github注册
  • 淘宝镜像源是可读镜像源,发布代码需要替换设置npm镜像源是npm官网镜像源
  • 如果generator要在官方的仓库列表中出现,需要在项目名称中添加yeoman-的keywords,对应package.json中的配置项目。
  • 以上用法只是在生成器文件中使用了prompting事件方法,还有其他特殊的事件方法,按照优先级排序:
    • initializing - 初始化开始
    • prompting - 调用this.prompt()与用户产生交互
    • configuring - 创建配置文件(package.json,config.js等)
    • default - 方法都不匹配这些优先级时,就会是default优先级(自定义方法会被划入default)
    • writing - 创建项目文件
    • conflicts - 文件创建中产生冲突的处理
    • install - 调用(npm, bower)包install
    • end - 结束项目初始化 其他自定义方法在configuring和writing按顺序优先级调用