node工程默认url_node命令行工具之实现项目工程自动初始化的标准流程

一、目的

传统的前端项目初始流程一般是这样:

可以看出,传统的初始化步骤,花费的时间并不少。而且,人工操作的情况下,总有改漏的情况出现。这个缺点有时很致命。

甚至有马大哈,没有更新项目仓库地址,导致提交代码到旧仓库,这就很尴尬了。。。

基于这些情况,编写命令行工具(CLI)的目的就很明确:

用于新项目工程的初始化利用工具进行初始化,可以节省项目初期的准备时间避免出现改漏的情况杜绝未更新项目版本仓库地址的问题

以下是新的流程示意图:

二、自动化流程分析

以下是自动化流程图:

从流程图可以得出两个重要的信息:

配置信息模板文件

命令行工具的角色,是负责将两个信息进行融合,提供一个交互平台给用户。

三、工具准备

3.1 配置信息工具

配置信息的获得,需要靠和用户进行交互。由于程序员一般是用终端输入命令进行项目操作。所以,这里选择了两个工具进行支撑。

commander

借鉴Ruby commander理念实现的命令行执行补全解决方案

commander可以接收命令行传入的参数

例子:

npg-cli --help

♫ ♫♬♪♫ npm-package-cli ♫ ♫♬♪♫

Usage: npg-cli [options]

Options:

-V, --version output the version number

-h, --help output usage information

run testcli and edit the setting.

inquirer

常用交互式命令行用户界面的集合。

inquirer用询问式的语句,与用户进行交互,接收参数

例子:

npg-cli

♫ ♫♬♪♫ npm-package-cli ♫ ♫♬♪♫

Follow the prompts to complete the project configuration.

? project name test

? version 1.0.0

? description

3.2 模板信息工具

前端的JavaScript 模板引擎,比如ejs,jade等。可以根据传入的参数,对模板标签进行替换,最终生成html。

如果把所有项目文件,不管文件后缀名,都看成是ejs模板,则可以在文件内容中使用ejs语法。

再根据配置信息进行替换,最终生成新文件。

其实,业界依据这个想法,已经有成熟的工具产生。

mem-fs

mem-fs是对文件进行读取,存入内存中。

mem-fs-editor

mem-fs-editor是对内存中的文件信息,使用ejs语法进行编译。最后调用commit方法输出最终文件。

3.3 提示信息工具

提示信息,除了console.log,还可以使用色彩更丰富的chalk。

这样,可以输出更直观、友好的提示。

3.4 文件操作

文件操作,有业界成熟的shelljs。

利用shelljs,可以在项目中简化以下步骤:

一些项目文件,不需要修改,只用直接copy。可以使用shelljs.copySync同步方式生成。一些文件夹,需要提前构建,可以使用shelljs.mkdir进行创建

四、实现

以下按我做的开源项目——npm-package-cli的创作过程进行分拆、讲解。

4.1 初始化

新建项目文件夹npm-package-cli,并在该文件夹下运行npm init,生成package.json。

项目结构如下:

npm-package-cli

|-- package.json

4.2 生成全局指令

这里要生成的全局指令是npg-cli。

4.2.1 新建执行文件

新建文件夹bin,并在文件夹下新建名称为cli的shell脚本文件(注意:不能有后缀名)。

clishell脚本文件内容如下:

#!/usr/bin/env node

console.log('hello world');

其中,#!/usr/bin/env node是告诉编译器,以node的方式,运行代码。

并在package.json加入以下内容:

"bin": {

"npg-cli": "bin/cli"

}

此时,项目结构如下:

npm-package-cli

|-- bin

|-- cli

|-- package.json

4.2.2 链接指令到全局

链接指令有两种方式:

npm link

npm install -g

两种方式,都需要在npm-package-cli文件夹下运行,才能生效。

作用是把npg-cli指令,指向全局的bin文件下,实现软链。

4.2.3 运行

在任意文件夹下运行命令:

npg-cli

# 输出

hello world

到这里,一个基本的指令就算完成了,接下来是指令的工作内容细化。

4.3 初始化操作类Creation

Creation的作用是整合所有操作,并提供接口给指令文件cli。

Creation的结构如下:

class Creation{

constructor(){

// code

}

do(){

// code

}

// other function

}

其中do方法暴露给脚本文件cli调用。

Creation类放在src/index.js中。

此时,项目结构如下:

npm-package-cli

|-- bin

|-- cli

|-- src

|-- index.js

|-- package.json

4.4 修改cli文件

#!/usr/bin/env node

const Creator = require('../src/index.js');

const project = new Creator();

project.do();

这样,只要实现好do方法,就可以完成npg-cli指令的运行了。

4.5 实现命令行参数读取

实现npg-cli --help,需要借助上文提到的工具commander。

新建src/command.js文件,文件内容如下:

const commander = require('commander');

const chalk = require('chalk');

const packageJson = require('../package.json');

const log = console.log;

function initCommand(){

commander.version(packageJson.version)

.on('--help', ()=>{

log(chalk.green(' run testcli and edit the setting.'));

})

.parse(process.argv);

}

module.exports = initCommand;

此时,项目结构如下:

npm-package-cli

|-- bin

|-- cli

|-- src

|-- command.js

|-- index.js

|-- package.json

然后在Creation.do方法内执行initCommand()即可生效。

// src/index.js Creation

const initCommand = require('./command');

class Creation{

// other code

do(){

initCommand();

}

}

此时,运行npg-cli --help指令,就可以看到:

Usage: npg-cli [options]

Options:

-V, --version output the version number

-h, --help output usage information

run testcli and edit the setting.

4.6 获取用户输入配置信息

要获取用户输入的信息,需要借助工具inquirer。

新建src/setting.js文件,文件内容如下:

const inquirer = require('inquirer');

const fse = require('fs-extra');

function initSetting(){

let prompt = [

{

type: 'input',

name: 'projectName',

message: 'project name',

validate(input){

if(!input){

return 'project name is required.'

}

if(fse.existsSync(input)){

return 'project name of folder is exist.'

}

return true;

}

},

// other prompt

];

return inquirer.prompt(prompt);

}

module.exports = initSetting;

此时,项目结构如下:

npm-package-cli

|-- bin

|-- cli

|-- src

|-- command.js

|-- index.js

|-- setting.js

|-- package.json

然后在Creation.do方法内执行initSetting()即可生效。

// src/index.js Creation

const initCommand = require('./command');

const initSetting = require('./setting');

class Creation{

// other code

do(){

initCommand();

initSetting().then(setting => {

// 用户输入完成后,会得到全部输入信息的json数据 setting

});

}

}

这里,inquirer.prompt方法装载好要收集的问题后,返回的是Promise对象。收集完成之后,要在then方法内拿到配置信息,以便进行下一步模板替换的操作。

4.7 模板文件替换输出

模板文件替换,要用到工具mem-fs和mem-fs-editor。

文件操作,要用到工具shelljs。

新建src/output.js文件,文件内容如下(删除了部分代码,以下只是示例,完整项目看最后分享链接):

const chalk = require('chalk');

const fse = require('fs-extra');

const path = require('path');

const log = console.log;

function output(creation){

return new Promise((resolve, reject)=>{

// 拿到配置信息

const setting = creation._setting;

const {

projectName

} = setting;

// 获取当前命令行执行环境所在文件夹

const cwd = process.cwd();

// 初始化文件夹path

const projectPath = path.join(cwd, projectName);

const projectResolve = getProjectResolve(projectPath);

// 新建项目文件夹

fse.mkdirSync(projectPath);

// copy文件夹

creation.copy('src', projectResolve('src'));

// 根据配置信息,替换文件内容

creation.copyTpl('package.json', projectResolve('package.json'), setting);

// 将内存中的文件,输出到硬盘上

creation._mfs.commit(() => {

resolve();

});

});

}

module.exports = output;

output方法的作用:

新建项目文件夹

把模板文件读取出来,根据配置信息,进行替换(调用的是mem-fs-editor的copyTpl方法)

拷贝其他文件

输出最终文件到硬盘上

这里最重要的一步,是调用mem-fs-editor的方法后,要执行mem-fs-editor的commit方法,输出内存中的文件到硬盘上。

在Creation.do方法中,调用output方法即可输出新项目文件。

打开src/index.js文件,文件内容增加如下方法:

// src/index.js Creation

const initCommand = require('./command');

const initSetting = require('./setting');

const output = require('./output');

class Creation{

// other code

do(){

initCommand();

initSetting().then(setting => {

// 用户输入完成后,会得到全部输入信息的json数据 setting

this._setting = Object.assign({}, this._setting, setting);

// 输出文件

output(this).then(res => {

// 项目输出完成

});

});

}

}

4.8 阶段小结

自动初始化一个项目的流程不外乎以下三点:

读取用户配置

读取模板文件

根据配置,编译模板文件,输出最终文件

命令行工具,是对这三点的有效整合,串连成一个规范的流程。

五、发布npm包的注意点

命令行工具中,使用的第三方工具包,都需要用--save的方式安装。

体现在package.json的表现是dependencies字段:

"dependencies": {

"chalk": "^2.4.2",

"commander": "^3.0.0",

"fs-extra": "^8.1.0",

"inquirer": "^6.5.0",

"mem-fs": "^1.1.3",

"mem-fs-editor": "^6.0.0",

"shelljs": "^0.8.3"

},

这样,其他用户在安装你发布的CLI工具时,才会自动安装这些依赖。

六、项目开源

我创作的npm-package-cli,是专门用于生成个人npm package项目的CLI工具。

生成的项目,囊括以下功能点:

支持TypeScrpt

mocha+chai自动化测试,支持使用TypeScript编写测试用例支持测试覆盖率

coverage支持eslint,包括对TypeScript的lint检查

Git commit规范提交

Git版本自动打标签(standard-version),更新CHANGELOG.md

输出的npm包

支持各种模块规范(AMD、CMD、CommonJS、ESModule)

CLI工具安装方式:

npm install -g npm-package-cli

如果对你有所帮助,麻烦给个Star,你的肯定是我前进的动力~

总结

以上所述是小编给大家介绍的node命令行工具之实现项目工程自动初始化的标准流程,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/436887.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【转】!C#中的Stream相关

计算机文件基本上分为二种:二进制文件和 ASCII(也称纯文本文件)。图形文件及文字处理程序等计算机程序都属于二进制文件。这些文件含有特殊的格式及计算机代码。ASCII 则是可以用任何文字处理程序阅读的简单文本文件,由一些字符的…

音频帧AVFrame::linesize大于实际值的问题记录

在解析AAC的音频流时,发现AVFrame::linesize[0]大小为8192。 但是AVFrame::nb_samples为1024,AVFrame::format类型为AV_SAMPLE_FMT_FLTP,即每个采样是4字节。 那么此音频帧中的数据应该为4096,和AVFrame::linesize[0]不相等。 …

vscode生成vue模板快捷键_vs code 快速生成vue 模板

1.使用快捷Ctrl Shift P唤出控制台,然后输入snippets并选择。(或 文件>首选项>用户代码片断里面,输入 vue.json ,然后回车 )(或 file > Preferences > User Snippets,然后回车)2.接着输入vue,选择vue-ht…

【转】!!c#文件系统操作类继承关系图

自己总结的,给大家参考一下,

FFmpeg资料

ffmpeg内存模型及AVPacket和AVFrame API解释

php elasticsearch 获取索引所有文档_Elasticsearch客户端主要方法的使用规则

安装1.在 composer.json 文件中引入 elasticsearch-php:{ "require": { "elasticsearch/elasticsearch": "~6.0" }}2.用 composer 安装客户端:curl -s http://getcomposer.org/installer | phpphp composer.…

【转】如何用好SVN的Branch

转自: http://www.cnblogs.com/lovebanyi/archive/2012/06/13/2547525.html 在SVN里面我们一般会创建出三个文件夹 Trunk(主干) Branch(分支) TAG(标签) 在我们项目一开始的时候我们会将代码…

python数据爬取并可视化_Python爬取数据并实现可视化代码解析

这次主要是爬了京东上一双鞋的相关评论:将数据保存到excel中并可视化展示相应的信息主要的python代码如下:文件1#将excel中的数据进行读取分析import openpyxlimport matplotlib.pyplot as pit #数据统计用的wkopenpyxl.load_workbook(销售数据.xlsx)she…

【转】SVN trunk(主线) branch(分支) tag(标记) 用法详解和详细操作步骤

转自:https://monday.blog.csdn.net/article/details/51122637 一:使用场景: 假如你的项目(这里指的是手机客户端项目)的某个版本(例如1.0版本)已经完成开发、测试并已经上线了,接…

纠正一个可能的错误翻译—交叉编译

交叉编译,是英文 Cross Compilation 的中文翻译。 下面摘自百度: 交叉编译是在一个平台上生成另一个平台上的可执行代码。 由于嵌入式设备的性能局限,往往不能通过本机编译得到所需软件的可执行程序。因此,以Linux为主机操作系统…

jar 退出run_Java终止线程的三种方式

停止一个线程通常意味着在线程处理任务完成之前停掉正在做的操作,也就是放弃当前的操作。在 Java 中有以下 3 种方法可以终止正在运行的线程:使用退出标志,使线程正常退出,也就是当 run() 方法完成后线程中止。使用 stop() 方法强…

【转】人工智能教程-前言

前言 大家好!欢迎来到我的网站! 人工智能被认为是一种拯救世界、终结世界的技术。毋庸置疑,人工智能时代就要来临了,科幻电影中的场景将成为现实,未来已来! 我很庆幸。十四年前就认定了人工智能专业&…

golang 包含 数组_Golang数组类型

数组数组是指一系列同一类型数据的集合。数组中包含的每个数据被称为数组元素(element),一个数组包含的元素个数被称为数组的长度。1. 声明方法[32]byte //长度为32的数组[2*N] struct {x, y int32} //复杂类型数组[100]*float64 //指针数组[3][5]int //二维数组[2]…

【转】人工智能-1.1.1 什么是神经网络

1.1.1 什么是神经网络 什么是人工智能?通俗来讲,就是让机器能像人一样思考。这个无需解释太多,因为通过各种科幻电影我们已经对人工智能很熟悉了。大家现在感兴趣的应该是——如何实现人工智能? 从1956年夏季首次提出“人工智能…

【V4L2】学习资料

预备知识 V4L2,即Linux视频设备内核驱动。 参考文章 v4l2的学习建议和流程解析Linux V4L2学习高通msm-V4L2-Camera驱动浅析5-buffer00_video_decode (video decode):此内容为英伟达Jetson的Demo文档手册,有条件的可以结合Jetson的代码阅读…

解决margin塌陷的问题_解决margin塌陷与margin合并(margin)清除浮动问题

**1、margin塌陷**问题:垂直方向的父子关系的盒子使用不当会产生margin塌陷。给子级设置margin-top时,他不会相对父级一起动,只有他的margin超过父级的margin时,才会生效,但会带着父级一起动(作者总结,官方…

【转】人工智能-1.2.2 神经网络是如何进行预测的

上一篇文章中我们已经知道了如何将数据输入到神经网络中。那么神经网络是如何根据这些数据进行预测的呢?我们将一张图片输入到神经网络中,神经网络是如何预测这张图中是否有猫的呢?? 这个预测的过程其实只是基于一个简单的公式&a…

js 根据公历日期 算出农历_一招教会你公历换算成农历,要不要试试看

古代的历法是干支纪年,俗称农历或阴历,现在我们都统一采用公历的阿拉伯数字纪年。因此,就存在着一个历法的换算问题。当然,我们可以查历书就直接知道了,但是这个方法并不一定方便。现在告诉大家一个简单的口诀&#xf…

【转】C# HMAC Sha1 生成签字

最近因为工作的需要,开始接触腾讯云,在调用CMQ服务时发现官方提供的SDK只有基于.Net Framework的,而现在做.net项目的谁不是用.net core啊。好吧,既然没有官方的SDK,只能自己写服务来调用Api了。遇到的第一个麻烦点的事…