비계는 왜 필요한가? 노드에 스캐폴딩을 구축하는 단계에 대한 자세한 설명

青灯夜游
풀어 주다: 2023-04-10 19:06:06
앞으로
1396명이 탐색했습니다.

비계는 왜 필요한가요? 비계를 만드는 방법? 다음 기사에서는 노드에서 스캐폴딩을 구축하는 단계를 소개합니다. 모든 사람에게 도움이 되기를 바랍니다.

비계는 왜 필요한가? 노드에 스캐폴딩을 구축하는 단계에 대한 자세한 설명

1 스캐폴딩이 필요한 이유

  • 상호 작용을 기반으로 프로젝트 구조 및 구성 파일을 동적으로 생성합니다.
  • 사용자는 명령 상호 작용을 통해 다양한 템플릿을 다운로드합니다.
  • 사용자 정의된 프로젝트 템플릿은 템플릿 엔진에 의해 렌더링됩니다.
  • 템플릿이 변경되면 템플릿만 업데이트하면 되고 사용자는 스캐폴딩을 업데이트할 필요가 없습니다. [관련 튜토리얼 권장 사항: nodejs 비디오 튜토리얼, 프로그래밍 교육

2 구성 단계

  • mycli 폴더를 만들고(파일 이름은 사용자 정의 가능) 새 bin 파일 아래에 index.js라는 새 bin 파일을 만듭니다. 이 index.js가 항목 파일입니다. 를 <code>index.js 파일의 헤더에 추가합니다. #!/usr/bin/env node 코드 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即可输出所有命令~~

비계는 왜 필요한가? 노드에 스캐폴딩을 구축하는 단계에 대한 자세한 설명

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文件

비계는 왜 필요한가? 노드에 스캐폴딩을 구축하는 단계에 대한 자세한 설명

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

🎜🎜는 package.json을 생성합니다. 이때, bin 구성 객체가 있을 것입니다. 키 값은 전역 스캐폴딩 이름이고, 값은 항목 파일 bin 파일의 index.js 경로입니다. 🎜🎜🎜
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)
로그인 후 복사
로그인 후 복사
🎜🎜🎜🎜 🎜scaffolding 전역 명령을 전역 명령에 연결합니다. 터미널에 mycli가 인쇄되면 연결이 성공한 것입니다. 🎜
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()
로그인 후 복사
로그인 후 복사
🎜🎜🎜설치 종속성🎜🎜🎜
#!/usr/bin/env node
console.log("adas");
require("../lib/commander/index.js")
로그인 후 복사
로그인 후 복사
🎜🎜commander: 명령줄 도구로, 명령줄 명령을 읽고 사용자가 무엇을 원하는지 알 수 있습니다🎜🎜 inquirer</ code>: 사용자에게 아름다운 인터페이스와 질문을 제기할 수 있는 방법을 제공하는 대화형 명령줄 도구🎜🎜<code>download-git-repo: 원격 창고 다운로드를 담당하는 원격 템플릿 도구 다운로드 템플릿 프로젝트 🎜🎜 분필: 명령줄 출력 스타일을 수정하고, 명확하고 직관적인 색상을 통해 정보와 오류 로그를 구별하는 데 사용되는 색상 플러그인 🎜🎜ora: 로딩 표시에 사용 효과는 프런트 엔드 페이지의 로딩 효과와 유사합니다. 템플릿 다운로드와 같이 시간이 많이 걸리는 작업의 경우 로딩 효과가 사용자에게 진행 중임을 알려줄 수 있습니다. 인내심을 갖고 기다려 주세요🎜🎜figlet : 빈 글꼴 스타일🎜 🎜

참고: 아래 코드는 디버깅을 위해 bin 파일 index.js에 배치됩니다.

2.1 Commander.js 개요

🎜commander.js는 노드의 명령줄 프로그램을 빌드하는 데 사용되는 도구로, 사용자 정의 지침을 사용하여 노드 스크립트를 실행할 수 있습니다. 글로벌 명령줄. 원래는 스크립트가 위치한 파일의 루트 디렉터리에 있는 node xxx.js를 통해서만 스크립트를 실행할 수 있었습니다. Commander를 통해 명령줄 프로그램을 빌드한 후에는 어떤 디렉터리에서든 실행할 수 있습니다. 데스크탑과 같은 사용자 디렉토리와 같은 사용자 정의 명령을 직접 입력하면 스크립트를 직접 실행하는 것이 더 쉽습니다. 🎜
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)
로그인 후 복사
로그인 후 복사
🎜전역 명령 mycli를 실행하면 모든 명령이 출력됩니다~~🎜🎜비계는 왜 필요한가? 노드에 스캐폴딩을 구축하는 단계에 대한 자세한 설명🎜

2.2 다운로드-git-repo

🎜🎜다운로드</code >(저장소, 대상, 옵션, 콜백)🎜🎜<code>저장소: 다운로드 주소🎜🎜대상: 다운로드 경로🎜🎜옵션: 구성 항목 { clone: ​​​​true}🎜🎜callback: 다운로드 후 콜백🎜🎜
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
로그인 후 복사
로그인 후 복사
🎜 mycli를 실행하면 xxx 파일이 생성된 것을 볼 수 있습니다. 파일🎜 🎜비계는 왜 필요한가? 노드에 스캐폴딩을 구축하는 단계에 대한 자세한 설명🎜< h4 data -id="heading-5">2.3 Inquirer(명령 상호작용)🎜🎜inquirer🎜는 일반적으로 사용되는 대화형 터미널 사용자 인터페이스 모음입니다. 간단히 말해서 🎜inquirer🎜는 다양한 터미널 대화형 동작을 쉽게 수행할 수 있게 해주는 라이브러리입니다. 🎜🎜inquirer는 질문 등록을 용이하게 하기 위해 주로 세 가지 방법을 제공합니다.🎜🎜🎜🎜prompt(questions) => promise🎜 이 방법은 터미널 상호 작용의 핵심 방법입니다. 프롬프트 방법을 실행하면 터미널에 대화형 명령 인터페이스가 시작됩니다. - 프롬프트 메소드는 🎜questions🎜 배열을 전달해야 합니다. 질문 배열에는 각 질문이 개체 형태로 포함됩니다. 질문의 특정 구조 필드의 의미는 나중에 소개됩니다. - 프롬프트 메소드의 반환 값은 promise 개체이고 promise.then에서 받은 반환 값은 🎜answers🎜 개체입니다. Answers 개체에는 이전 질문에 대한 답변의 데이터 결과가 포함됩니다. 🎜🎜
  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 및 chalk(미화)

🎜사용자가 답변을 입력하면 템플릿 다운로드가 시작됩니다. 이때 ora<를 사용하세요. /code>를 입력하면 사용자에게 다운로드 중이라는 메시지가 표시됩니다. 🎜🎜참고: 버전마다 소개 방법이 다릅니다. 여기서는 <code>ora(버전 5.4.1), chalk(버전 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()
로그인 후 복사
로그인 후 복사

비계는 왜 필요한가? 노드에 스캐폴딩을 구축하는 단계에 대한 자세한 설명

总结

创建一个完整的脚手架

目录结构:

  • 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 教程

위 내용은 비계는 왜 필요한가? 노드에 스캐폴딩을 구축하는 단계에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:juejin.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿