欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

教你用NodeJs構(gòu)建屬于自己的前端腳手工具

 更新時間:2022年05月19日 11:05:19   作者:蝸牛前端  
對于腳手架我們可能天天都在接觸,像npm包管理工具,vue-cli,webpack…,但是這些腳手架是怎么做出來的,我們自己能不能做一個出來玩玩,下面這篇文章主要給大家介紹了關(guān)于如何利用NodeJs構(gòu)建屬于自己的前端腳手工具的相關(guān)資料,需要的朋友可以參考下

一.前言

在日常開發(fā)中,我們經(jīng)常會用到各種腳手架工具,如常用的vue和react腳手架工具:vue-cli、Create React App。只需要執(zhí)行內(nèi)置命令和選擇內(nèi)置條件就可以生成對應(yīng)的項目模板。極大的提高了我們開發(fā)開發(fā)效率,所以我們能不能根據(jù)自己的日常業(yè)務(wù)構(gòu)建屬于自己的一套腳手架工具呢,答案是可以的。接下來步入本文章的主題

二.技術(shù)棧

  • commander:^9.2.0 :完整的 node.js命令行解決方案
  • execa: ^6.1.0:執(zhí)行shel命令
  • inquirer: ^8.2.4:交互式命令行用戶界面,在命令工具中可提供交互
  • ejs: ^3.1.8:嵌入式JavaScript模板
  • chalk: ^5.0.1:設(shè)置終端字符串樣式
  • mkdirp:^1.0.4:遞歸mkdir

三.特別說明

在開始之前,需要了解nodejs基礎(chǔ)知識,常用shell執(zhí)行命令,和javascript基礎(chǔ)知識!?。?本文將從零到一完整講解腳手架開發(fā)過程,以Vite + React18.0為模板案例,不會完整開發(fā)類似vue-cli 的所有功能!你可按照此文優(yōu)化完善自己的腳手架代碼。

四.構(gòu)建項目

現(xiàn)在正式開始構(gòu)建腳手架項目,可根據(jù)自己熟悉方式創(chuàng)建,直接創(chuàng)建項目文件夾

# 創(chuàng)建項目文件夾 名稱為 my-cli 可自定義
mkdir my-cli
# 初始化 npm 根據(jù)自己的需求填寫對應(yīng)信息,也可以直接默認
npm init

五.安裝依賴

yarn add commander execa inquirer chalk mkdirp
# or npm 安裝 
npm install commander execa inquirer chalk mkdirp

六.目錄說明

完整目錄,如下所示,可根據(jù)目錄設(shè)計添加對應(yīng)文件。

my-cli # 項目名稱
└── bin # 主目錄
    ├── commands # 命令文件
    │   ├── options # 命令所有選項
    │   │   ├── create.js # 創(chuàng)建命令
    │   │   ├── help.js # 幫助命令
    │   │   ├── help.js # 導出所有命令文件
    │   ├── index.js # 導出command命令方法
    ├── inquirers # 交互式命令文件
    │   ├── options # 交互式命令所有選項
    │   │   ├── common.js # 公共交互式命令
    │   │   ├── react.js # react相關(guān)命令
    │   │   ├── index.js # 導出所有交互式命令文件
    │   ├── index.js # 導出command命令方法
    ├── templates # 所有模板文件
    │   ├── react # react相關(guān)模板
    │   ├── vue # vue相關(guān)模板
    ├── utils # 工具類
    │   ├── index.js # 工具類處理函數(shù)
    ├── index.js # 入口文件

完整代碼:my-cli

七.實戰(zhàn)

在開始前,我們需要修改package.json文件,增加"bin": "./bin/index.js":發(fā)布到npm設(shè)置執(zhí)行入口文件; "type": "module":表示允許執(zhí)行export、import操作;"start": "node ./bin/index.js":做本地測試使用,表示執(zhí)行腳手架入口文件

{
  + "bin": "./bin/index.js",
  + "type": "module",
  "scripts": {
    - "test": "echo \"Error: no test specified\" && exit 1",
    + "start": "node ./bin/index.js"
  }
}

(一).入口文件

首先從入口文件開始分析,需要的模塊逐步完善。目錄路徑:bin/index.js

#! /usr/bin/env node
// 引入 fs模 塊
import fs, { mkdirSync } from "fs";
// 引入 path 模塊
import path from "path";

// 引入 commands 相關(guān)命令方法
import commands from "./commands/index.js";
// 獲取用戶輸入、選擇項
let config = await command();

需要注意的是#! /usr/bin/env node 表示執(zhí)行環(huán)境為node,引入fs文件系統(tǒng)模塊,創(chuàng)建文件項目會涉及到文件相關(guān)讀取寫能力;引入path讀取文件路徑。commands執(zhí)行命令;通過let config = await command();獲取用戶輸入、選擇項;這一步涉及到commands所以接下來開始分析:bin/commands/index.js用戶輸入命令模塊

(二).命令文件

目錄路徑:bin/commands/index.js

// 引入 commander 命令
import { program } from "commander";
import chalk from "chalk";
// 導入 create創(chuàng)建命令 help幫助命令
import { create, help } from "./options/index.js";

export default async (call) => {
  return new Promise((resolve, reject) => {
    program
      .name(chalk.blue("my-cli"))
      .usage("[global options] command");
    // 版本信息
    program.version("1.0.0");
    // 幫助信息
    program.option("-F, --framework", "surport vue,react");
    // 創(chuàng)建項目命令
    create(program, (item) => {
      resolve(item);
    });
    // 幫助信息
    help(program);
    // 解析指令
    program.parse(process.argv);
  });
};

我們需要關(guān)注的是create、help分別是創(chuàng)建命令、幫助命令

(三).創(chuàng)建命令

create創(chuàng)建命令 ,文件路徑:bin/commands/options/create.js

/**
 * @description 創(chuàng)建項目指令
 * @author hu-snail 1217437592@qq.com
 */

 import inquirer from "inquirer";
 import { changeTemplate, changeVariant, inputProjectName } from "../../inquirers/options/index.js";
 import  {InvalidArgumentError} from "commander";
 import chalk from "chalk";
 import { hasTemplate, getSupportTs } from '../../utils/index.js'
 export default (program, call) => {
   program
     .command("create")
     .argument("<build-method>", "build tools", validatBuildMethod)
     .argument("[app-name]", "app name", validatAppName)
     .description("create a new project powered by my-cli")
     .option("-t, --template <value>", "create a new project by template", validatTemplate)
     .action(async (method, projectName, option) => {
       let item = {};
        // 判斷用戶是否輸入 projectName 
        if (!projectName) {
          item = await inquirer.prompt([inputProjectName(), changeTemplate(), changeVariant()]);
          // string轉(zhuǎn)為boolean
          item.supportTs = item.supportTs === 'true' ? true : false
          return call && call({ method, ...item });
        }
       // 如果用戶沒有輸入 模板參數(shù),則提供項目類型選擇 react/vue
       if (!option.template) {
         item = await getFramework(option);
				 item.supportTs = item.supportTs === 'true' ? true : false
       } else {
         item = option;
         item.supportTs = getSupportTs(item.template)
       }
       call && call({ method, projectName, ...item });
     });
 };
 
 /**
  * @description 校驗構(gòu)建方式
  * @param {String} appName 項目名稱
  * @returns appName
  */
 function validatBuildMethod(val) {
   if (val === "vite") return val;
   else
     throw new InvalidArgumentError(
       chalk.red(
         `
         "<build-method>構(gòu)建方式,只支持值為:${chalk.green(
           "vite"
         )}!請重新輸入`
       )
     );
 }
 
 /**
  * @description 校驗項目名稱
  * @param {String} appName 項目名稱
  * @returns appName
  */
 function validatAppName(appName) {
   var reg = /^[a-zA-Z][-_a-zA-Z0-9]/;
   if (!reg.test(appName)) {
     throw new InvalidArgumentError(
       chalk.red(`
       <app-name>項目名稱必須以字母開頭且長度大于2,請重新輸入!`)
     );
   }
   return appName;
 }

/**
  * @description 校驗?zāi)0?
  * @param {String} template 模板名稱
  * @returns template
  */
 function validatTemplate(template) {
   if (hasTemplate(template)) return template
   else {
    console.log(chalk.white(`error: option '-t, --template <value>' argument '${template}' is invalid`))
   }
 }
 
 async function getFramework() {
   let answer = await inquirer.prompt([changeTemplate(), changeVariant()]);
   return answer;
 }

思路分析:

上圖所示,主要分兩種情況,當用戶完整輸入和部分輸入?yún)?shù)判。

關(guān)于program詳細分析

.command("create"):表示創(chuàng)建一個名為create的命令;

.argument("<build-method>", "build tools", validatBuildMethod):其中argument:表示參數(shù)、<build-method>:表示構(gòu)建方式,必填參數(shù)、build tools:表示參數(shù)描述、validatBuildMethod:表示自定義校驗方法;

[app-name]:表示可選項,項目名稱。<>:表示必填參數(shù),[]:表示可選項

.description("create a new project powered by my-project-cli"):表示命令描述

.option("-t, --template <value>", "create a new project by template"):表示命令參數(shù)、 "-t, --template <value>":表示用戶可輸入-t--template:表示template參數(shù)、"create a new project by template":表示參數(shù)描述;

.action(async (method, projectName, option) => {}):表示命令行為事件,其中method, projectName:分別代表<build-method>構(gòu)建方式、<app-name>項目名稱,和順序關(guān)聯(lián),可根據(jù)自己需求增刪參數(shù)、option:表示參數(shù)選項、也就是"-t, --template <value>"可根據(jù)自己需求定義。

hasTemplate、getSupportTs:分別表示是否存在模板,獲取是否支持ts,在bin/utils/index.js可查看其用法

當用戶沒有完整輸入項目框架時,我們會提供changeTemplate、changeVariant、inputProjectName這個時候,就需要用到inquirer交互式命令提供選擇項。

(四).公共處理交互式命令

文件路徑:bin/inquirers/options/common.js

import chalk from "chalk";
export const changeVariant = () => {
    return {
      type: "list",
      name: "supportTs",
      choices: [
        {
          name: 'true',
        },
        {
          name: 'false',
        }
      ],
      message:
        "Support TS(default by javascript)",
    };
  };

  export const inputProjectName = () => {
    return {
      type: "input",
      name: "projectName",
      default: "vite-app-project",
      validate: function (appName) {
        var done = this.async();
        var reg = /^[a-zA-Z][-_a-zA-Z0-9]/;
        if (!reg.test(appName)) {
          done(chalk.red(`<app-name>項目名稱必須以字母開頭且長度大于2,請重新輸入!`));
        }
        done(null, true);
      },
      message:
        "Project name",
    };
  };

參數(shù)解釋,完整參數(shù)文檔inpuirer文檔

  • type:表示參數(shù)類型,提供input、number、confirm、list、rawlist、expand、checkbox、password、editor
  • name:表示參數(shù)屬性
  • choices:選擇項
  • message: 操作提示語
  • de'fa

其中changeVariant:選擇是否支持ts;inputProjectName:輸入項目名稱

(五).選擇項目框架交互式命令

文件路徑:bin/inquirers/options/template.js

/**
 * @description 創(chuàng)建項目類型選擇
 * @author hu-snail 1217437592@qq.com
 */

 export const changeTemplate = () => {
    return {
      type: "list",
      name: "template",
      choices: [
        {
          name: "react",
        },
        {
          name: "vue",
        },
      ],
      message: "Select a framework",
    };
  };

創(chuàng)建命令,到此結(jié)束,接下來分析help命令

文件路徑:bin/commands/options/help.js

/**
 * @description 幫助信息
 * @author hu-snail 1217437592@qq.com
 */
 import chalk from "chalk";

 export default (program) => {
   program.addHelpText(
     "after",
     `
       Run ${chalk.green(
         "my-cli <command> --help"
       )} for detailed usage of given command.`
   );
 };

addHelpText:表示添加幫助文字,"after":表示在之后,可選項“before”,效果圖如下

(六).導出command命令

文件目錄:bin/commands/option/index.js

/**
 * @description 導出所有命令
 * @author hu-snail 1217437592@qq.com
 */
import create from "./create.js";
import help from "./help.js";
export { create, help };

(七).導出inquirer交互式命令

文件目錄:bin/inquirers/option/index.js

/**
 * @description 導出用戶輸入選擇項
 * @author hu-snail 1217437592@qq.com
 */
 import { changeTemplate } from "./template.js";
 import { changeVariant, inputProjectName } from './common.js'
 export { changeTemplate, changeVariant, inputProjectName };

(八).工具類代碼

export function hasTemplate(template) {
    return ['vue', 'vue-ts', 'react', 'react-ts'].includes(template)
}

export function getSupportTs(template) {
  return ['vue-ts', 'react-ts'].includes(template)
}

這兩個方法在react命令中使用到,補充?。?!

八.本地測試

準備完以上代碼后,我們開始本地測試,測試目的是檢測是否能夠正確的返回我們預(yù)設(shè)的結(jié)果,可根據(jù)自己的需求定義和完善腳手架。本文只是講解demo流程?。?!

(一).完整輸入

完成輸入測試包含正確輸入、構(gòu)建方式有誤輸入、項目名稱不合規(guī)輸入

js版本完成輸入、默認為js版本

# react 版本
yarn start create vite app-test --template react
# or npm
npm run start create vite app-test--template react

效果圖:

ts版本正確輸入

# react-ts 版本
yarn start create vite app-test --template react-ts
# or npm
npm run start create vite app-test --template react-ts

效果圖:

以上結(jié)果也就是我們?nèi)肟谖募?code>bin/index.js中let config = await command();獲取的值

構(gòu)建方法輸入有誤vite1:為錯誤輸入?  只支持vite方式構(gòu)建,可根據(jù)自己的需求適配多種構(gòu)建方式

yarn start create vite1 app-test
# or npm
npm run start create vite1 app-test

效果圖:

項目名稱不合規(guī)輸入 1my-test-project:為不符合規(guī)范名稱

yarn start create vite 1my-test-project --template react
# or npm
npm run start create vite 1my-test-project --template react

效果圖:

(二).不完整輸入

包含構(gòu)建方式不輸入、名稱不輸入、項目框架方式不輸入

構(gòu)建方式不輸入會直接導致報錯,重點是名稱不輸入、項目框架方式不輸入,這時會給用戶提供選擇

項目名稱不輸入

yarn start create vite 
# or npm
npm run start create vite 

效果圖

項目名稱不輸入會提供默認值和輸入給用戶,同時完成項目框架選擇、和是否支持ts選擇。完整截圖如下:

這個結(jié)果也就是我們?nèi)肟谖募?code>bin/index.js中let config = await command();獲取的值

項目框架方式不輸入

yarn start create vite app-test 
# or npm
npm run start create vite app-test 

效果圖:

不輸入項目框架會提供選擇,同時選擇是否支持ts,完整截圖如下:

到此結(jié)束測試,你可以根據(jù)這個思路完善自己的腳手架,接下來開始模板生成

九.導入Vite + react18模板

當我們能獲取到用戶輸入選擇的值后,就可根據(jù)用戶輸入的參數(shù)生成對應(yīng)的項目模板,本文以vite+reat18為例

bin/templates目錄下創(chuàng)建React模板文件,完整目錄如下:

bin
├── templates # 所有模板文件
│   ├── react # react相關(guān)模板
│   │   ├── src # react主要文件
│   │   │   ├── App.css # App 樣式文件
│   │   │   ├── App.jsx.ejs # App 模板文件
│   │   │   ├── index.css # 首頁樣式文件
│   │   │   ├── main.js.ejs # main 模板文件
│   │   │   ├── logo.svg # react logo文件
│   │   ├── .gitignore # git忽略配置文件
│   │   ├── index.html.ejs # react首頁ejs模板
│   │   ├── package.json.ejs # package.json ejs模板
│   │   ├── tsconfig.json # ts 配置文件
│   │   ├── tsconfig.node.json # tsconfig node配置文件
│   │   ├── vite.config.js.ejs # vite.config ejs模板

具體代碼,查看完整代碼:github.com/hu-snail/my…

如果實現(xiàn)vite + vue3可參考此方法生成對應(yīng)模板

模板技巧:不需要動態(tài)改變文件,直接使用原后綴名,例如:靜態(tài)資源(圖、視頻、音等資源)、需要動態(tài)改變的文件,保留原來的后綴名,在其基礎(chǔ)上添加.ejs:例如(package.jsonpackage.json.ejs)這樣的好處是,知道原來的文件類型,方便更快的處理

十.創(chuàng)建生成模板代碼

完成模板之后,開始重點環(huán)節(jié),根據(jù)用戶輸入選擇參數(shù)動態(tài)生成項目模板,跟著我的步驟完成生成模板語法

第一步:創(chuàng)建build文件夾

bin/創(chuàng)建build文件,用于存放生成模板文件和生成配置文件,目錄如下:

bin
├── build # 生成模板文件
    ├── config.js # 模板配置文件
    ├── react.js # 生成react模板文件

第二步: config配置

因為腳手架內(nèi)置了支持tsjs,所有存在差異化,具體配置如下:

/**
 * @description js需要忽略的文件
 */
export const jsignoreFile = [
    'tsconfig.json',
    'tsconfig.node.json'
]

其中模板中的tsconfig.jsontsconfig.node.jsonts才存在,所以在js需要忽略??砂凑沾朔绞絽^(qū)分文件之間的差異化。

第三步:react生成模板

準備完以上內(nèi)容后,接下正式開始生成模板,文件路徑:bin/build/react.js

/**
 * @description 生成react模板
 * @author hu-snail 1217437592@qq.com
 */

import fs from 'fs'
import mkdirp from "mkdirp";
import { getFiles, copyFile, getCode } from '../utils/index.js'
import { jsignoreFile } from './config.js'

代碼分析:

代碼中導入了getFiles、copyFile、getCode三個方法,分別代表獲取文件、拷貝文件、獲取代碼。首先從這三個方法開始分析,文件路徑:bin/utils/index.js

1).getFiles 獲取文件

import fs from "fs";
let files = []
let dirs = []
export function getFiles(template, dir) {
const templatePath = `./bin/templates/${template}/`
const rootFiles = fs.readdirSync(templatePath, 'utf-8')
rootFiles.map(item => {
  const stat = fs.lstatSync(templatePath + item)
  const isDir = stat.isDirectory()
  if (isDir) {
    const itemDir = `${template}/${item}/`.replace(/react\//g, '')
    dirs.push(itemDir)
    getFiles(`${template}/${item}`, itemDir)
  } else files.push((dir ? dir : '') + item)
})
return {files, dirs}
}

代碼分析:

該函數(shù)提供兩個參數(shù),分別是template、dir,表示模板、目錄,同時在方法前定義了兩個變量filesdirs分別表示文件、目錄,主要作用區(qū)分文件和目錄,這樣方便用于生成目錄和創(chuàng)建文件。

  • templatePath:表示模板地址,根據(jù)傳入template動態(tài)配置
  • rootFiles:表示所有模板文件,通過fs.readdirSync讀取
  • stat:表示文件信息,通過fs.lstatSync獲取
  • isDir: 表示是否目錄,通過stat.isDirectory()判斷,如果是則遞歸該目錄下的所有文件
  • itemDir:表示層級目錄,會把上一層接口也接入

2).copyFile拷貝文件

import fs from "fs"; 
import { fileURLToPath } from "url";
const __dirname = fileURLToPath(import.meta.url);
/**
  * @description 復(fù)制文件,比如圖片/圖標靜態(tài)資源
  * @param {*} rootPath 根目錄
  * @param {*} template 模板
  * @param {*} item 靜態(tài)模板文件
  */
 export function copyFile(rootPath, template, item) {
   const fromFileName = path.resolve(
     __dirname,
     `../../templates/${template}/${item}`
   );
   const toFileName = `${rootPath}/${item}`;
   const rs = fs.createReadStream(fromFileName, {
     autoClose: true,
     encoding: "utf-8",
     highWaterMark: 64 * 1024 * 1024,
     flags: "r",
   });
   const ws = fs.createWriteStream(toFileName, {
     encoding: "utf-8",
     flags: "a",
     highWaterMark: 16 * 1024 * 1024,
     autoClose: true,
   });
   rs.on("data", (chunk) => {
     const wsFlag = ws.write(chunk, "utf-8");
     if (!wsFlag) {
       rs.pause();
     }
   });
   ws.on("drain", () => {
     // 繼續(xù)讀取
     rs.resume();
   });
 
   rs.on("end", () => {
     ws.end();
   });
 }

代碼分析:

該函數(shù)提供三個參數(shù)rootPath 、template、item,分別表示根目錄,模板名稱、靜態(tài)模板路徑。

  • fromFileName:表示讀取文件地址
  • toFileName:表示拷貝至地址
  • rs:表示讀取文件流,通過fs.createWriteStream創(chuàng)建
  • ws:表示寫入文件流,通過fs.createWriteStream創(chuàng)建

3).getCode獲取代碼

import ejs from "ejs";
import fs from "fs";
/**
  * @description 解析ejs模板
  * @param {Object} config
  * @param {String} templateName
  * @param {String} templatePath
  * @returns code
  */
 export function getCode(config, templateName, templatePath) {
   const template = fs.readFileSync(
     path.resolve(__dirname, `../../templates/${templateName}/${templatePath}`)
   );
   const code = ejs.render(template.toString(), {
     ...config,
   });
   return code;
 }

代碼分析:

該函數(shù)接受三個參數(shù)config、templateName、 templatePath:分別表示配置信息、模板名稱、模板地址

  • template:模板文件,通過fs.readFileSync讀取
  • code: 模板代碼,通過ejs.render提供生成
  • ...config: 用戶輸入選擇的參數(shù)值,通過此參數(shù)動態(tài)生成對應(yīng)模板

第四步 分析createReact函數(shù)

分析完工具函數(shù)代碼之后,我們正式分析主函數(shù)createReact

/**
 * @description 生成react模板
 * @author hu-snail 1217437592@qq.com
 */

import fs from 'fs'
import mkdirp from "mkdirp";
import { getFiles, copyFile, getCode } from '../utils/index.js'
import { jsignoreFile } from './config.js'
export const createReact = (config, rootPath) => {
   // 創(chuàng)建項目
   mkdirp.sync(rootPath)
   const { template, supportTs } = config
   const reactTemplate = (template === 'react' || template === 'react-ts') ? 'react' : ''
   const { files, dirs } = getFiles(reactTemplate)
   // 創(chuàng)建文件夾
   dirs.map(item => {
    mkdirp.sync(`${rootPath}/${item}`)
   })

   files.map(item => {
    const isEjs = item.indexOf('.ejs') !== -1
    // 對模板文件進行操作
    if (isEjs) {
       const fileTyep = supportTs ? 'ts' : 'js'
       // 去掉ejs后綴
       const newItem = item.replace(/.ejs/g, '')
       // json后綴名不需要處理
       const isJson = newItem.indexOf('.json') !== -1
       // 替換后綴名
       const newFilePath = isJson ? newItem : newItem.replace(/js/g, fileTyep)
       // 寫入相關(guān)模板文件
      fs.writeFileSync(
         `${rootPath}/${newFilePath}`,
         getCode(config, reactTemplate, item)
       )
    } else {
       // 如果不是ejs模板,直接復(fù)制文件 
       if (supportTs) copyFile(rootPath, reactTemplate, item)
       else {
         // 判斷是否存在js需要忽略的文件,即存在ts文件
         const hasTsFile = jsignoreFile.includes(item)
         if (!hasTsFile) copyFile(rootPath, reactTemplate, item)
       }
    }
   })
    return ''
}

代碼分析:

該函數(shù)接受兩個參數(shù)config、 rootPath:分別表示用戶輸入選擇參數(shù)值配置、項目根目錄。

  • mkdirp.sync(rootPath):通過mkdirp創(chuàng)建項目目錄
  • reactTemplate:通過template傳入的值react、react-ts 統(tǒng)一react傳入,因為模板目錄只有react,可根據(jù)自己需求調(diào)整

其他項有代碼注釋,不一一贅述

第五步 模板動態(tài)配置

作為測試,我們對package.json.ejsindex.html.ejs進行動態(tài)配置,分別對應(yīng)的目錄bin/templates/react/package.json.ejs、bin/templates/react/index.html.ejs

package.json.ejs:代碼

{
  "name": "<%= projectName %>",
  "private": true,
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  },
  "devDependencies": {
    "@types/react": "^18.0.0",
    "@types/react-dom": "^18.0.0",
    "@vitejs/plugin-react": "^1.3.0",
    <%_ if (supportTs) { -%>
    "typescript": "^4.6.3",
    <%_ } -%>
    "vite": "^2.9.9"
  }
}

根據(jù)supportTs:判斷是否需要"typescript",需要注意的<%_ -%>:語法會刪除多余空行,如果使用<% %>:會導致留白,可以自行測試,"name": "<%= projectName %>":根據(jù)創(chuàng)建的項目名稱生成

index.html.ejs:代碼

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/src/favicon.svg" rel="external nofollow"  />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title><%= projectName %></title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html>

動態(tài)生成 <title><%= projectName %></title>

以上模板只是測試,可根據(jù)ejs模板語法,動態(tài)生成你需要的值

第五步 入口文件執(zhí)行模板生成

接下來將在入口文件,執(zhí)行我們的createReact函數(shù)

#! /usr/bin/env node
/**
 * @description 腳手架入口文件
 * @author hu-snail 1217437592@qq.com
 */
 import fs, { mkdirSync } from "fs";
 import path from "path";

 import command from "./commands/index.js";
 import { createReact } from './build/react.js'

 let config = await command();

 var currentPath = path.resolve("./");

 createReact(config, getRootPath())

 function getRootPath() {
    return `${currentPath}/${config.projectName}`;
 }

生成模板演示

現(xiàn)在可以看看具體效果

(一).js版本

yarn start create vite app-test -t react

效果圖

生成目錄

package.json文件

index.hml文件

(二).ts版本

yarn start create vite app-test -t react-ts

效果圖

生成目錄

package.json文件

index.hml文件相同

總結(jié)

到此這篇關(guān)于用NodeJs構(gòu)建屬于自己的前端腳手工具的文章就介紹到這了,更多相關(guān)NodeJs構(gòu)建前端腳手工具內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 簡單好用的nodejs 爬蟲框架分享

    簡單好用的nodejs 爬蟲框架分享

    使用nodejs開發(fā)爬蟲半年左右了,爬蟲可以很簡單,也可以很復(fù)雜。簡單的爬蟲定向爬取一個網(wǎng)站,可能有個幾萬或者幾十萬的頁面請求,今天給大家介紹這款非常好用的爬蟲框架crawl-pet
    2017-03-03
  • 利用pm2部署多個node.js項目的配置教程

    利用pm2部署多個node.js項目的配置教程

    目前似乎最常見的線上部署nodejs項目的有forever,pm2這兩種,而下面這篇文章主要給大家介紹了關(guān)于利用pm2部署多個node.js項目的配置教程,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-10-10
  • node.js中的fs.lchmodSync方法使用說明

    node.js中的fs.lchmodSync方法使用說明

    這篇文章主要介紹了node.js中的fs.lchmodSync方法使用說明,本文介紹了fs.lchmodSync的方法說明、語法、接收參數(shù)、使用實例和實現(xiàn)源碼,需要的朋友可以參考下
    2014-12-12
  • 詳解nodeJS中讀寫文件方法的區(qū)別

    詳解nodeJS中讀寫文件方法的區(qū)別

    本篇文章主要介紹了詳解nodeJS中讀寫文件方法的區(qū)別,nodejs的fs模塊針對讀操作為我們提供了readFile,read, createReadStream三個方法,有興趣的可以了解一下。
    2017-03-03
  • Node.js?連接?MySql?統(tǒng)計組件屬性的使用情況解析

    Node.js?連接?MySql?統(tǒng)計組件屬性的使用情況解析

    這篇文章主要為大家介紹了Node.js?連接?MySql?統(tǒng)計組件屬性的使用情況解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10
  • Node.js之IP地址和端口號問題

    Node.js之IP地址和端口號問題

    這篇文章主要介紹了Node.js之IP地址和端口號問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • node.js中的buffer.write方法使用說明

    node.js中的buffer.write方法使用說明

    這篇文章主要介紹了node.js中的buffer.write方法使用說明,本文介紹了buffer.write的方法說明、語法、接收參數(shù)、使用實例和實現(xiàn)源碼,需要的朋友可以參考下
    2014-12-12
  • 在Linux系統(tǒng)中搭建Node.js開發(fā)環(huán)境的簡單步驟講解

    在Linux系統(tǒng)中搭建Node.js開發(fā)環(huán)境的簡單步驟講解

    這篇文章主要介紹了在Linux系統(tǒng)中搭建Node.js開發(fā)環(huán)境的步驟,Node使得JavaScript程序可以在本地操作系統(tǒng)環(huán)境中解釋運行,需要的朋友可以參考下
    2016-01-01
  • node 可讀流與可寫流的運用詳解

    node 可讀流與可寫流的運用詳解

    這篇文章主要為大家介紹了node 可讀流與可寫流的運用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • node實現(xiàn)批量上傳本地圖片轉(zhuǎn)為圖片CDN的項目實踐

    node實現(xiàn)批量上傳本地圖片轉(zhuǎn)為圖片CDN的項目實踐

    本文主要介紹了node實現(xiàn)批量上傳本地圖片轉(zhuǎn)為圖片CDN的項目實踐,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-07-07

最新評論