前端实现一个PPT功能模块脚手架
需求背景
公司有个使用 javaScript
来编写PPT的需求,通过 pptxgenjs
这个库可以实现,但是有一个问题,那就是当我为A需求编写了一套PPT代码之后,然后此时B需求又需要一个PPT,样式及内容上和A需求大差不差,此时还觉得可以让这两个PPT共用同一份代码,然后通过判断区分一下即可,直到C需求来了,C又跟B大差不差,最后得知,公司还打算搞个D/E/F等等出来。
其实在做B需求的时候,我就发现,这玩意不可以像 vue
组件那样复用,必须把它们相互独立起来,当然,一些小的静态组合还是可以抽离出来做组件的,但是页面必须独立,哪怕样式/逻辑一模一样。
也就是说,假设A需求有一个A1页面,然后这个A1页面在B需求中也是需要的,并且没有任何改动,我们不能直接在B中导入A1,而是要复制一份A1,作为B1,然后在B中导入B1。
后来做到C需求的时候,因为这些PPT页面都挺多的,而我又把一个页面拆分成一个 .js
文件,也就是说,我需要复制十几个文件,然后还要重命名,太麻烦了,可不可以像NextJS那样,在终端输入 nest g controller cats
,就可以自动生成对应的目录以及代码文件呢?
因此自己写了个功能模块脚手架 bluewhale-ppt-cli
来实现这个需求。
实现过程
一、初始化项目
新建一个 bluewhale-ppt-cli
目录,然后进入目录,执行 npm init -y
,生成 package,json
文件。
打开 package,json
文件,将 author
字段填写完整。
然后,在目录中新建 bin
目录,并且在 bin
目录下新建 index.js
文件,在 index.js
文件写下如下代码
#!/usr/bin/env node
// 注意,上面这行代码必须在开头第一行
require('../src/index.js')
#!/usr/bin/env node
是为了解决不同用户 node
安装路径不同的问题,/usr/bin/env
就是告诉系统可以在PATH目录中查找,让系统动态的去查找 node
来执行脚本文件。
然后,我们要在 package.json
文件中,添加如下代码
"bin":{
"bw-ppt":"bin/index.js"
}
这里的 bw-ppt
就是我们要在终端输入的自定义命令,当我们输入 bw-ppt
的时候,它就会执行 bin/index.js
中的代码。
此时,项目目录结构如下
根据上面的代码,不难知道,我们还需要创建一个 src
目录以及 src
目录下的 index.js
文件,之所以这样做,是为了将代码分模块,更方便管理,如果你狠一点,可以把全部代码都写在 bin/index.js
里面,创建完成后,我们在 src/index.js
文件中写入一行代码 console.log('hello cli')
,保存。
然后在项目根目录打开终端,执行命令 npm link
,进行软连接,然后在终端中输入 bw-ppt
,回车,出现 hello cli
表示第一步基本完成了。
二、安装依赖
这一步需要使用 npm install
命令进行一些依赖包的安装。
commander
可以自定一些终端命令,当我们在终端中输入自定义命令的时候就会去执行相应的操作。
我们最后希望做到的是,在终端输入 bw-ppt create pptName
的时候,想要代码理解 create pptName
这一部分,就要用到这个包了。
安装命令: npm i commander
chalk
可以美化终端的输出,但是要注意的是,chalk5.0
版本不再支持 require()
导入,即下面的代码会报错
const chalk = require('chalk')
有两种解决方法,一种是安装 chalk4.0
# 先卸载当前版本
npm uninstall chalk
# 安装4.0版本
npm install chalk@4
另一种方法则是修改整个项目的 EMS
规范,在 package.json
文件中,将 type
字段的值指定为 module
{
"name": "ppt-cli",
"type":"module"
...
}
inquirer
这个包可以让我们在终端中对用户进行询问,并且记录用户选择的结果,用它是因为考虑到,到时候会根据终端输入 pptName
在相应目录下创建同名文件夹,那必然会遇到存在同名文件夹的情况,这个时候就可以使用这个包来询问用户是否需要覆盖这个目录了。
安装命令: npm i inquirer@8
该包8.0后面的版本不再支持require导入
figlet
该包可以在终端中输出logo,用上它主要是为了排面
安装命令: npm i figlet
ora
该包的作用是在终端输出加载动画,后面我们会把模板代码放到代码仓库,然后下载的过程中就需要用到这个加载动画了。
安装命令: npm i ora@5
该包5.0之后的版本不支持require导入
fs-extra
该包是 fs
模块的一个拓展,提供了很多API,继承了 fs
所有方法
安装命令: npm i fs-extra
download-git-repo
该包的作用是下载远程模板,就是从仓库中拉取代码的意思
安装命令: npm i download-git-repo
命令合集
npm install commander chalk@4 inquirer@8 figlet ora@5 fs-extra download-git-repo
三、代码实现
前面的准备工作完成之后,就开始具体实现了,首先是 src/index.js
文件中的代码
index.js
const { program } = require('commander');
const chalk = require('chalk')
const figlet = require('figlet')
program
.command('create <name>')
.description('创建一个新的PPT')
.action((PPTName) => {
console.log('\r\n' + chalk.white.bgBlueBright.bold(figlet.textSync('bluewhale-ppt', {
font: 'Standard',
horizontalLayout: 'full',
verticalLayout: 'default',
width: 180,
whitespaceBreak: true,
})) + '\r\n');
})
program.parse();
上面的代码实现的功能就是,当我们在终端中输入 bw-ppt create pptName
的时候,控制台出现一个大大的logo,如下
此处没什么实际作用,主要是好看。
然后我们在 index.js
的同级新建一个 create.js
文件,这个文件默认会导出一个函数,因此我们在 index.js
中引入它,如下
const create = require('./create.js')
program
.command('create <name>')
.description('创建一个新的PPT')
.action((PPTName) => {
// ....
create(PPTName);
})
到这里,就没有 index.js
这个文件的事情了,我们来到 crate,js
文件
create.js
这个文件默认导出一个匿名函数,函数刚开始执行的时候,会调用 isInstallPptxGenJS
函数来检查用户是否安装了 pptxgenjs
这个依赖库,如果没有安装,则提醒用户安装,然后退出执行。
如果用户安装了所需要的依赖库,就继续判断是否存在同名目录,存在的话则询问用户是否覆盖,不存在的话则直接拉取代码。
const path = require('path')
const fse = require('fs-extra')
const inquirer = require('inquirer')
const chalk = require('chalk')
const download = require('./download.js')
module.exports = function (name) {
// 判断是否已经安装pptxgenjs库
if (isInstallPptxGenJS() !== 'installed') {
// 未安装时执行的逻辑
return
}
// 当前命令行执行的目录
const cwd = process.cwd();
// 需要创建的目录
const targetPath = path.join(cwd, '/src/blueWhalePPT', name)
// 目录是否存在
if (fse.existsSync(targetPath)) {
inquirer.prompt([{
name: 'action',
type: 'list',
message: '目录已存在,请选择:',
choices: [
{ name: '覆盖', value: 'overwrite' },
{ name: '取消', value: false }
]
}]).then(({ action }) => {
// 用户选择了取消-即不覆盖,所以终止运行
if (!action) return
// 用户选择了覆盖
if (action === 'overwrite') {
// 移除已经存在的目录
fse.remove(targetPath).then(() => {
download(targetPath)
})
}
})
} else {
download(targetPath)
}
return
}
通过上面的代码,我们可以知道,我们还需要实现一个 isInstallPptxGenJS
函数以及在同级目录下新增一个 download.js
文件,这样 create.js
文件才能正常的执行。
isInstallPptxGenJS
/**
* 判断当前用户是否已经安装了PptxGenJS库
* 未安装则询问是否安装,不安装则退出
* 已安装则输出版本号
*/
function isInstallPptxGenJS() {
const cwd = process.cwd();
const packageDir = cwd + '/package.json'
if (fse.existsSync(packageDir)) {
const { dependencies } = require(packageDir)
// 判断是否安装PptxGenJS
if ('pptxgenjs' in dependencies) {
const version = dependencies['pptxgenjs']
console.log(chalk.green.bold(`已安装pptxgenjs:${version}`))
return 'installed'
} else {
const str1 = `未安装pptxgenjs`
const str2 = `请执行 ${chalk.cyan(`npm install pptxgenjs --save`)} or ${chalk.cyan(`yarn add pptxgenjs`)} 进行安装`
const str3 = `更多详情请查阅PptxGenJS官方文档:https://gitbrent.github.io/PptxGenJS/`
console.log(chalk.redBright.bold(`${str1}\r\n${str2}\r\n${str3}`))
return `nonexistence pptxgenjs` // 未安装pptxgenjs库
}
} else {
const str1 = `未在 ${chalk.green.bold(cwd)} 目录下找到package.json文件`
const str2 = `[] 请检查执行路径是否正确`
const str3 = `[] 请执行 ${chalk.cyan(`npm init`)} 命令生成package.json文件`
console.log(chalk.redBright.bold(`${str1}\r\n${str2}\r\n${str3}`))
return 'package.json not found' // 未找到package.json文件
}
}
上面这个函数,会先检查用户当前执行命令的路径下是否存在 package.json
文件,存在导入 package.json
文件,然后判断里面的 dependencies
字段中是否存在 pptxgenjs
这个字段,存在则输入版本号,不存在则提醒用户安装。
download.js
这个文件默认导出一个匿名函数,用于从远端仓库中下载模板。
const download = require("download-git-repo")
const ora = require("ora")
module.exports = function (targetDir) {
const spinner = ora('远端仓库开始下载...')
spinner.start()
// 下载远端模板
const repoUrl = 'direct:https://gitee.com/XXX/YYY.git'
const downloadConfig = {
clone: true
}
download(repoUrl, targetDir, downloadConfig, (err) => {
if (err) {
spinner.fail('[ 远端仓库下载失败 ]')
console.log(err)
} else {
spinner.succeed('[ 远端仓库下载成功 ]')
}
})
}
我这里选择的是把模板文件存在码云上,可以根据实际需求更改拉取模板的仓库地址 repoUrl
即可。
上面是模板代码的目录结构。
四、本地测试
在终端中输入命令 bw-ppt create myPPT
,回车执行
然后可以看到,在 src
目录下多出了一个 bluewhalePPT
目录,然后该目录下还有一个 myPPT
目录,且里面的文件跟我们上面在码云中看到的一模一样,说明我们这个功能脚手架是可以的了。
五、发布到npm
接下来我们要把这个东西发布到 npm
上去,这样别人执行 npm i bluewhale-ppt-cli
后,在终端输入 bw-ppt create <PPTName>
就可以达到同样的效果了。
首先,终端执行 npm login
,输入用户名,密码,登录到 npm
然后登录成功后,输入 npm publish
,执行发布操作
看到 + 包名@版本号
出现,说明发布成功。正常来说,还会收到邮件的通知。
发布的时候要注意
- 出现问题直接百度
- 每次修改代码之后记得修改版本号,然后重新发布
npm publish
六、项目实测
这次新建一个项目,来测试一下这个脚手架能不能用
过程跟简单,新建一个目录,执行 npm init -y
,然后执行 npm i bluewhale-ppt-cli -D
和 npm i pptxgenjs
,然后在终端输入 bw-ppt create myPPT
很棒,完成。
后续计划
上面只是简单的实现了这个功能脚手架的基本功能,后续应该要加上模板选择,然后还有文件的名称应该跟终端输入的一样,然后还有 common.js
这种文件是每个PPT公用的文件,要想办法提取出来,而不是每个目录创建一个,然后还有代码内容也要控制起来。
反正就是给这个脚手架加入更多的参数和更多的功能。
转载自:https://juejin.cn/post/7212164132795039800