Make writing a habit together! This is the 7th day of my participation in the “Gold Digging Day New Plan ยท April More text Challenge”. Click here for more details.

What will be gained

  • Master command line interaction methods
  • Server frameworkegg.jsThe application andapiDevelopment methods
  • egg.jsIntegrated cloudmongodbImplementing data storage

The main content

  • Scaffolding project creates functional architecture design
  • Obtain basic project information through command line interaction
  • egg.js+ cloudmongodbThe integration of
  • Develop front-end project templates
  • egg.jsGet the project templateAPIThe development of
  • Project template download function development
  • inquirerSource code parsing, thoroughly understand command line interaction

Create functional architecture designs

  • Scalable: can quickly reuse to different teams, adapt to the differences between different teams
  • Low cost: Templates can be added without changing the scaffolding source code, and the cost of adding templates is very low
  • A high performance: Controls storage space and makes full use of it during installationnodeMultiple processes improve installation performance

Create functional architecture blueprints

Preparation stage

Template Download phase

Template Installation Phase

Preparatory development

// commands\init\lib\index.js
'use strict';

const fs = require('fs');
const Command = require('@hzw-cli-dev/command');
const log = require('@hzw-cli-dev/log');
const inquirer = require('inquirer');
const fse = require('fs-extra');
const semver = require('semver');
const TYPE_PROJECT = 'project';
const TYPE_COMPONENT = 'component';

/ * * *@description: init Command, inherited from Command *@param {*}
 * @return {*}* /
class InitCommand extends Command {
  / * * *@description: Command initialization phase *@param {*}
   * @return {*}* /
  init() {
    // Project name
    this.projectName = this._argv[0] | |'project';
    // Whether to carry the force parameter
    this.force = !!this._argv[1].force;
    log.verbose('๐Ÿš€๐Ÿš€ ~ Mandatory Installation '.this.force);
    log.verbose('๐Ÿš€๐Ÿš€ ~ Project name '.this.projectName);
  }
  / * * *@description: Command execution phase *@param {*}
   * @return {*}* /
  async exec() {
    try {
      // 1. Preparation stage
      const ret = await this.prepare();
      if (ret) {
        // 2. Download the template
        // 3. Install the template}}catch(error) { log.error(error.message); }}/ * * *@description: Preparation stage *@param {*}
   * @return {*}* /
  async prepare() {
    Path.resolve ('.') is also available
    const localPath = process.cwd();
    // 1. Check whether the current directory is empty
    const isEmpty = this.isDirEmpty(localPath);
    let isContinue = false;
    if(! isEmpty) {if (!this.force) {
        // Ask the user to continue
        const res = await inquirer.prompt([
          {
            type: 'confirm'.name: 'isContinue'.message: 'The current folder is not empty. Do you want to continue creating the project here? '.default: false,}]); isContinue = res.isContinue;if(! isContinue) {return false; }}// 2. Determine whether to enable forcible installation
      // Empty the folder for creation
      if (isContinue || this.force) {
        const { isDelete } = await inquirer.prompt([
          {
            type: 'confirm'.name: 'isDelete'.message: 'Do you want to clear the files in the current directory? '.default: false,}]);if (isDelete) {
          // Clear the current directoryfse.emptyDirSync(localPath); }}}// 3. Select create project or component
    // 4. Get basic information about the project
    return this.getInfo();
  }

  / * * *@description: Select create project or component to get basic information about the project return Object *@param {*}
   * @return {*} Basic project information */
  async getInfo() {
    const info = {};
    // Select create project or component;
    const { type } = await inquirer.prompt({
      type: 'list'.message: 'Please select an initialization type'.name: 'type'.default: TYPE_PROJECT,
      choices: [{name: 'the project'.value: TYPE_PROJECT,
        },
        {
          name: 'components'.value: TYPE_COMPONENT,
        },
      ],
    });
    log.verbose('type', type);
    // Get basic information about the project;
    if (type === TYPE_COMPONENT) {
    }
    if (type === TYPE_PROJECT) {
      const o = await inquirer.prompt([
        {
          type: 'input'.message: 'Please enter project name'.name: 'project'.validate: (a) = > {
            const reg =
              /^[a-zA-Z]+([-][a-zA-Z0-9]|[_][a-zA-Z0-9]|[a-zA-Z0-9])*$/;
            if (reg.test(a)) {
              return true;
            }
            return 'Must start with a letter, end with a number or a letter. Only characters allowed are - and _'.; }, {},type: 'input'.message: 'Please enter the project version number'.name: 'version'.default: '1.0.0'.validate: (a) = > {
            return!!!!! semver.valid(a) ||'Please enter a valid version number';
          },
          filter: (a) = > {
            if(!!!!! semver.valid(a)) {return semver.valid(a);
            }
            returna; }},]);console.log('๐Ÿš€๐Ÿš€ ~ InitCommand ~ o', o);
    }
    return info;
  }

  / * * *@description: Checks whether the current directory is empty *@param {*}
   * @return { Boolean }  False is not empty */
  isDirEmpty(localPath) {
    // Read all files in the current directory
    let fileList = fs.readdirSync(localPath);
    // Filter out unaffected file directories (whitelist)
    fileList = fileList.filter(
      (file) = >! file.startsWith('. ') && ['node_modules'].indexOf(file) < 0,);// No directory or number of files is 0 returns true
    return! fileList || fileList.length ===0; }}/ * * *@description: Returns an instance of InitCommand *@param {*} Argv: projectName projectName, options of the command, commander instance *@return {*}* /
function init(argv) {
  return new InitCommand(argv);
}

module.exports = init;
module.exports.InitCommand = InitCommand;
Copy the code