经常会有人问我,前端的脚手架到底是什么东西?我一般也只能泛泛而谈,把对方拉到比我低的水平,然后一本正经的编点东西....

1、脚手架是一种约定和规范

  1. 相同的文件组织结构
  2. 相同的开发范式
  3. 相同的模块依赖
  4. 相同的工具配置
  5. 相同的基础代码
  6. 然后脚手架 将这些 重复性的东西全部都集成起来,减少这样无意义的操作

就像在 flutter new project 中,自动生成的 文件目录,文件结构,就是脚手架的一种,而 vue-cli ,react-create-app 也是脚手架的一种

2. 安装yeoman

- 安装 yeoman

sudo yarn global add yo

- 安装 generator-node

sudo yarn global add generator-node

创建一个目录之后输入命令

yo node

接下来就是等了.....

3. 使用yeoman

只想给已有的项目增加 部分功能,生成自己的 cli

yo node:cli

sudo npm link

my-modlue --help

可以发现 my-module 这个 命令 被注册进了命令之中

需要注意的是,在 mac ,使用 yarn link 是会出现问题的 相关 issue

3、创建自己的generator,用于自动生成 定义好的文件

mkdir generator-simple

cd generator-simple

yarn init --yes

yarn add yeoman-generator  // 所有 generator 的基类

创建 generators/app/index.js

// 作为 generator 的 核心入口
// 需要导入一个继承自 Yeoman Generator 的一些生命周期方法
// Yeoman Generator 在工作的时候回自动调用 再次类型中定义的 一些生命周期方法

const Generator = require('yeoman-generator')

module.exports = class extends Generator {
    // Yeoman 自动在生成文件阶段调用这个方法
    writing() {
        // 父类的 fs 模块
        this.fs.write(
            // 文件目录
            this.destinationPath('temp.txt'),
            // 文件内容
            Math.random().toString()
        ) 
    }
}

可能会报这个错,Unexpected end of JSON input while parsing near '...LAigpnGt0Bi7uIZXmMhXs' ,执行

npm cache clean --force

cd ../

mkdir simple

yo simple // 就能看到 生成了自己想要的文件

使用模板

在 generators/app 里创建 templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><%= title %></title>
</head>
<body>
    <% if (success) { %>
        <div>Hello generator</div>
    <% } %>
</body>
</html>

修改 index.js 中的代码

// 作为 generator 的 核心入口
// 需要导入一个继承自 Yeoman Generator 的一些生命周期方法
// Yeoman Generator 在工作的时候回自动调用 再次类型中定义的 一些生命周期方法

const Generator = require('yeoman-generator')

module.exports = class extends Generator {
    // Yeoman 自动在生成文件阶段调用这个方法
    writing() {
        // 通过模板方法 协议文件到目标目录
        const tmpl = this.templatePath('index.html')
        const output = this.destinationPath('index.html')
        const conext = { title: 'generator', success: true }
        this.fs.copyTpl(tmpl, output, conext)
    }
}

然后执行 sudo npm unlink

sudo npm link

在 simple 文件夹中执行

yo simple

使用 用户输入的值

// 作为 generator 的 核心入口
// 需要导入一个继承自 Yeoman Generator 的一些生命周期方法
// Yeoman Generator 在工作的时候回自动调用 再次类型中定义的 一些生命周期方法

const Generator = require('yeoman-generator')

module.exports = class extends Generator {
    promiting() {
        return this.prompt([
            {
                type: 'input', // 用户输入的方式
                name: 'title',
                message: 'your project title', // 提示
                default: this.appname, // appname 为 为项目生成目录的名称,作为 这个问题的默认值
            }
        ]).then(answers => {
            this.answers = answers
        })
    }
    // Yeoman 自动在生成文件阶段调用这个方法
    writing() {
        // 通过模板方法 协议文件到目标目录
        // 这里可以定义一个 数组,然后 通过遍历的方式,一次性生成一大堆文件
        const tmpl = this.templatePath('index.html')
        const output = this.destinationPath('index.html')
        const conext = { title: this.answers.title, success: true }
        this.fs.copyTpl(tmpl, output, conext)
    }
}

4、发布

echo node_modules > .gitignore 

git init

git add .  

git commit -m "XXX"

创建 github 仓库

git remote add origin xxxxxx

git push -u origin master // 上传 到 github

yarn publish       // 发布(国内一般都是 使用 了淘宝的镜像,而这个镜像 是只读的,所以发布不上去,就需要改回去)

yarn publish --registry https://registry.yarnpkg.com  // 手动推送 到 yarn 的地址上,这个是和 npm 库保持同步的

5、脚手架的原理—自己实现一个脚手架

mkdir scaffold

yarn init --yes

修改package.json,增加 bin 属性

{
  "name": "scaffold",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "bin": "cli.js"
}

在根目录下创建一个 cli.js

#!/usr/bin/env node

// 设置环境变量的 文件头

console.log('cli start')

sudo npm link

scaffold // 执行 脚手架命令

开始实现脚手架的具体工作流程

  1. 通过命令行 询问用户问题
  2. 根据用户输入的内容,生成文件

yarn add inquirer // 在命令行发起询问

yarn add ejs // 模板引擎

创建templates 文件夹,里面加入 两个文件 index.html 和 index.css

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><%= name %></title></title>
</head>
<body>
    
</body>
</html>
.<%= name %> {
    color: red;
}

修改 cli.js 里的内容

#!/usr/bin/env node

// 设置环境变量的 文件头
// 如果是 macOS 系统下,还得修改这个文件的权限为 755

const inquirer = require('inquirer')
const path = require('path')
const fs = require('fs')
const ejs = require('ejs')

inquirer.prompt([
    {
        type: 'input',
        name: 'name',
        message: '文件名称'
    }
]).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)
            })
        })
    })
})

然后到 一个新的 文件夹,

执行:

scaffold

  1. 所以脚手架 的原理到现在也比较清晰了
  2. 手动创建模板,或者需要的文件以及对应的配置
  3. 将 对应的命令注入到 bin 环境变量中
  4. 通过获取用户的输入,将输入 通过 模板语法注入到 之前的模板文件中
  5. 生成新的文件

 

 

 

 

Logo

前往低代码交流专区

更多推荐