脚手架下载项目模版功能实现流程

项目创建前准备阶段架构设计:

prepare方法是有清空当前目录的操作的,所以新建一个文件夹/Users/Minjie/Documents/test/mj-cli-test中去执行命令,因为mj-cli-dev命令是全局的;
__dirname它会去找当前执行时的代码,如果在另一个进程中执行,不能获取当前目录;可以用path.resolve(".")

js 复制代码
mj-cli-dev init --targetPath /Users/Minjie/Documents/vue3/mj-cli-dev/commands/init --debug test-project

准备工作

强制清空当前目录

commands/init目录下安装inquirer库;

js 复制代码
lerna add inquirer@7.3.3 commands/init

lerna add fs-extra@9.0.1 commands/init

如果命令中有--force时会确认两次,如果命令中无--force时只会做一次确认;

js 复制代码
async prepare() {
    const localPath = process.cwd();
    // 1.当前目录是否为空
    if (!this.isCwdEmpty(localPath)) {
      // 询问是否继续创建
      // 没有--force的命令会进行这次确认
      let ifContinue = false;
      if (!this.force) {
        ifContinue = (
          await inquirer.prompt([
            {
              type: "confirm",
              name: "ifContinue",
              default: false,
              message: "当前文件夹不为空,是否继续创建项目?",
            },
          ])
        ).ifContinue;
        if (!ifContinue) {
          return;
        }
      }
      // 2.是否为强制更新
      if (ifContinue || this.force) {
        // 清空当前目录,给用户做二次确认
        const { secondContinue } = await inquirer.prompt([
          {
            type: "confirm",
            name: "secondContinue",
            default: false,
            message: "是否确认清空当前目录下的文件?",
          },
        ]);
        if (secondContinue) {
          fse.emptyDirSync(localPath);
        } else {
          return;
        }
      }
    } else {
    }
    return this.getProjectInfo();
  }

项目名称和版本号合法性校验

js 复制代码
lerna add semver@7.3.4 commands/init
js 复制代码
// 当选择时项目类型时
const o = await inquirer.prompt([
        {
          type: "input",
          name: "projectName",
          message: "请输入项目名称",
          default: "",
          validate: function (v) {
            const done = this.async();

            // Do async stuff
            setTimeout(function () {
              // 1.输入的首字符;
              // 2.尾字符必须是英文字符或数字,不能为字符
              // 3.字符近允许是"-_""
              if (
                !/^[a-zA-Z]+([-][a-zA-Z][a-zA-Z0-9]*|[_][a-zA-Z][a-zA-Z0-9]*|[a-zA-Z0-9])*$/.test(
                  v
                )
              ) {
                done("请输入合法的项目名称");
              } else {
                done(null, true);
              }
            }, 0);
          },
          filter: function (v) {
            return v;
          },
        },
        {
          type: "input",
          name: "projectVersion",
          message: "请输入版本号",
          default: "1.0.0",
          validate: function (v) {
            const done = this.async();

            setTimeout(function () {
              if (!!!semver.valid(v)) {
                done("请输入合法的版本号");
              } else {
                done(null, true);
              }
            }, 0);
          },
          filter: function (v) {
            if (!!semver.valid(v)) {
              return semver.valid(v);
            } else {
              return v;
            }
          },
        },
      ]);

下载模版

下载模版步骤:

1.通过项目模板api获取项目模板信息

1.1.通过egg.js搭建一套后端系统提供api

1.2.通过api的项目存储项目模板(vue-cli、vue-element-admin)

1.3.将项目模版信息存储到mongodb数据库中

1.4.通过egg.js获取mongodb中的数据并且通过API返回

通过api的项目存储项目模板

首先创建项目:

js 复制代码
mkdir mj-cli-dev-template
cd mj-cli-dev-template
mkdir mj-cli-dev-template-vue3
cd mj-cli-dev-template-vue3
npm init -y
cnpm i -g @vue/cli
vue create vue-test

每次都因为node版本问题卡好久;

在vue-test中执行npm run serve;vue3项目模板就创建好了;

接下来精简一下项目,删除一些不必要的文件,比如node_modolues等;然后移动到template的文件夹中; 在mj-cli-dev-template-vue3目录下执行npm publish发布这个包; 接着需要在mongodb中存储这个模版信息,实现一个API,让脚手架端能获取到这个模版;

在mongodb中写入一条数据:

js 复制代码
db.project.insert({name: 'vue3标准模版', 
    npmName: 'mj-cli-dev-template-vue3',
    version: '1.0.0',
})

此时在mj-cli-dev-server服务中可以获取到mongodb中的数据;

接着我们就要去脚手架mj-cli-dev中请求数据;在utils目录下创建request包;

js 复制代码
lerna create @mj-cli-dev/request

// 安装axios
lerna add axios@0.21.1 utils/request

request/lib/index.js文件;

js 复制代码
"use strict";

const axios = require("axios");

const BASE_URL = process.env.MJ_CLI_BASE_URL
  ? process.env.MJ_CLI_BASE_URL
  : "http://127.0.0.1:7002";

const request = axios.create({
  baseURL: BASE_URL,
  timeout: 5000,
});

request.interceptors.response.use(
  (response) => {
    if (response.status === 200) {
      return response.data;
    }
  },
  (error) => {
    return Promise.reject(error);
  }
);

module.exports = request;

在commands/init模块中引用utils/request模块; 新建commands/lib/getProjectTemplate文件,在commands/lib/index的prepare方法加入判断逻辑:

js 复制代码
    // 0.判断项目模版是否存在
    const template = await getProjectTemplate();

    if (!template || template.length == 0) {
      this.template = template;
      throw new Error("项目模版不存在!");
    }

通过环境变量配置默认URL+选择项目模板功能开发

checkEnv方法还遗留了问题;

commands/init模块getProjectInfo中增加选择模板命令;

js 复制代码
{
  type: "list",
  name: "projectTemplate",
  message: "请选择项目模板",
  choices: this.createTemplateChioice(),
},

 // 生成模板选项
  createTemplateChioice() {
    const arr = this.template.map((item) => ({
      name: item.npmName,
      value: item.name,
    }));

    return arr;
  }

下载一个新的模板vue-element-admin-master点击这里;将这个模版也放入之前mj-cli-dev-template中;为vue-element-admin-master精简代码然后npm run dev运行起来;新建一个目录,然后将下载的vue-element-admin-master放到template文件夹下;

接着进入mj-cli-dev-template-vue-element-admin目录下执行发布npm publish命令;

发布成功之后,我们也把这个模版的信息维护到mongodb中;

js 复制代码
db.project.insert({name: 'vue-element-admin', 
    npmName: 'mj-cli-dev-template-vue-element-admin',
    version: '1.0.0',
})

数据插入成功之后,再去执行脚手架命令,现在就显示出了两个模板信息;

脚手架下载项目模版

我们会把templage拷贝到用户的目录下;

首先在commands/init模块依赖models/command模块;

安装user-home包;

在commands/init模块增加下载模版的方法:

js 复制代码
  // 下载模版
  async downloadTemplate() {
    const { projectTemplate } = this.projectInfo;
    const templateInfo = this.template.find(
      (item) => item.npmName === projectTemplate
    );
    const targetPath = path.resolve(userHome, "mj-cli-dev", "template");
    const storeDir = path.resolve(
      userHome,
      "mj-cli-dev",
      "template",
      "node_modules"
    );

    const { npmName, version } = templateInfo;
    const templateNpm = new Package({
      targetPath,
      storeDir,
      packageName: npmName,
      packageVersion: version,
    });

    // 不存在时
    if (!(await templateNpm.exists())) {
      await templateNpm.install();
    } else {
      await templateNpm.update();
    }
  }

通过spinner实现命令行loading效果

人家自带loading了。。。这个功能略过。。。

相关推荐
y先森1 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy1 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189111 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿2 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡3 小时前
commitlint校验git提交信息
前端
虾球xz4 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇4 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒4 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员4 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐4 小时前
前端图像处理(一)
前端