从0搭建前端脚手架详解(小白也可以搭建)

news2024/9/20 19:32:18

本篇文章用来为大家提供一个搭建简易前端脚手架的思路。

先来看一眼实现的效果。

请添加图片描述

从图上来看这个脚手架的功能非常的简单只有一个创建的命令,其他都是帮助和显示版本号的。

请添加图片描述

也就是上图这句,创建一个新项目,只需要输入create 项目名便可使用,在创建时执行了一系列的操作,这一块的思路很简单,就是将git仓库中的项目模板拷贝下来再依据使用者的不同操作对复制下来的模板的部分文件进行修改就可以了,大致思路便介绍到这里,接下来我们便来详细的讲讲如何实现,以及会用到的依赖。

脚手架目录结构

请添加图片描述

了解搭建的脚手架

脚手架就是在启动的时候询问一些简单的问题,并且通过用户回答的结果去渲染对应的模板文件,我们接下来的流程亦是如此

脚手架的初始化

由于它是一个npm的包,因此我们需要使用npm的初始化命令,随意新建一个文件夹打开命令行,输入npm init,会出现以下情况。

请添加图片描述

名称意思默认值
package name包的名称创建文件夹时的名称
version版本号1.0.0
description包的描述创建文件时的名称
entry point入口文件index.js
test command测试命令
git repositorygit仓库地址
keywords关键词,上传到npm官网时在页面中展示的关键词
author作者信息,对象的形式,里面存储一些邮箱、作者名、url
license执照MIT

这就是输入初始化命令时会询问的东西,回答完这些后就会生成一个 package.json 的文件,这个文件就是记录包的信息。

如果想要了解更多,可查看如下地址:
package.json详解

脚手架依赖安装

用到如下依赖请安装。

npm i path
npm i chalk@4.1.0
npm i fs-extra
npm i inquirer@8.2.4
npm i commander
npm i axios
npm i download-git-repo

询问用户问题

创建入口文件

在询问问题前我们需要先创建一个入口文件,创建完成后在package.json中添加bin项,并且将入口文件路径写进去
请添加图片描述

填写完入口文件路径后在入口文件内随便输出一句, 但必须在入口文件顶层声明文件执行方式为node。
声明代码:#! /usr/bin/env node

请添加图片描述

写完后我们需要测试一下我们是否可以正常的访问的我们的脚手架,在本文件夹打开命令行,输入 npm link ,该命令会创建一个全局访问的包的快捷方式,这个是临时的就是本地测试的时候用的,这个在命令行输入你的脚手架的名称可以看到入口文件输出的内容。

请添加图片描述

最基本的交互命令

在完成上一步后我们就要开始与用户进行交互了,这个时候我们就需要用到一个用于自定义命令行指令的依赖 commander。

引入依赖:

const program = require('commander')

简单介绍一下commander依赖常用的方法

command

命令。.command()的第一个参数为命令名称。命令参数可以跟在名称后面,也可以用.argument()单独指定。

参数可为必选的(尖括号表示)、可选的(方括号表示)或变长参数(点号表示,如果使用,只能是最后一个参数)。

例如:

// 创建一个create命令
.command('create <app-name>')

parse

解析。.parse()的第一个参数是要解析的字符串数组,也可以省略参数而使用process.argv,这里我们也是用process.argv用来解析node的参数。

例如:

// 解析用户执行命令传入参数
program.parse(process.argv);

option

选项。option()可以附加选项的简介。第一个参数可以定义一个短选项名称(-后面接单个字符)和一个长选项名称(–后面接一个或多个单词),使用逗号、空格或|分隔。第二个参数为该选项的简介。

例如:

.option('-f, --force', '如果存在的话强行覆盖')

action

处理函数。用command创建的自定义命令的处理函数,action携带的实参顺序就是命令上的参数的顺序。

例如:

program
.command('create <app-name>')
// 这个name 就代表第一个必填参数 options就代表其余, 如果有第二个就在写一个,最后一个永远是剩余参数
.action((name, options) => {
    console.log(name)
    // 打印执行结果
    // require("../lib/create")(name, options)
})

编写交互命令 create

入口文件

#! /usr/bin/env node
const program = require('commander');
const chalk = require('chalk');

// 定义命令和参数
// create命令
program
.command('create <app-name>')
.description('create a new project')
// -f or --force 为强制创建,如果创建的目录存在则直接覆盖
.option('-f, --force', 'overwrite target directory if it exist')
.action((name, options) => {
    // 打印执行结果
    console.log('项目名称', name)
})

// 解析用户执行命令传入参数
program.parse(process.argv);

这里我们创建了一个叫 create 的自定义指令,这个命令有着必填的项目名、可以选择的强制覆盖的选项 -f,有着处理函数action

我们在action中接收并打印了用户输入的项目名称。

接下来我们再次运行一下自己的脚手架并带上create命令,我的叫test

test-cli create app

出现如下就说明第一个命令创建成功了

这里请注意 解析用户命令参数的操作一定要在最后一行否则什么都不会出现。

program.parse(process.argv)

到这里为止我们成功为我们脚手架创建了第一个交互命令,想查看更多关于 commander 的请点击这里commander。

创建第一个模板项目

在创建了一个基本命令 create 后我们就要开始创建一个模板并在用户使用该命令时复制并修改我们所创建的模板。

创建一个模板

我们在复制模板前需要一个模板,现在的我们随便创建一个文件夹并取名为template里面创建一个html。

像这样创建好后,我们就有了一个模板,但我们依然需要让模板有一个可被下载、查询的地方,这里我选择的是使用 git 组织仓库,因为这样可以直接通过git提供的接口进行文件下载,包括选择不同的模板等。

上传模板

我们先去 git 的官网中新建一个存放模板的组织仓库。


点击图中的位置进入组织,并点击下图的创建

会进入到付费的位置,没有大需求就选免费

在这里插入图片描述

填写信息完基本就算创建成功了
在这里插入图片描述

接下来在组织中创建一个储存库
在这里插入图片描述

这里我们暂且选择可见的仓库,千万不要选择私人仓库,否则git接口会找不该仓库
在这里插入图片描述

创建好后的仓库,就直接将模板代码提交至也本次创建的仓库中就可以了,我们在vscode中进行演示。
先点击推送

如果没有推送的仓库则会提示是否添加推送仓库,我们点击推送远程仓库,并从中找到自己的仓库

在这里插入图片描述

择完成后输入仓库名称,然后会报错,报错原因就是因为暂无推送的内容,这个使用,正常的在 vscode 中提交代码就行了,然后查看自己的仓库,会出现上传的内容
在这里插入图片描述

增加一个新的版本标签

跟着下列图操作

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
点击发布发行版后就可以了。

下载模板

我们上传模板后可以通过 git 提供的接口来完成下载模板的功能,首先我们先去询问用户要下载的模板名称然后在用依赖包来进行下载:
https://api.github.com/orgs/geeksTest/repos 获取该组织下的所有模板

create命令后续操作

上传模板后,我们就可以继续完成create命令的后续操作了。

create命令下使用创建函数

program
.command('create <app-name>')
.description(chalk.cyan('create a new project'))
// -f or --force 为强制创建,如果创建的目录存在则直接覆盖
.option('-f, --force', 'overwrite target directory if it exist')
.action((name, options) => {
    // 打印执行结果
    require("../lib/create")(name, options)
})

创建create文件

创建 create 文件用来回应用户的 create 命令。

这里用到的依赖

// lib/create.js

const path = require('path')
// fs-extra 是对 fs 模块的扩展,支持 promise 语法
const fs = require('fs-extra')
// 用于交互式询问用户问题
const inquirer = require('inquirer')
// 导出Generator类
const Generator = require('./Generator')

//1. 抛出一个方法用来接收用户要创建的文件夹(项目)名 和 其他参数
module.exports = async function (name, options) {
  // 当前命令行选择的目录
  const cwd  = process.cwd();
  // 需要创建的目录地址
  const targetAir  = path.join(cwd, name)
  
  //2 判断是否存在相同的文件夹(项目)名
  // 目录是否已经存在?
  if (fs.existsSync(targetAir)) {
    // 是否为强制创建?
    if (options.force) {
      await fs.remove(targetAir)
    } else {
      // 询问用户是否确定要覆盖
      let { action } = await inquirer.prompt([
        {
          name: 'action',
          type: 'list',
          message: 'Target directory already exists Pick an action:',
          choices: [
            {
              name: 'Overwrite',
              value: 'overwrite'
            },{
              name: 'Cancel',
              value: false
            }
          ]
        }
      ])
      // 如果用户拒绝覆盖则停止剩余操作
      if (!action) {
        return;
      } else if (action === 'overwrite') {
        // 移除已存在的目录
        console.log(`\r\nRemoving...`)
        await fs.remove(targetAir)
      }
    }
  }

  //3 新建generator类
  const generator = new Generator(name, targetAir);
  generator.create();
}

创建generator类

// lib/Generator.js

const { getRepoList, getTagList } = require('./http')
const ora = require('ora')
const inquirer = require('inquirer')
const util = require('util')
const downloadGitRepo = require('download-git-repo') // 不支持 Promise
const chalk = require('chalk')
const path = require('path');
const fs = require("fs-extra");

// 添加加载动画
async function wrapLoading(fn, message, ...args) {
  // 使用 ora 初始化,传入提示信息 message
  const spinner = ora(message);
  // 开始加载动画
  spinner.start();

  try {
    // 执行传入方法 fn
    const result = await fn(...args);
    // 状态为修改为成功
    spinner.succeed();
    return result; 
  } catch (error) {
    // 状态为修改为失败
    spinner.fail('Request failed, refetch ...');
  } 
}

class Generator {
  constructor (name, targetDir){
    // 目录名称
    this.name = name;
    // 创建位置
    this.targetDir = targetDir;
    // 对 download-git-repo 进行 promise 化改造
    this.downloadGitRepo = util.promisify(downloadGitRepo);
  }

  // 获取用户选择的模板
  // 1)从远程拉取模板数据
  // 2)用户选择自己新下载的模板名称
  // 3)return 用户选择的名称

  async getRepo() {
    // 1)从远程拉取模板数据
    const repoList = await wrapLoading(getRepoList, 'waiting fetch template');
    if (!repoList) return;
    // 过滤我们需要的模板名称
    const repos = repoList.map(item => item.name);

    // 2)用户选择自己新下载的模板名称
    const { repo } = await inquirer.prompt({
      name: 'repo',
      type: 'list',
      choices: repos,
      message: 'Please choose a template to create project'
    })

    // 3)return 用户选择的名称
    return repo;
  }

  // 获取用户选择的版本
  // 1)基于 repo 结果,远程拉取对应的 tag 列表
  // 2)自动选择最新版的 tag

  async getTag(repo) {
    // 1)基于 repo 结果,远程拉取对应的 tag 列表
    const tags = await wrapLoading(getTagList, 'waiting fetch tag', repo);
    if (!tags) return;
    
    // 过滤我们需要的 tag 名称
    const tagsList = tags.map(item => item.name);

    // 2)return 用户选择的 tag
    return tagsList[0]
  }

  // 下载远程模板
  // 1)拼接下载地址
  // 2)调用下载方法
  async download(repo, tag){
    // 1)拼接下载地址
    const requestUrl = `geeksTest/${repo}${tag ? '#'+tag : ''}`;

    // 2)调用下载方法
    await wrapLoading(
      this.downloadGitRepo, // 远程下载方法
      'waiting download template', // 加载提示信息
      requestUrl, // 参数1: 下载地址
      path.resolve(process.cwd(), this.targetDir) // 参数2: 创建位置
    ) 
  }

  // 核心创建逻辑
  // 1)获取模板名称
  // 2)获取 tag 名称
  // 3)下载模板到模板目录
  // 4) 对uniapp模板中部分文件进行读写
  // 5) 模板使用提示
  async create(){

    // 1)获取模板名称
    const repo = await this.getRepo()

    // 2) 获取 tag 名称
    const tag = await this.getTag(repo)

    // 3)下载模板到模板目录
    await this.download(repo, tag)
    
    // 5)模板使用提示
    console.log(`\r\nSuccessfully created project ${chalk.cyan(this.name)}`)
    console.log(`\r\n  cd ${chalk.cyan(this.name)}`)
    console.log(`\r\n  启动前请务必阅读 ${chalk.cyan("README.md")} 文件`)
  
  }
}

module.exports = Generator;

创建http文件

新建一个http.js的文件用来存放要请求的接口,我们用axios去请求.

依赖安装 npm i commander

// lib/http.js

// 通过 axios 处理请求
const axios = require('axios')

axios.interceptors.response.use(res => {
  return res.data;
})

/**
 * 获取模板列表
 * @returns Promise
 */
async function getRepoList() {
  return axios.get('https://api.github.com/orgs/geeksTest/repos')
}

/**
 * 获取版本信息
 * @param {string} repo 模板名称
 * @returns Promise
 */
async function  getTagList(repo) {
  return axios.get(`https://api.github.com/repos/geeksTest/${repo}/tags`)
}

module.exports = {
  getRepoList,
  getTagList
}

最后导出了两个方法, 模板列表、模板tag列表。
这个时候的api接口是可以直接在浏览器中访问到的,如果不想被人随意访问读取数据则可以在git中增加双因素验证,然后每次访问api时都会要求带上git的访问token否则会访问不到,查看双因素详情

搭建完成

完成这一步后我们再去进行test-cli create app命令,会看到下图。

在这里插入图片描述

会询问要创建的模板项目,我这里的远程组织模板叫做test,大家选择自己的模板回车,稍等一下就会创建成功,并看到在你使用命令的路径上多出一个项目名的文件夹,就成功了。
在这里插入图片描述

如果有对模板在下载后进行操作的需求可以使用fs依赖进行操作,到这里为止我们已经完成了一个简易的脚手架搭建,感谢大家耐心观看。

结语: 天才无非是长久的忍耐,努力吧!

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

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

相关文章

[附源码]计算机毕业设计大学生心理测评系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

MATLAB学习笔记(系统学习)

教程来源&#xff1a; 1.MATLAB教程&#xff1a;https://www.cainiaojc.com/matlab/matlab-tutorial.html 不断学习补充中~~~ 文章目录一、MATLAB基础二、MATLAB科研绘图&#xff08;重点在于修改参数&#xff0c;优化图片&#xff09;一、MATLAB基础 1.在MATLAB中使用分号&a…

免费网课查题接口

免费网课查题接口 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 查题校园题库&#xff1a;查题校园题库后台&#xff08;点击跳…

Java并发编程学习14-任务关闭(上)

任务关闭&#xff08;上&#xff09;-- 关闭基于线程的服务 《任务关闭》由于篇幅较多&#xff0c;拆分了两篇来介绍各种任务和服务的关闭机制&#xff0c;以及如何编写任务和服务&#xff0c;使它们能够优雅地处理关闭。 我们知道&#xff0c;应用程序通常会创建拥有多个线…

微服务框架 SpringCloud微服务架构 10 使用Docker 10.9 数据卷挂载案例2

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构10 使用Docker10.9 数据卷挂载案例210.9.1 直接开干10.9.2 数据卷挂载的方…

[附源码]Python计算机毕业设计Django设备运维平台出入库模块APP

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

动态数据增强及构造方案解决

前言 随着数据量的增长以及业务的调整变更&#xff0c;我们需要选择合适的技术及存储引擎对数据进行归类&#xff0c;调整&#xff0c;达到高并发、秒响应、低延迟及可扩展对现有程序的改造升级问题&现状 任务重&#xff0c;时间紧&#xff0c;人力不足&#xff0c;不能够…

[附源码]计算机毕业设计基于SpringBoot的玉石交易系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

源码深度剖析Spring Bean标签的解析及注册

在博客《一步一步带你深入源码看Spring是如何加载XML配置文件的》中把Spring对XML配置文件如何加载的说明白了&#xff0c;XML配置文件加载完成后就是对标签的解析&#xff0c;本篇博客就是针对Spring bean 标签的解析以及bean definition 的注册。 Spring 中的标签包括默认标…

Dreamweaver网页设计与制作100例 餐饮主题简洁日式料理餐饮网页设计(4页)HTML+CSS+JavaScript

&#x1f380; 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

[附源码]计算机毕业设计点餐系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

音视频技术开发周刊 | 274

每周一期&#xff0c;纵览音视频技术领域的干货。新闻投稿&#xff1a;contributelivevideostack.com。「紧急通知」LiveVideoStackCon 2022 音视频技术大会北京站改期各位LVSer们&#xff1a;因疫情影响&#xff0c;北京近期不再允许举办大型线下活动&#xff0c;我们无奈且抱…

【消息中间件】为什么选择RocketMQ及使用案例

目录 一、为什么选择RocketMQ 1、为什么是为什么选择RocketMQ 2、RocketMQ、ActiveMQ和Kafka之间的比较 2.1、对比1 2.2、对比2&#xff0c;接着上表 二、使用案例 1、引入依赖 2、编写启动类 3、编写application.yml配置文件 4、创建rocketmq文件夹 4.1、创建生产者…

OpenCV实战(4)——像素操作

OpenCV实战&#xff08;4&#xff09;——像素操作0. 前言1. 图像的基本组成2. 访问像素值2.1 修改图像像素2.2 cv::Mat_ 模板类2.3 完整代码示例3. 用指针扫描图像3.1 图像扫描3.2 其他减色公式3.3 使用输入和输出参数3.4 高效扫描连续图像3.5 低阶指针算法4. 使用迭代器扫描图…

linux操作系统期末考试题库

1. cal命令 目录 1. cal命令 2.cat命令 3.cd命令 4.date命令 5.echo命令 6.grep命令 7.head 命令 8.ls 命令 9.touch 命令 10.more命令 11. ln创建链接命令 12.查看进程 13.mkdir命令 cal -3 cal 查看指定日期的日历 cal 4 2022 cal 2018 2.cat命令 cat -n /etc…

认识MyBatis

MyBatis是什么&#xff1f; MyBatis是dao层&#xff08;持久层&#xff09;框架&#xff0c;它支持自定义SQL、存储过程以及高级映射。 MyBatis 免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的XML或注解来配置和映射原始类型、接口和Java …

2022 NCTF

MISC 炉边聚会 卡组代码是 Base64 编码的字节串&#xff0c;exp <?php $deckstring "AAEDAZoFKIwGngXIBrwFzgnQBfIHygf0CIgJkAiBogJ1gjMCPIHtgeeBeAD6AfyB7YHvgbgAAD4AO2B7wFkgnMCMwIga2B/QImgi6BJAIiAn2BOIJAAA"; #这是⼀个⾮常有趣的萨满卡组 $binary bas…

非零基础自学Golang 2 开发环境 2.2 配置GOPATH

非零基础自学Golang 学习文档地址&#xff1a;https://www.topgoer.cn/ 本文仅用于学习记录&#xff0c;不存在任何商业用途&#xff0c;如侵删【已联系过文档作者】 文章目录非零基础自学Golang2 开发环境2.2 配置GOPATH2.2.1 配置GOPATH2.2.2 go的项目目录2.2.3 适合个人开发…

[附源码]Python计算机毕业设计Django剧本杀交流分享平台

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

年产2万吨山楂酒工厂的设计-发酵工段及车间的设计(lunwen+任务书+cad图纸)

目录 1前 言 1 2总论 2 2.1设计依据 2 2.2设计指导思想和原则 2 2.3设计范围 2 2.3.1生产部门 2 2.3.2设计图纸 3 2.4工艺设计基本数据和指标 3 2.5生产工艺概述 3 2.6生产设备概述 4 2.7生产工艺流程图 4 2.8生产方法的简单介绍 6 3全程物料衡算 7 3.1全程总物料概算 7 3.1.1山…