脚手架的基础
首先需要新建一个package.json文件,并在配置里添加"bin"属性,"bin"的值为文件路径。
PS:如果你想自定义CLI启动的名字,可以给bin一个对象,键值就是你启动输入的名字,不过你开发项目的时候要注意不要跟其他的CLI名称重复了。不自定义名称的话,就是输入项目的名称即可。本次演示我就不取自定义名称了,想自定义名称的小伙伴记得启动项目时,需要用自定义的名称(如下图)。
CLI应用的入口文件必须要有 #!/usr/bin/env node 作为文件头,如果使用的是Linux和macOS系统的话,还需要将此文件的读写权限改为755。
接着我们通过yarn link的方式将此模块link到全局 ,来看看这个项目的能不能跑起来。
可以看到打出了log的信息,就代表项目正常执行了,脚手架的基础已经建好了。
PS:这里如果执行不了,可能是环境变量配置有问题,你可以用'yarn global bin'去查看你的yarn全局Bin的地址,并加到环境变量中就可以了。
脚手架的工作过程
接下来,我们来编写脚手架的工作过程,其过程分为两点:1.通过命令行交互询问用户问题;2.根据用户回答的结果生成文件。
通过命令行交互询问用户问题
在node里想使用命令行对用户发起询问,需要使用‘inquirer’这个模块,所以需要先安装这个模块,可以用yarn add来加载。
yarn add inquirer
安装好后,将quirer引入cli,inquirer有个prompt方法,可以通过传递相关配置,用这个方法来对用户进行询问,询问完后,通过‘.then’来获得用户的输入值。
#!/usr/bin/env node // console.log('cli working') const inquirer = require('inquirer'); inquirer.prompt([ { type: 'input', //指定问题的输入方式 name: 'name', //指定问题返回值的键名 message: 'Project name?' //给用户的提示 } ]).then( answer => { console.log(answer); });
我们回到控制台看看能否进行询问并返回。
我们可以看到询问和返回都是没有问题的,我们的询问这一步就完成了
根据用户回答的结果生成文件
现在我们需要根据回答生成文件,生成的文件需要模板,所以我们要先建立模板文件,模板文件可以使用<%= name %>来填入刚才回答的问题,如果你刚刚在prompt中name的value值用的是别的,这里就把name换成你自己写的value值即可。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title><%= name %></title> </head> <body> </body> </html>
在生成模板文件之前,我们一般先要把模板的根目录和目标路径给确定下来
#!/usr/bin/env node // console.log('cli working') const inquirer = require('inquirer'); const path = require('path'); inquirer.prompt([ { type: 'input', //指定问题的输入方式 name: 'name', //指定问题返回值的键名 message: 'Project name?' //给用户的提示 } ]).then( answer => { // console.log(answer); // 模板目录 const tmplDir = path.join(__dirname, '../temp') // 目标目录 const destDir = process.cwd() });
在确定了路径之后,我们再通过fs去读取模板目录下的目标文件,再将读取到的文件通过模板引擎渲染文件并转化到目标路径,这里需要通过'yarn add ejs'下载模板引擎。
#!/usr/bin/env node // console.log('cli working') const inquirer = require('inquirer'); const path = require('path'); const fs = require('fs'); const ejs = require('ejs') inquirer.prompt([ { type: 'input', //指定问题的输入方式 name: 'name', //指定问题返回值的键名 message: 'Project name?' //给用户的提示 } ]).then( answer => { // console.log(answer); // 模板目录 const tmplDir = path.join(__dirname, '../temp') // 目标目录 const destDir = process.cwd() // 将模板下的文件全部转换到目标目录 fs.readdir(tmplDir, (err, files) => { if (err) throw err files.forEach(file => { // 通过模板引擎渲染文件 ejs.renderFile(path.join(tmplDir, file), answer, (err, result) => { if (err) throw err // 将结果写入目标文件路径 fs.writeFileSync(path.join(destDir, file), result) }) }) }) });
完成之后,这个脚手架就完成搭建了!
尝试使用新搭建的脚手架
我们建立一个新的目录,并在下面去执行我们的脚手架命令
可以看到新建的文件夹里生成了一个html文件,我们打开看看这个文件是不是按照我们的模板渲染生成的
可以看到<title></title>标签里的name就是我们输入的demo,到此我们的脚手架就成功完成了!