使用yeoman根据自己的模板创建一个脚手架

news2024/11/15 8:23:29

介绍

  1. 本文使用的模板并不是通用模板~,是自己构建的模板。内部具体如何选择模板逻辑就没有了,仅仅相当于入门demo实现流程。
  2. 有兴趣学习脚手架的话yo还是不错的,走完本文逻辑可以试试看抽成自己项目,然后引用至公司~
  3. 加油!
  4. 参考资料:
  5. yeoman官网
  6. node官网文档选择

实现过程

  1. 创建文件夹(xxx/csdn),然后执行npm init -y
    (1)注意name必须为 generator-xxx ; (xxx为你自定义名字,这里我们以 generator-app来举例子)
    在这里插入图片描述

  2. 再创建 (xxx/csdn/generators/app)(xxx/csdn/generators/app/index.js)
    xxx/csdn/generators/app/index.js内填入以下内容

    const Generator = require('yeoman-generator');
    module.exports = class extends Generator {
    	method() {
    		console.log('我执行了')
    	}
    }
    
  3. 下载需要的依赖
    (1)yeoman-generator[ npm install --save yeoman-generator ]
    (2)inquirer[ npm i inquirer@8.0.0 ]
    (3)ejs[npm i ejs]
    (4)yo[ npm install -g yo ]
    (5)generator-webapp[ npm install -g generator-webapp ]

做完以上操作后你的界面结构应该是这样的(你的yeoman环境准备完毕)

在这里插入图片描述

  1. 接下来进入cmd小黑窗运行 npm link命令;(不懂 npm link 意思的可以去看看我这篇文章)

  2. 然后任意找一个地方建立一个文件夹(d:/xxxxxxxx/use),cmd进入小黑窗然后执行yo app 命令(记住你一开始使用的 generator-app则运行这个命令,如果不是则yo xxx;(xxx为你自定义的名字)
    如果执行完毕后你出现以下情况,则说明你成功了一半了~
    在这里插入图片描述

  3. 创建 xxx/csdn/utils/readFilePath.js文件,填入以下代码,代码介绍代码里有~

/**
 * fileDisplay(url, callback)
 * @param url: 你即将读取的文件夹路径
 * @param callback: 回调函数
 */

// node fs模块
const fs = require('fs');
// node path模块
const path = require('path');
// 收集所有的文件路径
const arr = [];
let timer = null;
class firstUrl {
  _url = '';
  constructor() {
    this.get()
  }
  get(url) {
    if (this._url) return this._url
    this._url = url
    return url
  }
}
const init = new firstUrl();
const fileDisplay = (url, cb) => {
  init.get(url);
  const filePath = path.resolve(url);
  //根据文件路径读取文件,返回文件列表
  fs.readdir(filePath, (err, files) => {
    if (err) return console.error('Error:(spec)', err)
    files.forEach((filename) => {
      //获取当前文件的绝对路径
      const filedir = path.join(filePath, filename);
      // fs.stat(path)执行后,会将stats类的实例返回给其回调函数。
      fs.stat(filedir, (eror, stats) => {
        if (eror) return console.error('Error:(spec)', err);
        // 是否是文件
        const isFile = stats.isFile();
        // 是否是文件夹
        const isDir = stats.isDirectory();
        if (isFile) {
          // 这块我自己处理了多余的绝对路径,第一个 replace 是替换掉那个路径,第二个是所有满足\\的直接替换掉
          arr.push(filedir.replace(init.get(), '').replace(/\\/img, '/'))
          // 最后打印的就是完整的文件路径了
          if (timer) clearTimeout(timer)
          timer = setTimeout(() => cb && cb(arr), 200)
        }
        // 如果是文件夹
        if (isDir) {
          arr.push(filedir.replace(init.get(), '').replace(/\\/img, '/'))
          fileDisplay(filedir, cb)
        };
      })
    });
  });
}
// 测试代码
// fileDisplay('./src', (arr) => {
//   console.log(arr, '-=')
// })
// commonjs规范
module.exports = fileDisplay;
  1. 然后 xxx/csdn/generators/app/index.js文件内容替换成以下内容。
const Generator = require('yeoman-generator');
const inquirer = require('inquirer');
const fileDisplay = require('../../utils/readFilePath.js')
const path = require('path')
const ejs = require('ejs')
const fs = require('fs')

const exec = require("child_process").exec;

const execNpmi = () => {
  const cmd = 'npm i';
  exec(cmd, {
    maxBuffer: 1024 * 2000,
    stdio: 'inherit',
    shell: true
  }, function (err, stdout, stderr) {
    if (err) {
      console.log(err);
      Promise.reject(err);
    } else if (stderr.lenght > 0) {
      Promise.reject(new Error(stderr.toString()));
    } else {
      console.log(stdout);
      Promise.resolve();
    }
  });
}

module.exports = class extends Generator {
  method1() {
    const _this = this;
    inquirer.prompt([
      /* 在这里配置您的问题(可以设置多个,它们将按顺序向用户提出) */
      {
        type: 'input',
        name: 'name',
        message: '请输入项目名称'
      }
    ]).then(answers => {
      // 回调,对用户输入的答案就行处理
      // 目标目录
      const destDir = process.cwd();
      const tmpDir = path.join(__dirname, 'templates')
      const ejsArr = ['.js', '.ts', '.vue', '.jsx', '.tsx', '.html', '.css', '.json']
      fileDisplay(tmpDir, (arrList) => {
        console.log(arrList, 'arrList')
        // 克隆文件及文件夹
        arrList.forEach(file => {
          fs.stat(path.join(tmpDir, file), (eror, stats) => {
            // 是否是文件
            const isFile = stats.isFile();
            // 是否是文件夹
            const isDir = stats.isDirectory();
            if (isFile) {
              // 如果满足 ejs 的文件规则 则进入 ejs 模板模式
              if (ejsArr.includes(path.extname(file).toLowerCase())) {
                ejs.renderFile(path.join(tmpDir, file), answers, function (err, res) {
                  if (err) return console.log(err, '写入错误');
                  fs.writeFileSync(path.join(destDir, file), res);
                });
              } else {
                // 不满足则直接读取文件并进行拷贝
                fs.readFile(path.join(tmpDir, file), 'utf8', function (err, info) {
                  if (err) return console.log(err)
                  fs.writeFileSync(path.join(destDir, file), info);
                })
              }
            }
            // 如果是文件夹
            if (isDir) {
              fs.mkdirSync(path.join(destDir, file));
            };
          })
        });
        // 执行命令行
        execNpmi();
      })
    });
  }
};
  1. 然后创建模板文件夹xxx/csdn/generators/app/templates。里面内容则为你需要的模板。

  2. 如果你没用模板可以用用我的小模板【注意要切换分支,使用template分支】

  3. 最终去到(d:/xxxxxxxx/use)进入小黑框执行 yo app;下图为最终输出结果(因为会下载依赖会导致界面黑屏卡顿,但是你会看到新增加node_modules还在新增文件,这个就说明是没问题的,需等待一会儿)

在这里插入图片描述

最终说明一下ejs语法

  1. 模板文件更改name为ejs语法就行了(<%= name %>);这个name是我们自己在控制台中输入的值,我们给它定义的名称就为name。所以说这里取值为name。
    在这里插入图片描述
  2. 当你的模板文件中有ejs语法的时候需要这样写(<%%= xxxxxxx %>)表示<%%= xxxxxxx %>编译为<%= xxxxxxx %>
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/382949.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【日常总结】Docker 磁盘占满解决方案

目录 项目背景&#xff1a; 问题描述 原因分析&#xff1a; 解决方案&#xff1a; Step 1&#xff1a;查看硬盘使用情况 Step 2&#xff1a;安装crontab Step 3&#xff1a;编写清理脚本cleardockerlog.sh&#xff0c;并执行一次 Step 4&#xff1a;加入定时任务,并设置…

什么是客户忠诚度?建立忠诚文化的 5 种方法

客户忠诚度影响企业的各个方面&#xff0c;例如收入、品牌形象、预算分配和产品路线图。拥有忠实的客户群对于建立成功的企业至关重要&#xff0c;因为您的客户是您的主要拥护者&#xff0c;有助于为您的企业营造积极的氛围。 什么是客户忠诚度&#xff1f; 客户忠诚度衡量客户…

深入浅出 MyBatis 的一级、二级缓存机制

一、MyBatis 缓存 缓存就是内存中的数据&#xff0c;常常来自对数据库查询结果的保存。使用缓存&#xff0c;我们可以避免频繁与数据库进行交互&#xff0c;从而提高响应速度。 MyBatis 也提供了对缓存的支持&#xff0c;分为一级缓存和二级缓存&#xff0c;来看下下面这张图…

java Object 万字详解 (通俗易懂)

基本介绍构造方法成员方法hashCode()getClass()toString()equals()finalize()JavaBean重写Object类的方法重写toString重写equals一、基本介绍Object类是java类层次最顶层的基类&#xff08;父类&#xff09;&#xff0c;所有类都是直接或间接继承自Object类&#xff0c;因此&a…

进程概念(详细版)

进程的概念本文主要介绍进程的相关知识 文章目录认识冯诺依曼体系结构操作系统的基本概念操作系统的作用是什么系统调用和库函数相关概念进程基本概念描述进程进程控制块(PCB)task_struct 结构体进程是如何被操作系统管理起来的先描述再组织描述好&#xff0c;组织好&#xff0…

taobao.item.img.delete( 删除商品图片 )

&#xffe5;开放平台免费API必须用户授权 删除商品图片 公共参数 请求地址: HTTP地址&#xff1a;http://gw.api.taobao.com/router/rest 公共请求参数: 公共响应参数: 请求参数 响应参数 点击获取key和secret 请求示例 TaobaoClient client new DefaultTaobaoClient(url…

学习ifconfig实战技巧,成为网络管理高手

文章目录前言一. ifconfig 命令介绍二. 语法格式及常用选项三. 参考案例3.1 显示网络设备信息3.2 启动和关闭指定的网卡3.3 对指定的网卡设备执行修改IP地址操作3.4 启动和关闭ARP协议3.5 使用ifconfig添加网卡总结前言 大家好&#xff0c;又见面了&#xff0c;我是沐风晓月&a…

Neovim for Rust

之前学习 Rust 一直使用的都是 VScode rust-analyzer&#xff0c;最近看到有网友安利 Neovim 于是就试了试&#xff0c;发现确实美观&#xff0c;好用&#xff0c;而且内存占用比较小。我个人很喜欢&#xff0c;也推荐给给大家。 前提&#xff1a;得有个代理&#xff0c;不然大…

一个自学自动驾驶(决策规划控制方向)的研究生学习资料总结(附相关资料的链接)

项目仓库 欢迎访问我的Github主页 项目名称说明chhCpp学习C仓库chhRobotics学习自动驾驶、控制理论相关仓库(python实现)chhRobotics_CPP学习自动驾驶、控制理论相关仓库(c实现)chhML 、chh-MachineLearning学习机器学习仓库chhRL学习强化学习仓库chhTricks存放一些有意思的t…

Unity烘焙常见问题

本文首发于公众号洪流学堂&#xff0c;未经允许&#xff0c;不可转载。 Unity中光影烘焙经常会遇到很多莫名其妙的问题&#xff0c;大智总结了一个问题解决手册&#xff0c;本文是比较常见的一些问题&#xff0c;还有一些不那么常见的问题&#xff0c;《手册全文pdf》获取方法&…

【2023蓝桥杯】2018年第九届C/C++A组真题(解析笔记)

目录 ♥【分数】循环累乘/快速幂运算/最大公因数 ♥【星期一】闰年/周期循环 ♥【乘积尾零】遍历/取余/取整 ♥【第几个幸运数】 遍历 ♥【打印图形】dfs填空 【航班时间】字符串/思维/时间换算 【三体攻击】差分&#xff01;中等难度 ♥【全球变暖】dfs/连通块计数 *…

Python解题 - CSDN周赛第33期

本期四道题全考过&#xff0c;题解在网上也都搜得到。。。没有想法&#xff0c;顺手水一份题解吧。 第一题&#xff1a;奇偶排序 给定一个存放整数的数组&#xff0c;重新排列数组使得数组左边为奇数&#xff0c;右边为偶数。 输入描述&#xff1a;第一行输入整数n。(1<n<…

深究Java Hibernate框架下的Deserialization

写在前面 Hibernate是一个开源免费的、基于 ORM 技术的 Java 持久化框架。通俗地说&#xff0c;Hibernate 是一个用来连接和操作数据库的 Java 框架&#xff0c;它最大的优点是使用了 ORM 技术。 Hibernate 支持几乎所有主流的关系型数据库&#xff0c;只要在配置文件中设置好…

在 The Sandbox 中以全新的 Rabbids 体验庆祝兔年!

育碧(Ubisoft) 和 The Sandbox 联手为你们带来终极的农历新年体验&#xff01; 穿戴上你们新鲜出炉的 Rabbids 人物化身来参加派对吧&#xff0c;保证震撼整个元宇宙&#xff01;这个全新体验为 Rabbids 人物化身持有者专属。没有获得 Rabbids 人物化身吗&#xff1f;不要担心&…

【Java】P2 基础语法与运算符

Java 基础语法 运算符Java注释方法基本数据类型驼峰命名法Scanner类基本运算除法隐式转换逻辑运算符 以及 短路逻辑运算符三元运算符前言 上一节内容涵盖Java的基础知识&#xff0c;包含安装下载&#xff0c;JDK与JRE等。 链接&#xff1a;https://blog.csdn.net/weixin_43098…

java 多线程处理任务

首先介绍一下我的使用场景我在redis set集合中有几十万个行程id&#xff0c;我需要一个脚本来离线计算每个行程的里程&#xff0c;计算完了之后&#xff0c;将公里数填到mongodb的表中&#xff0c;并且删除set集合中这个元素。我的目录结构我们创建一个maven项目&#xff0c;然…

STM32之PWM

PWMPWM&#xff0c;英文名Pulse Width Modulation&#xff0c;是脉冲宽度调制缩写&#xff0c;它是通过对一系列脉冲的宽度进行调制&#xff0c;等效出所需要的波形&#xff08;包含形状以及幅值&#xff09;&#xff0c;对模拟信号电平进行数字编码&#xff0c;也就是说通过调…

Office 365用户报告

通过ADManager Plus的现成Office 365用户报告&#xff0c;您无需复杂的PowerShell脚本&#xff0c;即可查找Office 365环境中用户的重要信息。使用这些报告&#xff0c;您只需点击几次基于Web的控制台&#xff0c;即可提取Office 365环境中活动和不活动用户数量等信息&#xff…

Celery 分布式任务队列

1. 认识 Celery Celery 是一个 基于 Python 开发的分布式异步消息任务队列&#xff0c;可以实现任务异步处理&#xff0c;制定定时任务等。 异步消息队列&#xff1a;执行异步任务时&#xff0c;会返回一个任务 ID 给你&#xff0c;过一段时间后拿着任务 ID 去取执行结果定时…

进程的介绍

文章目录一.进程的概念1.1概念1.2进程的组成1.2.1 PCB中描述进程的特征二.进程的虚拟地址空间三.进程间的通信引入线程一.进程的概念 1.1概念 百科的介绍: 换句话说,一个跑起来的程序,就是一个进程,也就是在操作系统中运行的exe程序就是一个进程,如下图的进程列表 进程是操…