vue|构建一个属于own的vue-cli💥💥💥

180 阅读7分钟

什么是脚手架

一个命令行工具

根据交互式终端动态生成项目结构和配置文件

通过命令行去完成那些重复性的工作,不需要在粘贴来粘贴去

开发一个通用的脚手架,去处理重复构建自己项目结构的这样一个事情

注意:vue-cli是一个整合了webpack+vue的脚手架,所以才会有一个面试题叫做:你有没有自己搭建一个vue项目? 这个知识点我回头会补充一下的。

实现自己的脚手架的思路

项目放在github上

用户通过命令行交互去下载不同的模板

经过模板引擎渲染去定制项目模板

模板变动,只需要更新模板,不需要用户更新脚手架

初始化-把脚本映射成命令

1、 初始化一个文件夹,文件夹中新建一个index.js,index.js的内容如下

#!/usr/bin/env node
console.log("这是使用自己创建的命令kvon-cli生成的代码");

文件头部的那一句话的含义:

使用node开发命令行工具去执行一个js脚本,必须在头部加上这一句声明

加上之后,在终端还是只能使用node index.js 执行这个文件,接下来就要编写自己的命令行了

执行npm init -y 生成package.json文件,在文件中进行配置

{
	"name": "kvon-cli_01",
	"version": "1.0.0",
	"description": "",
	"main": "index.js",
	"scripts": {
		"test": "echo \"Error: no test specified\" && exit 1"
	},
	"keywords": [],
	"author": "",
	"license": "ISC",
	"bin": {
		"kvon-cli-log": "index.js"
	}
}

bin这key是我配置的,首先bin是一个对象,我给了一个key:kvon-cli-log,是我的命令行;对应的值,就是这个命令行要执行的文件

此时在尝试使用命令行执行index.js文件,发现还是不能行,不过这一步就是把我们的js脚本映射成命令行,这一步做到了

image.png

还差的一步就是将这个命令行映射到全局,执行npm link,就可以通过命令行运行index.js文件了

image.png

思考💡:不过我发现我执行npm link之后,在我的文件夹下出现了package-lock.json文件,这个我也不知道我为什么,留作一个思考题把

使用commander解析命令行参数

以vue2为例,vue2提供的几个常用的命令行参数

image.png

所以我也打算做几个自己脚手架的参数

kvon -- help | -h
kvon -- version | -V
kvon list
kvon init <template-name> <project-name>

node原生提供了获取命令行参数的方法

// 原生获取命令行参数的方式
console.log(process.argv)

但是原生的老师就提了提,没教我,哈哈哈哈,那我们就直接用现成的吧

首先安装

npm i commander

访问网页github.com/tj/commande… ,利用现成的commander去编写自己的命令

// 代写在index.js下
#!/usr/bin/env node
const { program } = require('commander')
program.version('0.8.0')
program.parse(process.argv)

首先是实现了-v的命令,我们可以看一下

image.png

查看帮助文档

image.png

也就是说,-h| --help是默认提供我们的命令,因为我们没有写任何代码,他就可以运行这个命令,通过结果看出我们现在完成了

kvon -- help | -h
kvon -- version | -V

接下来就完成剩下的2条了,list和init命令

init是初始化我们项目的,所以init首先要定义一个模板、然后是项目名称

正如我们使用vue-cli初始化项目时,我们输入的一个命令

vue init webpack my-vue-demo

webpack 是一个模板的名称,my-vue-demo是自己定义的项目名称,可以随便写

list 是列出我们可用所有模板

经过以上分析,我们就编写出代码

const { program } = require('commander')
program.version('0.8.0')

program
	.command('init <template> <project>')
	.description('初始化项目模板')
	.action(function (env, options) {
		console.log(env, options)
	})
program
	.command('list')
	.description('查看所有可用模板')
	.action(() => {
		console.log(
            `xxxx ---> 模板1
            
            xxxx ----> 模板2
            
            xxxx ----> 模板3`
		)
	})

program.parse(process.argv)

image.png

准备模板

既然要基于模板去开发自己的项目,所以前提就是要设计自己的模板,现在github上搞一个几个简单的,测试着,回头在学习怎么设计自己的项目模板

image.png

既然模板已经存在了,就在list的命令中,获取所有模板了

const { program } = require('commander')
program.version('0.8.0')

const templates = {
	'kvon-a': {
		url: 'https://github.com/Kvon917/kvon-a',
		description: '模板a',
	},
	'kvon-b': {
		url: 'https://github.com/Kvon917/kvon-b',
		description: '模板b',
	},
	'kvon-c': {
		url: 'https://github.com/Kvon917/kvon-c',
		description: '模板c',
	},
}
program
	.command('init <template> <project>')
	.description('初始化项目模板')
	.action(function (env, options) {
		console.log(env, options)
	})
program
	.command('list')
	.description('查看所有可用模板')
	.action(() => {
		for (key in templates) {
			console.log(`${key} ---> ${templates[key].description}`)
		}
	})

program.parse(process.argv)

通过init将模板下载到本地

需要借助第三方工具,安装

npm install download-git-repo 

安装完成之后,就完成我们init命令的代码

第一步:需要导入下载的download-git-repo

const download = require('download-git-repo')

第二步,在定义的对象中,丰富下载地址

const templates = {
	'kvon-a': {
		url: 'https://github.com/Kvon917/kvon-a',
		downloadUrl: 'http://github.com:Kvon917/kvon-a#master',
		description: '模板a',
	},
	'kvon-b': {
		url: 'https://github.com/Kvon917/kvon-b',
		downloadUrl: 'http://github.com:Kvon917/kvon-b#master',
		description: '模板b',
	},
	'kvon-c': {
		url: 'https://github.com/Kvon917/kvon-c',
		downloadUrl: 'http://github.com:Kvon917/kvon-c#master',
		description: '模板c',
	},
}

第三步,使用download

program
	.command('init <template> <project>')
	.description('初始化项目模板')
	.action(function (templateName, projectName) {
		const { downloadUrl } = templates[templateName]
		// download 第一个参数是 下载地址 第二个参数是项目名称
		download(downloadUrl, projectName, (err) => {
			if (err) {
                console.log(err);
				console.log('下载失败')
			} else {
				console.log('下载成功')
			}
		})
	})

最后到了验证阶段,我们可以使用init命令,初始化项目

image.png

以向导的方式初始化项目

我们常用的vue初始化项目的时候,会出现一些命令行的交互,比如问你要不要安装XXX呀,要不要使用XXX标准呀,等一类的问题。

image.png

现在就来实现这个功能

首先我们在github上处理一下我们的package.json,新建一个package.json,内容写成模板引擎的模式

{
    "name": "{{name}}",
    "version": "1.0.0",
    "description": "{{description}}",
    "main": "index.js",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "{{author}}",
    "license": "ISC",
    "bin": {
        "kvon": "index.js"
    },
    "dependencies": {
        "commander": "^9.4.1",
        "download-git-repo": "^3.0.2"
    }
}

接下就是处理了思路了

1、能够读取package.json文件

2、以向导的方式获取用户输入的值

3、使用模板引擎将获取的值解析到package.json

4、解析完成,把结果重新写入到package.json

安装模板引擎的插件

npm i handlebars

安装向导的插件

npm i inquirer

安装完成就可以编写index.js文件了

const { program } = require('commander')
const download = require('download-git-repo')
const handlebars = require('handlebars')
const inquirer = require('inquirer')
const fs = require('fs')
program.version('0.8.0')

const templates = {
	'kvon-a': {
		url: 'https://github.com/Kvon917/kvon-a',
		downloadUrl: 'http://github.com:Kvon917/kvon-a#master',
		description: '模板a',
	},
	'kvon-b': {
		url: 'https://github.com/Kvon917/kvon-b',
		downloadUrl: 'http://github.com:Kvon917/kvon-b#master',
		description: '模板b',
	},
	'kvon-c': {
		url: 'https://github.com/Kvon917/kvon-c',
		downloadUrl: 'http://github.com:Kvon917/kvon-c#master',
		description: '模板c',
	},
}
program
	.command('init <template> <project>')
	.description('初始化项目模板')
	.action(function (templateName, projectName) {
		const { downloadUrl } = templates[templateName]
		// download 第一个参数是 下载地址 第二个参数是项目名称
		download(downloadUrl, projectName, (err) => {
			if (err) {
				return console.log('下载失败')
			}
			// 下载成功
			inquirer
				.prompt([
					{
						type: 'input',
						name: 'name',
						message: '请输入项目名称',
					},
					{
						type: 'input',
						name: 'description',
						message: '请输入项目简介',
					},
					{
						type: 'input',
						name: 'author',
						message: '请输入作者信息',
					},
				])
				.then((answers) => {
					// answers获取的是向导的输入值
					const packagePath = `${projectName}/package.json`
					const packageContent = fs.readFileSync(packagePath, 'utf-8')
					//利用handlebars 将模板字段编译完成
					const packageResult =
						handlebars.compile(packageContent)(answers)
					fs.writeFileSync(packagePath, packageResult)
					console.log('初始化模板成功')
				})
		})
	})
program
	.command('list')
	.description('查看所有可用模板')
	.action(() => {
		for (key in templates) {
			console.log(`${key} ---> ${templates[key].description}`)
		}
	})

program.parse(process.argv)

其中遇到了报错,就是一段

image.png

我的解决方案是根据inquirer的官网,安装固定版本,不然跑不起来

npm install --save inquirer@^8.0.0

最后成功解决相关问题

image.png

image.png

视觉优化-增加下载效果

下载插件,我装的指定版本,最新版本报错

npm i ora@3.0.0  

引入

const ora = require('ora')

使用

program
	.command('init <template> <project>')
	.description('初始化项目模板')
	.action(function (templateName, projectName) {
		// 下载之前的提示
		const spinner = ora('正在下载模板...').start()
		const { downloadUrl } = templates[templateName]
		// download 第一个参数是 下载地址 第二个参数是项目名称
		download(downloadUrl, projectName, (err) => {
			if (err) {
                        // 下载失败
				spinner.fail()
				return
			}
			// 下载成功
			spinner.succeed()
			inquirer
				.prompt([
                                ........

视觉优化-增加文字颜色和对钩等

npm i chalk@2.4.1
npm i log-symbols@2.2.0

logSymbol处理图标、chalk处理颜色

    ........
    const packageResult =
            handlebars.compile(packageContent)(answers)
    fs.writeFileSync(packagePath, packageResult)
    console.log(
            logSymbol.success,
            chalk.yellow('初始化模板成功')
    )
})

image.png

npm发包

  1. 打开npm官网
  2. 注册一个npm账号
  3. 在npm检查是否有重复包名
  4. 将package.json中的name修改为发布到npm上的包名
  5. 打开控制台,执行npm login,在控制台登录
  6. 登陆成功后,在项目下执行npm publish
  7. 发布成功
  8. 可自行测试