前端工程化2——常见脚手架工具介绍使用和工作原理分析(YeomanPlop)手写脚手架工具

Posted JIZQAQ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端工程化2——常见脚手架工具介绍使用和工作原理分析(YeomanPlop)手写脚手架工具相关的知识,希望对你有一定的参考价值。

目录

一、概念

二、常用脚手架工具

三、Yeoman

1.介绍

2.安装

3.基础使用

4.Sub Generator

5.使用步骤总结 

6.自定义Generator

概念

实现过程

7.根据模板创建文件 

8.接受用户输入数据

9.发布Generator

 四、Plop

1.安装和使用

总结

五、脚手架的工作原理(手写一个脚手架工具)


一、概念

脚手架可以理解为,就是自动的去帮我们创建羡慕的基础结构、提供项目规范和约定的工具。

通常我们在开发项目的时候,都会有一些相同的约定,比如:

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

而脚手架工具就是解决这些问题的,我们可以通过脚手架工具快速搭建相同类型的项目骨架,然后基于骨架进行后续开发工作

二、常用脚手架工具

React项目:create-react-app

Vue.js项目:vue-cli

Angular项目:angular-cli

这些脚手架工具的实现方式都大同小异,无外乎是根据信息创建对应的项目基础结构(特定文件和相关配置)。

还有一类是以Yeoman这样的工具为代表的,通用型项目脚手架工具,这类型的一般都很灵活很容易扩展。

除了以上在创建项目时使用的脚手架工具,还有一类脚手架也非常有用,代表的叫Plop。它们用来在项目开发过程当中用于去创建一些特定类型的文件,例如一个在一个组件化的项目当中去创建一个新的组件,或者是一个模块化的项目当中去新建一个模块。这些模块或者组件一般是由几个特定的文件组成的而且每个文件都有一些基本的代码结构,比起我们手动一个个去创建,脚手架会提供更便捷稳定的方式。

三、Yeoman

1.介绍

Yeoman官方定义,它是一款用于创造现代化Web应用的脚手架工具。不同于vue-cli那种工具,Yeoman更像是一个脚手架的运行平台,通过Yeoman搭配不同的generator去创建任何类型的项目,也就是说我们可以通过自己去定制generator来定制自己的前端脚手架。

2.安装

在安装Yeoman之前首先得安装node和npm,先来检查一下node环境是否正常。

如果没有安装node环境的,Mac用户可以看我下面这篇博文进行安装,Windows的就自行百度一下了。

如何直接运行Js文件?Mac Node.js安装使用教程

https://blog.csdn.net/qq_43106115/article/details/116429183

 安装Yeoman

npm install yo -g

安装Generator

npm install generator-node -g

3.基础使用

创建一个放项目的新的文件夹,进入到文件夹中去。输入

yo node

然后根据提示完成一系列问题。 (quq这里写名字的时候我拼错了…写成yeomon了)

运行完之后就安装成功拉。

4.Sub Generator

如果我们只是想在已有的项目基础之上创建一些特定类型的文件,比如创建readme、添加某些类型配置文件,我们就可以使用Yeoman提供的Sub Generator来实现。

假如我们需要添加cli,输入

yo node:cli

这样就好啦,可以看到我们package.json文件出现了cli相关的内容

我们可以通过npm link把它link到全局范围,这之后我们可以在命令行用这个名字来运行我们的模块了

npm link
npm install // 安装依赖
yeomon --help // 前面是module名称,在新建的时候输入的什么就是什么,因为我前面拼错了所以这里就是这个拼错了的玩意

不过不是每个Generator都提供Sub Generator,用之前需要查看官方文档。比如我们使用的generator-node就只提供下面这些Sub Generator

5.使用步骤总结 

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

比如我们创建一个网页应用,先到Yeoman的官网

Yeoman

https://yeoman.io/

找到对应的Generator

这里使用webapp Generator,使用npm进行安装

npm install generator-webapp -g

后面安装使用过程和上面的一样啦,就不再重复了。

6.自定义Generator

概念

创建Generator实际上就是创建一个npm模块。

Generator有特定结构:

如果需要提供多个Sub Generator,可以在app同级目录添加新的生成器目录,比如下面我们就添加了一个新的component Sub Generator

还有一个和普通npm不同的是,Yeoman的Generator名称必须是generator-<name>的格式,如果不使用这个名称,后续Yeoman工作的时候就无法找到这个生成器模块。

实现过程

新建一个文件夹

mkdir generator-sample
cd generator-sample

用npm init -y的方式新建一个package.json

npm init -y

安装一个yeoman-generator的模块,它提供了生成器的基类,里面的工具函数让我们创建生成器的时候更加便捷。

npm install yeoman-generator 

在VSCode中打开这个文件,可以看到现在是这么一个项目结构

 

根据前面的项目结构要求,创建文件

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

index,js中的内容

const Generator = require('yeoman-generator')

module.exports = class extends Generator {
    writing() {
        // Yeoman 自动在生成文件阶段调用此方法
        // 我们这里尝试往项目目录中写入文件
        this.fs.write(
            this.destinationPath('temp.txt'),// destinationPath自动获取生成文件的绝对路径
            Math.random().toString() // 文件内容
        )
    }
}

保存后,回到命令行,安装相关依赖,通过npm link把这个模块连接到全局范围,使之成为全局模块包。

npm install
npm link

回到上一级目录,新建一个文件夹,使用yo sample运行我们的模块包。

cd ..
mkdir my-proj
cd my-proj
yo sample

可以看到创建了一个temp.txt文件,内容也是我们需要的随机内容,这就完成啦。

7.根据模板创建文件 

相对于手动创建每一个文件,模板的方式大大提高了效率

根据下面结构新增foo.txt文件

foo.txt的内容如下

这个foo.txt是一个模板文件,内部可以使用EJS模板标记输出数据
例如<%= title %>。其他EJS语法也支持
<% if(success) { %>
哈哈哈
<% } %>

回到index.js文件,不再需要用上面fs.write方法来生成文件了

const Generator = require('yeoman-generator')

module.exports = class extends Generator {
    writing() {
        // Yeoman 自动在生成文件阶段调用此方法
        // 我们这里尝试往项目目录中写入文件
        // this.fs.write(
        //     this.destinationPath('temp.txt'),// destinationPath自动获取生成文件的绝对路径
        //     Math.random().toString() // 文件内容
        // )

        // 通过模板方式写入文件到目标目录

        // 模板文件路径
        const tmpl = this.templatePath('foo.txt')
        // 输出目标路径
        const output = this.destinationPath('foo.txt')
        // 模板数据上下文
        const context = { title: 'Hello!', success: false}

        this.fs.copyTpl(tmpl,output,context)
    }
}

然后和前面的步骤一样依次去运行

npm install
npm link
cd ..
mkdir my-proj
cd my-proj
yo sample

可以看到my-proj文件夹里面生成了如下的foo.txt文件 

8.接受用户输入数据

对于模板中的动态数据,例如标题、项目名称,一般通过命令行交互的方式得到。在Generator当中,想要发起一个命令行的询问,可以通过Generator里面的prompting方法实现。

index.js

const Generator = require('yeoman-generator')

module.exports = class extends Generator {
    prompting() {
        return this.prompt([{
            type:'input',// 使用什么方式去接收用户输入
            name:'name',// 最终生成的键
            message: 'Your project name',// 界面上给用户的提示
            default: this.appname// appname 为项目生成目录名称
        }]).then(answers => {
            this.answers = answers
        })
    }
    writing() {
        // Yeoman 自动在生成文件阶段调用此方法
        // 我们这里尝试往项目目录中写入文件
        // this.fs.write(
        //     this.destinationPath('temp.txt'),// destinationPath自动获取生成文件的绝对路径
        //     Math.random().toString() // 文件内容
        // )

        // 通过模板方式写入文件到目标目录

        // 模板文件路径
        const tmpl = this.templatePath('bar.html')
        // 输出目标路径
        const output = this.destinationPath('bar.html')
        // 模板数据上下文
        const context = this.answers

        this.fs.copyTpl(tmpl,output,context)
    }
}

按照下面创建一个bar.html文件夹 

放入下面内容

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title><%= name %></title>
</head>
<body>
  <h1><%= name %></h1>
</body>
</html>

还是之前那样运行,到yo sample的时候会提示需要我们输入project name

生成的bar.html 

9.发布Generator

将项目传到我们github仓库上,然后使用npm publish,成功后会有显示成功npm发布地址,打开看就能看到我们发布的generator了,也能使用npm install。如果希望我们的generator在Yeoman官方的仓库里面也能看得到,那我们可以为我们的项目添加一个yeoman-generator的关键词,这样Yeoman官方就会发现到我们的项目。

 四、Plop

如果我们在开发过程当中需要经常重复创建相同类型的文件,这么就可以使用Plop。

比如这个项目中,每个components我们创建的时候都需要创建三个文件,那我们就可以使用Plop代劳。

1.安装和使用

例子是先创建了一个基础的React项目,然后使用npm install plop安装plop

npm install plop -g

 在项目的根目录中创建一个叫plopfile.js的文件,这个文件是Plop的入口文件,需要导出一个函数。这个函数接受一个Plop对象,用于创建生成器任务

plopfile.js的文件内容如下

// Plop 入口文件,需要导出一个函数
// 此函数接收一个 plop 对象,用于创建生成器任务

module.exports = plop => {
  //setGenerator 需要接受两个参数,第一个是生成器的名字,第二个是生成器的一些配置选项
  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',// 添加的文件具体会被添加到哪个路径
        templateFile: 'plop-templates/component.hbs'// 本次添加的文件的模板文件是什么
      },
      {
        type: 'add', // 代表添加文件
        path: 'src/components/{{name}}/{{name}}.css',
        templateFile: 'plop-templates/component.css.hbs'
      },
      {
        type: 'add', // 代表添加文件
        path: 'src/components/{{name}}/{{name}}.test.js',
        templateFile: 'plop-templates/component.test.hbs'
      }
    ]
  })
}

模版文件地址:

在命令行中输入

plop component

成功运行,下图可以看到我们需要的文件顺利的创建出来了

总结

Plop的使用主要涉及到下面几个步骤

  1. 将plop模块作为项目开发依赖安装
  2. 在项目根目录下创建一个plopfile.js的文件
  3. 在plopfile.js文件中定义脚手架任务
  4. 编写用于生成特定类型文件的模板
  5. 通过Plop提供的cli运行脚手架任务

五、脚手架的工作原理(手写一个脚手架工具)

大部分脚手架的工作原理很简单,不外乎就是在启动它过后,它会自动去询问我们一些预设的问题,然后将回答的结果结合一些模板文件去生成结构。

下面使用node.js来一边写一个脚手架工具一边解释它的工作原理。

开始的时候新建一个项目根目录

mkdir sample-scaffolding
cd sample-scaffolding
npm init -y

在package.json文件中添加bin字段,用于指定cli应用的入口文件。

然后在项目根目录下创建一个cli.js文件

下面就是cli.js的文件内容,要注意的是Linux或者MacOS系统下需要通过运行chmod 755 cli.js讲该文件的读写权限改为755才能使用

#!/usr/bin/env node

// NodeCLI应用入口文件必须要有一个文件头
// 如果是Linux或者macOS还要把这个文件读写权限改为755,通过运行chmod 755 cli.js实现

console.log('cli working!')

然后运行

npm install
npm link
sample-scaffolding

在命令行中可以看到我们cli.js文件正常执行,那我们可以安心开始写逻辑了

脚手架的工作过程主要是下面两点

  1. 通过命令行交互询问用户问题
  2. 根据用户回答的结果生成文件

那么我们通过node.js发起命令行询问需要借助inquirer这个模块,所以我们先再安装一下这个模块

npm install inquirer -dev

需要使用到模板引擎,这里选择安装ejs

npm install ejs -dev

创建两个模板文件

iindex.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title><%= name %></title>
</head>
<body>
</body>
</html>

style.css

body{
    margin: 0;
    color:white;
    background-color: black;
}

cli.js

#!/usr/bin/env node

// NodeCLI应用入口文件必须要有一个文件头
// 如果是Linux或者macOS还要把这个文件读写权限改为755,通过运行chmod 755 cli.js实现

/*
脚手架的工作过程
1.通过命令行交互询问用户问题
2.根据用户回答的结果生成文件
*/
const fs = require('fs')
const path = require('path')
const inquirer = require('inquirer')
const ejs = require('ejs')

// prompt方法用来发起一个命令行询问
inquirer.prompt([
    {
        type: 'input',
        name: 'name',
        message: 'Project name?'
    }
]).then(answers => {
    // console.log(answers)
    // 根据用户回答的结果生成文件
    // 模板目录
    const tmplDir = path.join(__dirname,'templates')
    // 目标目录
    const destDir = process.cwd()

    // 将模板下的文件全部转换到目标目录
    fs.readdir(tmplDir, (err,files) => {
        if(err) throw err
        files.forEach(file => {
            // 通过模板引擎渲染文件
            ejs.renderFile(path.join(tmplDir,file),answers,(err,result) => {
                if (err) throw err
                // 将结果写入目标文件路径
                fs.writeFileSync(path.join(destDir,file),result)
            })
        });
    })
})

退出当前文件夹,另外新建一个demo文件夹进去,并执行sample-scaffolding

cd ..
mkdir demo
cd demo
sample-scaffolding

再看看demo文件夹,成功生成我们想要的文件

以上是关于前端工程化2——常见脚手架工具介绍使用和工作原理分析(YeomanPlop)手写脚手架工具的主要内容,如果未能解决你的问题,请参考以下文章

前端脚手架介绍

前端工程化实战:React 模块化开发性能优化和组件化实践

前端工程化—部署

前端工程师为什么要学习编译原理?

yeoman简介与基础使用

前端脚手架开发指南