Heim  >  Artikel  >  Web-Frontend  >  Warum wird ein Gerüst benötigt? Detaillierte Erläuterung der Schritte zum Bau eines Gerüsts im Knoten

Warum wird ein Gerüst benötigt? Detaillierte Erläuterung der Schritte zum Bau eines Gerüsts im Knoten

青灯夜游
青灯夜游nach vorne
2023-04-10 19:06:061389Durchsuche

Warum wird ein Gerüst benötigt? Wie baut man ein Gerüst? Der folgende Artikel stellt die Schritte zum Bau eines Gerüsts auf dem Knoten vor. Ich hoffe, er ist für alle hilfreich!

Warum wird ein Gerüst benötigt? Detaillierte Erläuterung der Schritte zum Bau eines Gerüsts im Knoten

1 Warum Gerüste benötigt werden

  • Generieren Sie dynamisch Projektstruktur- und Konfigurationsdateien basierend auf Interaktion.
  • Benutzer laden verschiedene Vorlagen durch Befehlsinteraktion herunter
  • Benutzerdefinierte Projektvorlagen werden von der Vorlagen-Engine gerendert
  • Wenn sich die Vorlage ändert, müssen Sie nur die Vorlage aktualisieren, und der Benutzer muss das Gerüst nicht aktualisieren [Empfehlungen für entsprechende Tutorials: nodejs-Video-Tutorial, Programmierunterricht]

2 Konstruktionsschritte

  • Erstellen Sie einen neuen mycli-Ordner (der Dateiname kann angepasst werden) und erstellen Sie einen neuen bin-Datei unten, Erstellen Sie eine neue bin-Datei mit dem Namen index.js. Diese index.js ist die Eintragsdatei zum Header der Datei <code>index.js #!/usr/bin/env Code mycli文件夹(可自定义文件名),下方新建bin文件,bin文件新建index.js,这个index.js就是入口文件,index.js文件头部加入#!/usr/bin/env node代码

  • 生成package.json文件,此时会有个bin配置对象,key值即为全局脚手架名称,value是入口文件bin文件的index.js路径。

    npm init -y
    npm install

  • 将脚手架全局命令链接到全局,终端打印mycli即链接成功。

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

  npm install commander inquirer@8.2.5 download-git-repo chalk@4.1.2 ora@5.4.1 figlet handlebars
  • commander:命令行工具,有了它我们就可以读取命令行命令,知道用户想要做什么了
  • inquirer: 交互式命令行工具,给用户提供一个漂亮的界面和提出问题流的方式
  • download-git-repo:下载远程模板工具,负责下载远程仓库的模板项目
  • chalk:颜色插件,用来修改命令行输出样式,通过颜色区分 info、error 日志,清晰直观
  • ora:用于显示加载中的效果,类似于前端页面的 loading 效果,像下载模板这种耗时的操作,有了 loading 效果可以提示用户正在进行中,请耐心等待
  • figlet :镂空字体样式

注意:下方代码都放在bin文件index.js进行调试

2.1 commander.js概述

commander.js是一个工具,用来构建node的命令行程序,使得能够使用自定义指令在全局命令行运行node脚本。本来我们只能在脚本所在文件的根目录里通过node xxx.js运行脚本,通过commander构建命令行程序后,就能在任意一个目录里,比如桌面,比如用户目录,直接输入自定义的那个指令,就能直接运行脚本,更加简便。

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

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,就是用户输入参数

执行全局命令mycli即可输出所有命令~~

Warum wird ein Gerüst benötigt? Detaillierte Erläuterung der Schritte zum Bau eines Gerüsts im Knoten

2.2 download-git-repo

  • download(repository, destination, options, callback)
  • repository:下载地址
  • destination:下载路径
  • options:配置项 {clone:true}
  • callback:下载后的回调
#!/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;)
})

执行mycli即可看到文件下生成一个xxx文件

Warum wird ein Gerüst benötigt? Detaillierte Erläuterung der Schritte zum Bau eines Gerüsts im Knoten

2.3 Inquirer(命令交互)

inquirer 是一个常用的交互式终端用户界面集合。 简单来说 inquirer 是可以让我们很方便的做各种终端交互行为的一个库。

inquirer 主要提供了三个方法方便我们注册问题

  • prompt(questions) => promise该方法就是 终端交互的核心方法,运行 prompt 方法即告诉终端启动 交互式命令界面。 - prompt 方法需要传入一个 questions 数组, questions 数组包含对象形式的各个 question. question 的具体结构字段含义在后文介绍。 - prompt 方法的返回值是一个 promise 对象,promise.then 接收的返回值是 answers 对象,answers 对象包含前面所有问题回答的数据结果。
#!/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()

2.4 ora and chalk(美化)

在用户输入答案之后,开始下载模板,这时候使用 ora 来提示用户正在下载中。

注意:注意版本不同引入方式不同,这里用ora(版本5.4.1) ,chalk

🎜🎜 generiert den package.json Zu diesem Zeitpunkt gibt es ein Bin-Konfigurationsobjekt, und der Wert ist der index.js-Pfad der Bin-Datei. 🎜🎜🎜
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)
🎜🎜🎜🎜 🎜Verknüpfen Sie den globalen Scaffolding-Befehl mit dem globalen Befehl. Wenn das Terminal mycli ausgibt, ist die Verknüpfung erfolgreich. 🎜
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()
🎜🎜🎜Installationsabhängigkeiten🎜🎜🎜
#!/usr/bin/env node
console.log("adas");
require("../lib/commander/index.js")
🎜🎜commander: Befehlszeilentool, mit dem wir Befehlszeilenbefehle lesen und wissen können, was der Benutzer tun möchte🎜🎜inquester Code>: Ein interaktives Befehlszeilentool, das Benutzern eine schöne Oberfläche und die Möglichkeit bietet, Fragen zu stellen🎜🎜<code>download-git-repo: Remote-Vorlagentool herunterladen, verantwortlich für das Herunterladen von Remote-Warehouse-Vorlagenprojekten 🎜🎜 chalk: Farb-Plug-in, wird verwendet, um den Befehlszeilenausgabestil zu ändern, Informationen und Fehlerprotokolle durch Farbe zu unterscheiden, klar und intuitiv 🎜🎜ora: wird verwendet, um den Ladevorgang anzuzeigen Der Effekt ähnelt dem Ladeeffekt der Front-End-Seite. Bei zeitaufwändigen Vorgängen wie dem Herunterladen von Vorlagen kann der Ladeeffekt den Benutzer daran erinnern, dass er gerade ausgeführt wird🎜🎜figlet : hohler Schriftstil🎜 🎜

Hinweis: Der folgende Code wird zum Debuggen in die Bin-Datei index.js eingefügt

2.1 Überblick über commander.js

🎜commander.js ist ein Tool zum Erstellen des Befehlszeilenprogramms des Knotens, das die Verwendung benutzerdefinierter Anweisungen zum Ausführen von Knotenskripten ermöglicht die globale Befehlszeile. Ursprünglich konnten wir das Skript nur über node xxx.js im Stammverzeichnis der Datei ausführen, in der sich das Skript befindet. Nachdem wir das Befehlszeilenprogramm über Commander erstellt haben, können wir es in jedem Verzeichnis ausführen. B. auf dem Desktop, z. B. im Benutzerverzeichnis. Geben Sie einfach den benutzerdefinierten Befehl direkt ein, um das Skript direkt auszuführen, was einfacher ist. 🎜
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)
🎜Führen Sie den globalen Befehl mycli aus, um alle Befehle auszugeben~~🎜🎜Warum wird ein Gerüst benötigt? Detaillierte Erläuterung der Schritte zum Bau eines Gerüsts im Knoten🎜

2.2 download-git-repo

🎜🎜download(Repository, Ziel, Optionen, Rückruf)🎜🎜repository: Download-Adresse🎜🎜destination: Download-Pfad🎜🎜options: Konfigurationselement { clone: ​​​​true}🎜🎜callback: callback after download🎜🎜
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
🎜Führen Sie mycli aus und Sie werden eine xxx-Datei sehen, die unter generiert wird Datei🎜 🎜Warum wird ein Gerüst benötigt? Detaillierte Erläuterung der Schritte zum Bau eines Gerüsts im Knoten🎜2.3 Inquirer (Befehlsinteraktion)🎜🎜inquirer🎜 ist eine Sammlung häufig verwendeter interaktiver Terminal-Benutzeroberflächen. Einfach ausgedrückt ist 🎜inquirer🎜 eine Bibliothek, mit der wir auf einfache Weise verschiedene interaktive Terminalverhaltensweisen ausführen können. 🎜🎜inquirer bietet hauptsächlich drei Methoden, um uns das Registrieren von Fragen zu erleichtern. 🎜🎜🎜🎜prompt(fragen) => versprechen🎜Diese Methode ist die Kernmethode der Terminalinteraktion und weist das Terminal an, die interaktive Befehlsschnittstelle zu starten. - Die Eingabeaufforderungsmethode muss ein Array „Fragen“ übergeben. Das Array „Fragen“ enthält jede Frage in Form von Objekten. Die Bedeutung der spezifischen Strukturfelder der Frage wird später erläutert. - Der Rückgabewert der Prompt-Methode ist ein Promise-Objekt, und der von Promise.then empfangene Rückgabewert ist das 🎜answers🎜-Objekt. Das Answers-Objekt enthält die Datenergebnisse der Antworten auf alle vorherigen Fragen. 🎜🎜
  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;

2.4 ora und Kreide (Verschönerung)

🎜Nachdem der Benutzer die Antwort eingegeben hat, beginnt der Download der Vorlage. Verwenden Sie zu diesem Zeitpunkt ora zur Aufforderung „Der Benutzer lädt herunter“. 🎜🎜Hinweis: Beachten Sie, dass verschiedene Versionen unterschiedliche Einführungsmethoden haben. Hier verwenden wir <code>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)

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()

Warum wird ein Gerüst benötigt? Detaillierte Erläuterung der Schritte zum Bau eines Gerüsts im Knoten

总结

创建一个完整的脚手架

目录结构:

  • bin/index.js
#!/usr/bin/env node
console.log("adas");
require("../lib/commander/index.js")
  • 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)
  • 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
  • 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;
  • 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;

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

Das obige ist der detaillierte Inhalt vonWarum wird ein Gerüst benötigt? Detaillierte Erläuterung der Schritte zum Bau eines Gerüsts im Knoten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.cn. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen