一.前言

在日常开发中,我们经常会用到各种脚手架工具,如常用的vue和react脚手架工具:vue-cli、Create React App。只需要执行内置命令和选择内置条件就可以生成对应的项目模板。极大的提高了我们开发开发效率,所以我们能不能根据自己的日常业务构建属于自己的一套脚手架工具呢,答案是可以的。接下来步入本文章的主题

二.技术栈

  • commander:^9.2.0 :完整的 node.js命令行解决方案
  • execa: ^6.1.0:执行shel命令
  • inquirer: ^8.2.4:交互式命令行用户界面,在命令工具中可提供交互
  • ejs: ^3.1.8:嵌入式JavaScript模板
  • chalk: ^5.0.1:设置终端字符串样式
  • mkdirp:^1.0.4:递归mkdir

三.特别说明

在开始之前,需要了解nodejs基础知识,常用shell执行命令,和javascript基础知识!!! 本文将从零到一完整讲解脚手架开发过程,以Vite React18.0为模板案例,不会完整开发类似vue-cli 的所有功能!你可按照此文优化完善自己的脚手架代码。

四.构建项目

现在正式开始构建脚手架项目,可根据自己熟悉方式创建,直接创建项目文件夹

# 创建项目文件夹 名称为 my-cli 可自定义
mkdir my-cli
# 初始化 npm 根据自己的需求填写对应信息,也可以直接默认
npm init

五.安装依赖

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

六.目录说明

完整目录,如下所示,可根据目录设计添加对应文件。

my-cli # 项目名称
└── bin # 主目录
    ├── commands # 命令文件
    │   ├── options # 命令所有选项
    │   │   ├── create.js # 创建命令
    │   │   ├── help.js # 帮助命令
    │   │   ├── help.js # 导出所有命令文件
    │   ├── index.js # 导出command命令方法
    ├── inquirers # 交互式命令文件
    │   ├── options # 交互式命令所有选项
    │   │   ├── common.js # 公共交互式命令
    │   │   ├── react.js # react相关命令
    │   │   ├── index.js # 导出所有交互式命令文件
    │   ├── index.js # 导出command命令方法
    ├── templates # 所有模板文件
    │   ├── react # react相关模板
    │   ├── vue # vue相关模板
    ├── utils # 工具类
    │   ├── index.js # 工具类处理函数
    ├── index.js # 入口文件

完整代码:my-cli

七.实战

在开始前,我们需要修改package.json文件,增加"bin": "./bin/index.js":发布到npm设置执行入口文件; "type": "module":表示允许执行export、import操作;"start": "node ./bin/index.js":做本地测试使用,表示执行脚手架入口文件

{
    "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 相关命令方法
import commands from "./commands/index.js";
// 获取用户输入、选择项
let config = await command();

需要注意的是#! /usr/bin/env node 表示执行环境为node,引入fs文件系统模块,创建文件项目会涉及到文件相关读取写能力;引入path读取文件路径。commands执行命令;通过let config = await command();获取用户输入、选择项;这一步涉及到commands所以接下来开始分析:bin/commands/index.js用户输入命令模块

(二).命令文件

目录路径:bin/commands/index.js

// 引入 commander 命令
import { program } from "commander";
import chalk from "chalk";
// 导入 create创建命令 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");
    // 创建项目命令
    create(program, (item) => {
      resolve(item);
    });
    // 帮助信息
    help(program);
    // 解析指令
    program.parse(process.argv);
  });
};

我们需要关注的是create、help分别是创建命令、帮助命令

(三).创建命令

create创建命令 ,文件路径:bin/commands/options/create.js

/**
 * @description 创建项目指令
 * @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转为boolean
          item.supportTs = item.supportTs === 'true' ? true : false
          return call && call({ method, ...item });
        }
       // 如果用户没有输入 模板参数,则提供项目类型选择 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 校验构建方式
  * @param {String} appName 项目名称
  * @returns appName
  */
 function validatBuildMethod(val) {
   if (val === "vite") return val;
   else
     throw new InvalidArgumentError(
       chalk.red(
         `
         "<build-method>构建方式,只支持值为:${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 校验模板
  * @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;
 }

思路分析:

上图所示,主要分两种情况,当用户完整输入和部分输入参数判。

关于program详细分析

.command("create"):表示创建一个名为create的命令;

.argument("<build-method>", "build tools", validatBuildMethod):其中argument:表示参数、<build-method>:表示构建方式,必填参数、build tools:表示参数描述、validatBuildMethod:表示自定义校验方法;

[app-name]:表示可选项,项目名称。<>:表示必填参数,[]:表示可选项

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

.option("-t, --template <value>", "create a new project by template"):表示命令参数、 "-t, --template <value>":表示用户可输入-t--template:表示template参数、"create a new project by template":表示参数描述;

.action(async (method, projectName, option) => {}):表示命令行为事件,其中method, projectName:分别代表<build-method>构建方式、<app-name>项目名称,和顺序关联,可根据自己需求增删参数、option:表示参数选项、也就是"-t, --template <value>"可根据自己需求定义。

hasTemplategetSupportTs:分别表示是否存在模板,获取是否支持ts,在bin/utils/index.js可查看其用法

当用户没有完整输入项目框架时,我们会提供changeTemplatechangeVariantinputProjectName这个时候,就需要用到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",
    };
  };

参数解释,完整参数文档inpuirer文档

  • type:表示参数类型,提供input、number、confirm、list、rawlist、expand、checkbox、password、editor
  • name:表示参数属性
  • choices:选择项
  • message: 操作提示语
  • de'fa

其中changeVariant:选择是否支持ts;inputProjectName:输入项目名称

(五).选择项目框架交互式命令

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

/**
 * @description 创建项目类型选择
 * @author hu-snail 1217437592@qq.com
 */

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

创建命令,到此结束,接下来分析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命令中使用到,补充!!!

八.本地测试

准备完以上代码后,我们开始本地测试,测试目的是检测是否能够正确的返回我们预设的结果,可根据自己的需求定义和完善脚手架。本文只是讲解demo流程!!!

(一).完整输入

完成输入测试包含正确输入、构建方式有误输入、项目名称不合规输入

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

效果图:

以上结果也就是我们入口文件:bin/index.jslet config = await command();获取的值

构建方法输入有误vite1:为错误输入❌  只支持vite方式构建,可根据自己的需求适配多种构建方式

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

效果图:

项目名称不合规输入 1my-test-project:为不符合规范名称

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

效果图:

(二).不完整输入

包含构建方式不输入、名称不输入、项目框架方式不输入

构建方式不输入会直接导致报错,重点是名称不输入、项目框架方式不输入,这时会给用户提供选择

项目名称不输入

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

效果图

项目名称不输入会提供默认值和输入给用户,同时完成项目框架选择、和是否支持ts选择。完整截图如下:

这个结果也就是我们入口文件:bin/index.jslet config = await command();获取的值

项目框架方式不输入

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

效果图:

不输入项目框架会提供选择,同时选择是否支持ts,完整截图如下:

到此结束测试,你可以根据这个思路完善自己的脚手架,接下来开始模板生成

九.导入Vite react18模板

当我们能获取到用户输入选择的值后,就可根据用户输入的参数生成对应的项目模板,本文以vite reat18为例

bin/templates目录下创建React模板文件,完整目录如下:

bin
├── templates # 所有模板文件
│   ├── react # react相关模板
│   │   ├── 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…

如果实现vite vue3可参考此方法生成对应模板

模板技巧:不需要动态改变文件,直接使用原后缀名,例如:静态资源(图、视频、音等资源)、需要动态改变的文件,保留原来的后缀名,在其基础上添加.ejs:例如(package.jsonpackage.json.ejs)这样的好处是,知道原来的文件类型,方便更快的处理

十.创建生成模板代码

完成模板之后,开始重点环节,根据用户输入选择参数动态生成项目模板,跟着我的步骤完成生成模板语法

第一步:创建build文件夹

bin/创建build文件,用于存放生成模板文件和生成配置文件,目录如下:

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

第二步: config配置

因为脚手架内置了支持tsjs,所有存在差异化,具体配置如下:

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

其中模板中的tsconfig.jsontsconfig.node.jsonts才存在,所以在js需要忽略。可按照此方式区分文件之间的差异化。

第三步:react生成模板

准备完以上内容后,接下正式开始生成模板,文件路径: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'

代码分析:

代码中导入了getFilescopyFilegetCode三个方法,分别代表获取文件、拷贝文件、获取代码。首先从这三个方法开始分析,文件路径: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}
}

代码分析:

该函数提供两个参数,分别是templatedir,表示模板、目录,同时在方法前定义了两个变量filesdirs分别表示文件、目录,主要作用区分文件和目录,这样方便用于生成目录和创建文件。

  • templatePath:表示模板地址,根据传入template动态配置
  • 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 复制文件,比如图片/图标静态资源
  * @param {*} rootPath 根目录
  * @param {*} template 模板
  * @param {*} item 静态模板文件
  */
 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", () => {
     // 继续读取
     rs.resume();
   });
 
   rs.on("end", () => {
     ws.end();
   });
 }

代码分析:

该函数提供三个参数rootPathtemplateitem,分别表示根目录,模板名称、静态模板路径。

  • fromFileName:表示读取文件地址
  • toFileName:表示拷贝至地址
  • rs:表示读取文件流,通过fs.createWriteStream创建
  • ws:表示写入文件流,通过fs.createWriteStream创建

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;
 }

代码分析:

该函数接受三个参数configtemplateNametemplatePath:分别表示配置信息、模板名称、模板地址

  • template:模板文件,通过fs.readFileSync读取
  • code: 模板代码,通过ejs.render提供生成
  • ...config: 用户输入选择的参数值,通过此参数动态生成对应模板

第四步 分析createReact函数

分析完工具函数代码之后,我们正式分析主函数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) => {
   // 创建项目
   mkdirp.sync(rootPath)
   const { template, supportTs } = config
   const reactTemplate = (template === 'react' || template === 'react-ts') ? 'react' : ''
   const { files, dirs } = getFiles(reactTemplate)
   // 创建文件夹
   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)
       // 写入相关模板文件
      fs.writeFileSync(
         `${rootPath}/${newFilePath}`,
         getCode(config, reactTemplate, item)
       )
    } else {
       // 如果不是ejs模板,直接复制文件 
       if (supportTs) copyFile(rootPath, reactTemplate, item)
       else {
         // 判断是否存在js需要忽略的文件,即存在ts文件
         const hasTsFile = jsignoreFile.includes(item)
         if (!hasTsFile) copyFile(rootPath, reactTemplate, item)
       }
    }
   })
    return ''
}

代码分析:

该函数接受两个参数configrootPath:分别表示用户输入选择参数值配置、项目根目录。

  • mkdirp.sync(rootPath):通过mkdirp创建项目目录
  • reactTemplate:通过template传入的值reactreact-ts 统一react传入,因为模板目录只有react,可根据自己需求调整

其他项有代码注释,不一一赘述

第五步 模板动态配置

作为测试,我们对package.json.ejsindex.html.ejs进行动态配置,分别对应的目录bin/templates/react/package.json.ejsbin/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"
  }
}

根据supportTs:判断是否需要"typescript",需要注意的<%_ -%>:语法会删除多余空行,如果使用<% %>:会导致留白,可以自行测试,"name": "<%= projectName %>":根据创建的项目名称生成

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>

动态生成 <title><%= projectName %></title>

以上模板只是测试,可根据ejs模板语法,动态生成你需要的值

第五步 入口文件执行模板生成

接下来将在入口文件,执行我们的createReact函数

#! /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}`;
 }

生成模板演示

现在可以看看具体效果

(一).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文件相同

总结

到此这篇关于用NodeJs构建属于自己的前端脚手工具的文章就介绍到这了,更多相关NodeJs构建前端脚手工具内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

教你用NodeJs构建属于自己的前端脚手工具的更多相关文章

  1. 前端实现背景虚化但内容清晰且自适应 的实例代码

    这篇文章主要介绍了前端实现背景虚化但内容清晰且自适应 的实例代码,需要的朋友可以参考下

  2. nodejs npm package.json中文文档

    这篇文章主要介绍了nodejs npm package.json中文文档,本文档中描述的很多行为都受npm-config(7)的影响,需要的朋友可以参考下

  3. 浅析Nodejs npm常用命令

    这篇文章主要介绍了浅析Nodejs npm常用命令的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下

  4. nodejs 使用nodejs-websocket模块实现点对点实时通讯

    这篇文章主要介绍了nodejs 使用nodejs-websocket模块实现点对点实时通讯的实例代码,代码简单易懂,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下

  5. nodeJs链接Mysql做增删改查的简单操作

    本篇文章主要介绍了nodeJs链接Mysql做增删改查的简单操作,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  6. Nodejs中使用captchapng模块生成图片验证码

    本篇文章主要介绍了Nodejs中使用captchapng模块实现图片验证码,非常具有实用价值,需要的朋友可以参考下

  7. nodejs 图片预览和上传的示例代码

    本篇文章主要介绍了nodejs 图片预览和上传的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  8. nodejs中函数的调用实例详解

    本文通过实例代码给大家介绍了nodejs函数的调用,代码简单易懂,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下

  9. NodeJS使用formidable实现文件上传

    这篇文章主要为大家详细介绍了NodeJS使用formidable实现文件上传的相关方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. Nodejs获取网络数据并生成Excel表格

    这篇文章主要为大家详细介绍了Nodejs获取网络数据并生成Excel表格的具体实现方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

随机推荐

  1. Error: Cannot find module ‘node:util‘问题解决

    控制台 安装 Vue-Cli 最后一步出现 Error: Cannot find module 'node:util' 问题解决方案1.问题C:\Windows\System32>cnpm install -g @vue/cli@4.0.3internal/modules/cjs/loader.js:638 throw err; &nbs

  2. yarn的安装和使用(全网最详细)

    一、yarn的简介:Yarn是facebook发布的一款取代npm的包管理工具。二、yarn的特点:速度超快。Yarn 缓存了每个下载过的包,所以再次使用时无需重复下载。 同时利用并行下载以最大化资源利用率,因此安装速度更快。超级安全。在执行代码之前,Yarn 会通过算法校验每个安装包的完整性。超级可靠。使用详细、简洁的锁文件格式和明确的安装算法,Yarn 能够保证在不同系统上无差异的工作。三、y

  3. 前端环境 本机可切换node多版本 问题源头是node使用的高版本

    前言投降投降 重头再来 重装环境 也就分分钟的事 偏要折腾 这下好了1天了 还没折腾出来问题的源头是node 使用的高版本 方案那就用 本机可切换多版本最终问题是因为nodejs的版本太高,导致的node-sass不兼容问题,我的node是v16.14.0的版本,项目中用了"node-sass": "^4.7.2"版本,无法匹配当前的node版本根据文章的提

  4. nodejs模块学习之connect解析

    这篇文章主要介绍了nodejs模块学习之connect解析,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  5. nodejs npm package.json中文文档

    这篇文章主要介绍了nodejs npm package.json中文文档,本文档中描述的很多行为都受npm-config(7)的影响,需要的朋友可以参考下

  6. 详解koa2学习中使用 async 、await、promise解决异步的问题

    这篇文章主要介绍了详解koa2学习中使用 async 、await、promise解决异步的问题,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  7. Node.js编写爬虫的基本思路及抓取百度图片的实例分享

    这篇文章主要介绍了Node.js编写爬虫的基本思路及抓取百度图片的实例分享,其中作者提到了需要特别注意GBK转码的转码问题,需要的朋友可以参考下

  8. CentOS 8.2服务器上安装最新版Node.js的方法

    这篇文章主要介绍了CentOS 8.2服务器上安装最新版Node.js的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  9. node.js三个步骤实现一个服务器及Express包使用

    这篇文章主要介绍了node.js三个步骤实现一个服务器及Express包使用,文章通过新建一个文件展开全文内容,具有一定的参考价值,需要的小伙伴可以参考一下

  10. node下使用UglifyJS压缩合并JS文件的方法

    下面小编就为大家分享一篇node下使用UglifyJS压缩合并JS文件的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

返回
顶部