const inquirer = require('inquirer') // npm i inquirer -D inquirer.prompt([ { name: 'projectName', message: '请输入项目名称' } ]).then(answers => { console.log(`你输入的项目名称是:${answers.projectName}`) })
prompt() 接受一个 的数据,在用户与终端交互过程中,将用户的输入存放在一个 中,然后返回一个 Promise ,通过 then() 获取到这个答案对象。so easy!
接下来继续对macaw-init.js进行完善。
// ... const inquirer = require('inquirer') const list = glob.sync('*') let next = undefined if (list.length) { if (list.filter(name => { const fileName = path.resolve(process.cwd(), path.join('.', name)) const isDir = fs.stat(fileName).isDirectory() return name.indexOf(projectName) !== -1 && isDir }).length !== 0) { console.log(`项目${projectName}已经存在`) return } next = Promise.resolve(projectName) } else if (rootName === projectName) { next = inquirer.prompt([ { name: 'buildInCurrent', message: '当前目录为空,且目录名称和项目名称相同,是否直接在当前目录下创建新项目?' type: 'confirm', default: true } ]).then(answer => { return Promise.resolve(answer.buildInCurrent ? '.' : projectName) }) } else { next = Promise.resolve(projectName) } next && go() function go () { next.then(projectRoot => { if (projectRoot !== '.') { fs.mkdirSync(projectRoot) } return download(projectRoot).then(target => { return { projectRoot, downloadTemp: target } }) }) }
如果当前目录是空的,并且目录名称和项目名称相同,那么就通过终端交互的方式确认是否直接在当前目录下创建项目,这样会让脚手架更加人性化。
前面提到,新项目的名称、版本号、描述等信息可以直接通过终端交互插入到项目模板中,那么再进一步完善交互流程。
// ... // 这个模块可以获取node包的最新版本 const latestVersion = require('latest-version') // npm i latest-version -D // ... function go () { next.then(projectRoot => { if (projectRoot !== '.') { fs.mkdirSync(projectRoot) } return download(projectRoot).then(target => { return { name: projectRoot, root: projectRoot, downloadTemp: target } }) }).then(context => { return inquirer.prompt([ { name: 'projectName', message: '项目的名称', default: context.name }, { name: 'projectVersion', message: '项目的版本号', default: '1.0.0' }, { name: 'projectDescription', message: '项目的简介', default: `A project named ${context.name}` } ]).then(answers => { return latestVersion('macaw-ui').then(version => { answers.supportUiVersion = version return { ...context, metadata: { ...answers } } }).catch(err => { return Promise.reject(err) }) }) }).then(context => { console.log(context) }).catch(err => { console.error(err) }) }
下载完成后,提示用户输入新项目信息。当然,交互的问题不仅限于此,可以根据自己项目的情况,添加更多的交互问题。inquirer.js强大的地方在于,支持很多种交互类型,除了简单的 input ,还有 confirm 、 list 、 password 、 checkbox 等,具体可以参见项目的 。
然后,怎么把这些输入的内容插入到模板中呢,这时候又用到另外一个简单但又不简单的工具包——metalsmith。
使用metalsmith处理模板
引用官网的介绍:
An extremely simple, pluggable static site generator.
它就是一个静态网站生成器,可以用在批量处理模板的场景,类似的工具包还有Wintersmith、 Assemble 、Hexo。它最大的一个特点就是 EVERYTHING IS PLUGIN ,所以,metalsmith本质上就是一个胶水框架,通过黏合各种插件来完成生产工作。
给项目模板添加变量占位符