企业网站网页打开慢,服装设计公司效果图,崇明网站怎么做seo,天宁网站建设制作目录 介绍为什么需要脚手架#xff1f;一个脚手架应该具备哪些功能#xff1f; 脚手架实现初始化项目相关依赖实现脚手架 发布 介绍
为什么需要脚手架#xff1f;
脚手架本质就是一个工具#xff0c;作用是能够让使用者专注于写代码#xff0c;它可以让我们只用一个命令… 目录 介绍为什么需要脚手架一个脚手架应该具备哪些功能 脚手架实现初始化项目相关依赖实现脚手架 发布 介绍
为什么需要脚手架
脚手架本质就是一个工具作用是能够让使用者专注于写代码它可以让我们只用一个命令就生成一个已经配置好的项目而不用我们再花时间去配置和安装相关依赖可以在很大程度上提升我们的开发效率。比如我们常用的create-vue和create-react-app就是脚手架很多大厂也都有自己的脚手架。
一个脚手架应该具备哪些功能
我们以vue官方的脚手架create-vue为例来分析下一个脚手架应该具备哪些功能
运行命令创建项目npm create vuelatest用户根据自己需要选择一些配置项 根据选择的配置项会生成一个模版项目
通过分析create-vue我们可以知道一个脚手架如果想要创建一个项目最少要有以下两点功能
可以通过命令行和用户交互根据交互的结果去生成对应的模版项目
脚手架实现
初始化项目
在电脑终端执行以下命令
mkdir kfc-vme50
cd kfc-vme50
npm init -y在根目录下创建bin/index.js文件作为入口文件并添加如下代码第一行注解是为了告诉操作系统本文件用node执行
#!/usr/bin/env node
console.log(肯德基疯狂星期四v我50)在package.json中添加bin字段
bin: /bin/index.js在根目录下执行npm link将项目链接到本地环境就可以实现kfc-vme50命令全局调用运行kfc-vme50并查看控制台输出 实际上npm link将这个包装到了全局我们在全局执行kfc-vme50系统会在package.json中找到bin声明bin指定的文件会被获取到然后用node执行这个文件 相关依赖
实现一个脚手架通常会用到以下依赖包
commander命令行处理工具安装npm install commander
#!/usr/bin/env node// #! 是shebang的标识告诉操作系统这是一个脚本文件。
// /usr/bin/env 是一个程序用来查找环境变量中定义的程序路径。在这个例子中它用来查找node的路径。
// node 是Node.js的可执行文件名它是运行JavaScript代码的运行时环境。// 它用于处理命令行参数;
const { program } require(commander);/*** .name 命令名称出现在帮助中也用于定位独立的可执行子命令。* .usage 通过这个选项可以修改帮助信息的首行提示即修改usage提示*/program.name(kfc-vme50-cli).usage(command [option]);/*** 「选项」 定义选项* 使用.option()方法来定义选项同时可以附加选项的简介。每个选项可以定义一个短选项名称-后面接单个字符* 一个长选项名称--后面接一个或多个单词使用逗号、空格或|分隔。* 有两种最常用的选项一类是 boolean 型选项选项无需配置参数* 另一类选项则可以设置参数使用尖括号声明在该选项后如--expect value。* 如果在命令行中不指定具体的选项及参数则会被定义为undefined*/program.option(-d, --debug, output extra debugging).option(-s, --small, small pizza size).option(-p, --pizza-type type, flavour of pizza);/*** 「命令」 通过.command()或.addCommand()可以配置命令* .command()的第一个参数为命令名称。命令参数可以跟在名称后面也可以用.argument()单独指定。* 参数可为必选的尖括号表示、可选的方括号表示或变长参数点号表示如果使用只能是最后一个参数。* ----------------------------------------------------------------* description 出现在命令的帮助中。* action 命令触发后的回调函数 [命令行的参数]*/program.command(clone source [destination]).description(clone a repository into a newly created directory).action((source, destination) {console.log(clone command called);console.log(source, destination);});/** * 「parse」解析命令行参数* program.parse 它的作用是解析 process.argv 数组将命令行参数转换为可操作的对象。* process.argv 是 Node.js 中的一个全局变量它是一个数组包含了命令行启动脚本时传递给 Node.js 进程的参数。数组的第一个元素 process.argv[0] 总是 node 表示 Node.js 可执行文件的路径 安装路径接下来的元素是脚本文件的路径即你正在运行的 JavaScript 文件的路径。之后的元素是传递给脚本的命令行参数process可以理解为node的环境变量argv是用户在控制台输入的命令
*/
program.parse(process.argv);/*** 「opts」获取用户输入的
命令行参数* 解析后的选项可以通过Command对象上的.opts()方法获取同时会被传递给命令处理函数。*/
const options program.opts();
console.log(options);console.log(肯德基疯狂星期四v我500);打印process.argv结果如下注意截图的指令为kfc-vme50-cli 使用上面定义好的clone命令 并且执行kfc-vme50-cli --help可以看到我们刚才定义的命令
chalk命令行输出美化工具安装npm install chalk4.0.0
#!/usr/bin/env node// 重要提示Chalk 5 部分是 ESM。如果您想将 Chalk 与 TypeScript 或构建工具一起使用您现在可能需要使用 Chalk 4/**
ESM 是 ECMAScript Module 的缩写它指的是一种 JavaScript 模块的规范允许开发者将代码分割成可重用的模块。
ESM 是现代 JavaScript 的一个特性它支持静态模块的导入和导出这意味着模块的依赖关系可以在编译时就确定下来从而提高代码的加载和执行效率。
然而ESM 也有它的限制比如它不支持 CommonJS 模块中的 require() 函数而是使用 import() 来动态加载模块。
此外ESM 需要在支持 ESM 的环境中使用比如现代浏览器或者使用 Babel 等工具转换的 Node.js 环境。*/const chalk require(chalk);// 颜色
console.log(chalk.yellow(Welcome));
// 加粗
console.log(chalk.red.bold(Welcome));
// 背景色
console.log(chalk.yellow.bold.bgBlue(Welcome));inquirer命令行交互工具安装npm install inquirer8.0.0
#!/usr/bin/env node
/*** !警告] Inquirer v9 及更高版本是 esm 模块* 这意味着您不能再使用 commonjs 语法 require(inquirer) * 或者如果您需要 commonjs 模块则应该依赖旧版本直到准备好升级环境*/
const inquirer require(inquirer);/*** inquirer.prompt(questions, answers) - promise* 启动提示界面查询会话* questions (Array) 包含 Question 对象使用反应式接口还可以传递 Rx.Observable 实例* 答案对象包含已回答问题的值。询问者将避免询问此处已提供的答案。默认值 {}。**「Question对象」 问题对象是包含问题相关值的哈希type 字符串提示的类型。【input, number, confirm, list, rawlist, expand, checkbox, password, editor】name字符串将答案存储在答案哈希中时使用的名称。如果名称包含句点它将在答案哈希中定义路径。message字符串|函数要打印的问题。如果定义为函数第一个参数将是当前询问者会话的答案。默认为 name 的值后跟冒号default字符串|数字|布尔值|数组|函数未输入任何内容时使用的默认值或返回默认值的函数。如果定义为函数第一个参数将是当前询问者会话的答案**/inquirer.prompt([// 将你的问题放在这{type: input,name: food,message: 你吃啥,default: 披萨,},{type: confirm,name: hot,message: 吃不吃辣,default: false,},]).then((answers) {//使用用户反馈。。。无论什么结果console.log(answers);}).catch((error) {if (error.isTtyError) {// 无法在当前环境中呈现提示} else {//其他问题}});就是用来定义询问用户操作的命令使用如下
ora终端loading美化工具安装npm install ora5.0.0更高版本是esm模块不能使用require引入
#!/usr/bin/env node
const ora require(ora);// 启动旋转器。返回实例。如果提供了文本则设置当前文本。
const spinner ora(Loading unicorns).start();// 旋转器1s后变为黄色文案变为Loading rainbows
setTimeout(() {spinner.color yellow;spinner.text Loading rainbows;
}, 1000);// 停止旋转器将其更改为绿色 ✔ 并保留当前文本或文本如果提供。返回实例。请参阅下面的 GIF。
// setTimeout(() {
// spinner.succeed(succeed);
// }, 2000);// 停止旋转器将其更改为红色 ✖ 并保留当前文本或文本如果提供。返回实例。
setTimeout(() {spinner.fail(fail);
}, 2000);git-clone下载项目模版工具安装npm install git-clonefiglet终端生成艺术字安装npm insatll figlet
#!/usr/bin/env node
var figlet require(figlet);// 将 Figlet 对象作为函数调用是调用文本函数的简写。此方法允许您从文本创建 ASCII 艺术。
// 输入文本 - 要转换为 ASCII 艺术的文本字符串。
// 选项 - 指示字体名称的字符串或选项对象如下所述
// 回调 - 使用生成的 ASCII Art 执行的函数。figlet(Hello World!!, function (err, data) {if (err) {console.log(Something went wrong...);console.dir(err);return;}console.log(data);
});// 该方法是上述方法的同步版本
// 输入文本 - 要转换为 ASCII 艺术的文本字符串。
// 字体选项 - 指示字体名称的字符串或选项对象如下所述。
console.log(figlet.textSync(Boo!, {font: Ghost, //类型字符串 默认值标准 指示要使用的 Figlet 字体的字符串值。horizontalLayout: default, //指示要使用的水平布局的字符串值verticalLayout: default, //指示要使用的垂直布局的字符串值width: 80, //宽度whitespaceBreak: true, //此选项与“宽度”结合使用。如果此选项设置为 true则库在限制宽度时将尝试在空白处分解文本。})
);fs-extra用来操作本地目录安装npm run fs-extra
实现脚手架
#!/usr/bin/env node// 操作终端命令行
const { program } require(commander);
// 艺术字
const figlet require(figlet);
// 操作文件
const fs require(fs-extra);
// 获取路径
const path require(path);
// 命令行交互
const inquirer require(inquirer);
// 彩色输出
const chalk require(chalk);
//控制台loadding
const ora require(ora);// clone 项目
const gitClone require(git-clone);// 项目仓库
const projectList {vue: https://gitee.com/y_project/RuoYi-Vue.git,react: https://gitee.com/whiteshader/ruoyi-react.git,reactts: https://gitee.com/whiteshader/ruoyi-react.git,vuets: https://gitee.com/lyforvue/ruoyi_vue3_ts.git,
};// 修改帮助信息的首行展示
program.usage(command [options]);// 版本号
program.version(v${require(../package.json).version});// 艺术字展示 监听 help添加提示信息
program.on(--help, function () {console.log(figlet.textSync(kfc vme50, {font: Ghost,horizontalLayout: default,verticalLayout: default,width: 100,whitespaceBreak: true,}));
});// 创建项目的命令
program.command(create app-name) // 创建项目的命令 name必填.description(创建新项目) //描述//执行命令后的回调【命令后的值】.action(async function (name, option) {//创建一个名为name的文件夹把我们模板项目的代码都放到文件夹下// 1. 先判断有没有名为name的文件夹const cwd process.cwd(); //获取命令执行的文件目录// 创建项目的位置const targetPath path.join(cwd, name);// 如果文件夹存在if (fs.existsSync(targetPath)) {const res await inquirer.prompt([{name: action,type: list,message: 是否覆盖已有文件夹,choices: [{name: YES,value: true,},{name: NO,value: false,},],},]);//不覆盖 直接返回让用户取一个新的名字再创建if (!res.action) return;fs.remove(targetPath);console.log(chalk.red(已删除之前的文件夹));}//新建项目const res await inquirer.prompt([{name: type,type: list,message: 请选择使用的框架,choices: [{name: Vue,value: vue,},{name: React,value: react,},],},{name: ts,type: list,message: 是否使用ts项目,choices: [{name: YES,value: true,},{name: NO,value: false,},],},]);// 是否为tsconst rep res.type (res.ts ? ts : );// 拉取项目模板const spinner ora(正在加载项目模板...).start();gitClone(projectList[rep], //拉取路径targetPath, //保存路径//分支{checkout: master,},//回调函数(err) {if (!err) {fs.remove(path.resolve(targetPath, .git));spinner.succeed(项目模板加载完成);console.log(now run:);console.log(chalk.green(\n cd ${name}));console.log(chalk.green( npm install));console.log(chalk.green( npm run ${res.type react ? start : dev}\n));} else {spinner.fail(chalk.red(项目模板加载失败请重新获取, err));}});});//解析控制台参数
program.parse(process.argv);发布
npm官网注册npm账号在本地登录并发布
# 登录刚注册的账号
npm login
Username: 用户名
Password: 密码
Email: 注册邮箱
Enter one-time password: 一次性密码 邮箱会收到邮件# 在我们脚手架的根目录下执行发布命令
npm publish注意 登录和发包前一定要先查看npm的源需要修改为https://registry.npmjs.org/在发布时包名不能重复所以可以先在npm官网搜索下看看有没有存在的包如果出现403错误可能是包名和线上的包重复了修改package.json中的name即可如果以后要更新包更新package.json的version再发布一下即可在npm官网上为你的包添加readme登陆npm官网可以在setting中删除你自己发的包