Home > Web Front-end > JS Tutorial > Why is scaffolding needed? Detailed explanation of the steps to build scaffolding in node

Why is scaffolding needed? Detailed explanation of the steps to build scaffolding in node

青灯夜游
Release: 2023-04-10 19:06:06
forward
1413 people have browsed it

Why is scaffolding needed? How to build scaffolding? The following article introduces the steps for building scaffolding on node. I hope it will be helpful to everyone!

Why is scaffolding needed? Detailed explanation of the steps to build scaffolding in node

1 Why scaffolding is needed

  • Dynamically generate project structure and configuration files based on interaction.
  • Users download different templates through command interaction
  • Render custom project templates through the template engine
  • When the template changes, you only need to update the template, and the user does not need to update the scaffolding [Related tutorial recommendations: nodejs video tutorial, Programming teaching]

2 Construction steps

  • Create a new mycli folder (the file name can be customized), create a new bin file below, create a new bin file index.js, this index.js is the entry file, index.js is added to the header of the file #!/usr/bin/env nodecode

  • Generate the package.json file. At this time, there will be a bin configuration object. The key value is the global scaffolding name, and the value is the index.js# of the entry file bin file. ##path.

  •     npm init -y
        npm install
    Copy after login

  • #Link the scaffolding global command to the global one. If the terminal prints

    mycli, the link is successful.

    //命令可以将一个任意位置的npm包链接到全局执行环境,从而在任意位置使用命令行都可以直接运行该npm包。
    npm link
    Copy after login

  • Installation dependencies

  •   npm install commander inquirer@8.2.5 download-git-repo chalk@4.1.2 ora@5.4.1 figlet handlebars
    Copy after login
  • commander: Command line tool, with which we can read Take the command line command and know what the user wants to do
  • inquirer: An interactive command line tool that provides users with a beautiful interface and a way to ask questions
  • download-git-repo: Download the remote template tool, responsible for downloading the template project of the remote warehouse
  • chalk: Color plug-in, used to modify the command line output style, The info and error logs are distinguished by color, which is clear and intuitive
  • ora: Used to display the loading effect, similar to the loading effect of the front-end page, for time-consuming operations such as downloading templates. With the loading effect, the user can be prompted that it is in progress, please wait patiently
  • figlet: Hollow font style
Note: The code below is placed in the bin file

index.jsDebugging

2.1 Overview of commander.js

commander.js is a tool used to build node’s command line program so that Ability to run node scripts on the global command line using custom instructions. Originally, we could only run the script through node xxx.js in the root directory of the file where the script is located. After building the command line program through commander, we can directly run it in any directory, such as the desktop, such as the user directory. Enter the custom command to run the script directly, which is easier.

#!/usr/bin/env node
//就是解决了不同的用户node路径不同的问题,可以让系统动态的去查找node来执行你的脚本文件。
//node.js内置了对命令行操作的支持,在 package.json 中的 bin 字段可以定义命令名和关联的执行文件。
const program = require("commander")
program.version('1.1.0')

function getFramwork (val) {
  console.log(val);
}

const myhelp = function (program) {
  program.option(&#39;-f --framwork <framwork>&#39;, &#39;设置框架&#39;, getFramwork)
}

const createProgress = function (program) {
  program.command(&#39;create <progress> [other...]&#39;)
    .alias(&#39;crt&#39;)
    .description(&#39;创建项目&#39;)
    .action((progress, arg) => {
      console.log(progress, arg);
    })
}
myhelp(program);
createProgress(program);
program.parse(process.argv)
// 补充
.parse()
// 作用就是解析,参数就是要解析的字符串,一般使用时参数就是用process.argv,就是用户输入参数
Copy after login

Execute the global command

mycli to output all commands~~

Why is scaffolding needed? Detailed explanation of the steps to build scaffolding in node##2.2 download-git-repo

    download
  • (repository, destination, options, callback)
  • repository
  • :Download address
  • destination
  • : Download path
  • options
  • : Configuration item {clone: ​​true}
  • callback
  • : Callback after download
    #!/usr/bin/env node
    const download = require(&#39;download-git-repo&#39;);
    download(&#39;direct:https://gitlab.com/flippidippi/download-git-repo-fixture.git&#39;, "xxx", { clone: true }, (err) => {
      console.log(err ? &#39;Error&#39; : &#39;Success&#39;)
    })
    Copy after login
  • Execute
mycli

and you will see a xxx file generated under the file

##2.3 Inquirer (command interaction)Why is scaffolding needed? Detailed explanation of the steps to build scaffolding in node

inquirer

is a collection of commonly used interactive terminal user interfaces. To put it simply,

inquirer is a library that allows us to easily perform various terminal interactive behaviors. inquirer mainly provides three methods to facilitate us to register questions

prompt(questions) => promise
    This method is the core method of terminal interaction. Run The prompt method tells the terminal to start an interactive command interface. - The prompt method needs to pass in an array of
  • questions. The questions array contains each question in the form of objects. The meaning of the specific structure fields of question will be introduced later. - The return value of the prompt method is a promise object, and the return value received by promise.then is the answers object. The answers object contains the data results of the answers to all previous questions.
    #!/usr/bin/env node
    const inquirer = require("inquirer")
    function getUsername() {
      return inquirer
        .prompt([
          {
            type: "input",
            name: "progress",
            message: "请输入项目名称",
            default: "progress",
            filter(input) {
              return input.trim()
            },
            validate(input) {
              return input.length > 0
            },
          },
        ])
        .then((answer) => {
          console.log(answer)
        })
    }
    function getFramework() {
      return inquirer
        .prompt([
          {
            type: "list",
            name: "framework",
            choices: [
              "express",
              new inquirer.Separator(),
              "koa",
              new inquirer.Separator(),
              "egg",
            ],
            message: "请选择你所使用的框架",
          },
        ])
        .then((answer) => {
          console.log(answer)
        })
    }
    
    function getSelect() {
      return inquirer
        .prompt([
          {
            type: "checkbox",
            name: "userndasde",
            choices: [
              { name: "pr", disabled: true },
              { name: "oa", checked: true },
              "gg",
            ],
            message: "需要的验证格式",
            // default: ["oa"],
          },
        ])
        .then((answer) => {
          console.log(answer)
        })
    }
    async function init() {
      await getSelect()
      await getUsername()
      await getFramework()
    }
    init()
    Copy after login
    2.4 ora and chalk (beautification)
After the user enters the answer, the template starts to be downloaded. At this time,

ora

is used to prompt the user that the download is in progress.

Note: Note that different versions have different introduction methods. Here we use ora

(version 5.4.1),

chalk (version 4.1.2)

const ora = require("ora")
const chalk = require("chalk")
const spinner = ora("Loading unicorns").start()
spinner.text = chalk.blue("下载中~~~~~~")
setTimeout(() => {
  spinner.succeed(chalk.red("下载成功!"))
  spinner.fail("下载失败!")
  spinner.warn("警告!")
}, 2000)
Copy after login

2.5 figlet(镂空文字)

镂空文字调试器地址:地址

figlet旨在完全实现JavaScript中的FIGfont规范。它可以在浏览器和Node.js中工作。

用法

figlet.text( description,{options},callback(err,data){}) 这个是异步的会被

参数

  • description:需要格式化的字符串

  • options:参数配置

    • Font:字体,Default value:Standard
    • horizontalLayout:布局,Default value:default; Values:{default,full,fitted};
    • verticalLayout:垂直布局, Default value:default; Values:{defalut,full,fitted,controlled smushing,universal smushing};
    • Width:宽度;
    • whitespaceBreak:换行(Boolean); Default value:false
  • callback(err,data):回调

const figlet = require("figlet")
const chalk = require("chalk")
//简单函数
function handleAsync(params) {
  const JAVASCRIPT = figlet.textSync(
    "NODEJS",
    {
      font: "big",
      horizontalLayout: "fitted",
      verticalLayout: "controlled smushing",
      width: 600,
      whitespaceBreak: true,
    },
    function (err, data) {
      if (err) {
        console.log("Something went wrong...")
        console.dir(err)
        return
      }
      console.log(data)
    }
  )

  console.log(chalk.blue.bold(JAVASCRIPT))
}
handleAsync()
Copy after login

Why is scaffolding needed? Detailed explanation of the steps to build scaffolding in node

总结

创建一个完整的脚手架

目录结构:

  • bin/index.js
#!/usr/bin/env node
console.log("adas");
require("../lib/commander/index.js")
Copy after login
  • lib/commonder/index.js
const program = require("commander")
const init = require(&#39;../inquirer/index&#39;);
const downloadFun = require("../core/download.js");
program.version(&#39;1.1.0&#39;)
function getFramwork (val) {
  console.log(val);
}
const myhelp = function (program) {
  program.option(&#39;-f --framwork <framork> [other...]&#39;, &#39;设置框架&#39;, getFramwork)
}
const createProgress = function (program) {
  program.command(&#39;create <progress> [other...]&#39;)
    .alias(&#39;crt&#39;)
    .description(&#39;创建项目&#39;)
    .action((progress, arg) => {
      init();
    })
}
const downloadUrl = function (program) {
  program.command(&#39;download <url> [...other]&#39;)
    .description(&#39;下载内容&#39;)
    .action((url, ...args) => {
      console.log(args);
      downloadFun(url, args[1].args[1])
    })
}
myhelp(program);
downloadUrl(program);
createProgress(program)
program.parse(process.argv)
Copy after login
  • lib/core/action.js (package.json重写)
const fs = require(&#39;fs&#39;);
const path = require("path");
const handlebars = require("handlebars");
  function modifyPackageJson (options) {
    let downloadPath = options.projectName;
    const packagePath = path.join(downloadPath, &#39;package.json&#39;);
    console.log(packagePath, "packagePath");
    
    //判断是否存在package.json文件
    if (fs.existsSync(packagePath)) {
      let content = fs.readFileSync(packagePath).toString();
      
      //判断是否选择了eslint
      if (options.isIslint) {
        let targetContent = JSON.parse(content);
        content = JSON.stringify(targetContent);
        targetContent.dependencies.eslint = "^1.0.0";
        console.log("content", content);
      }
      
      //写入模板
      const template = handlebars.compile(content);
      const param = { name: options.projectName };
      const result = template(param);
      
      //重新写入package.json文件
      fs.writeFileSync(packagePath, result);
      console.log(&#39;modify package.json complate&#39;);
    } else {
      throw new Error(&#39;no package.json&#39;);
    }
  }
  module.exports = modifyPackageJson
Copy after login
  • lib/core/download.js
  const download = require(&#39;download-git-repo&#39;);
  const ora = require("ora");
  const chalk = require("chalk");
  const figlet = require("figlet");
  const modifyPackageJson = require("./action")
  
  function handleAsync (params) {
    const JAVASCRIPT = figlet.textSync(&#39;JAVASCRIPT&#39;, {
      font: &#39;big&#39;,
      horizontalLayout: &#39;fitted&#39;,
      verticalLayout: &#39;controlled smushing&#39;,
      width: 600,
      whitespaceBreak: true
    }, function (err, data) {
      if (err) {
        console.log(&#39;Something went wrong...&#39;);
        console.dir(err);
        return;
      }
      console.log(data);
    });
    console.log(chalk.blue.bold(JAVASCRIPT));
  }
  
  const downloadFun = (url, option) => {
    const spinner = ora("Loading unicorns").start()
    spinner.text = chalk.blue("下载中");
    
    download(url, option.projectName, { clone: true }, function (err) {
      if (err) {
        spinner.fail("下载失败!");
        handleAsync()
      } else {
        spinner.succeed(chalk.red("下载成功!"))
        console.log(chalk.blue(`cd ${option.projectName}`))
        console.log(chalk.red("npm install"))
        console.log(chalk.yellow(`npm run dev`))
        modifyPackageJson(option)
        handleAsync()
      }
    })
  }
  module.exports = downloadFun;
Copy after login
  • inquire/index.js 注意frameworkConfig写自己的gitlab仓库地址
  const inquirer = require("inquirer");
  const downloadFun = require("../core/download.js");
  const frameworkConfig = {
    front: "https://gitlab.com/flippidippi/download-git-repo-fixture.git",
    manager: "https://gitlab.com/flippidippi/download-git-repo-fixture.git"
  }
  const config = {};
  
  function getFramework () {
    return inquirer.prompt([
      {
        type: &#39;list&#39;,
        name: &#39;framework&#39;,
        choices: ["front", "manager"],
        message: "请选择你所使用的框架"
      }
    ]).then((answer) => {
      return answer.framework;
    })
  }
  
  function getProjectName () {
    return inquirer.prompt([
      {
        type: &#39;input&#39;,
        name: &#39;projectName&#39;,
        message: &#39;项目名称&#39;,
        filter (input) {
          return input.trim();
        },
      }
    ]).then((answer) => {
      console.log(answer, "FDsfs");
      return answer.projectName;
    })
  }
  
  function getIsEslint () {
    return inquirer.prompt([
      {
        type: &#39;confirm&#39;,
        name: &#39;isIslint&#39;,
        message: &#39;是否使用eslint校验格式?&#39;
      }
    ]).then((answer) => {
      return answer.isIslint;
    })
  }
  
  async function init () {
    config.projectName = await getProjectName();
    config.framework = await getFramework();
    config.isIslint = await getIsEslint();
    let url = config.framework == "front" ? frameworkConfig.front : frameworkConfig.manager;
    downloadFun("direct:" + url, config);
  }
  module.exports = init;
Copy after login

更多node相关知识,请访问:nodejs 教程

The above is the detailed content of Why is scaffolding needed? Detailed explanation of the steps to build scaffolding in node. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:juejin.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template