1.实现自定义指令
-
1.通过
npm init --y
初始化一个node项目 -
2.创建一个JS文件, 并且在JS文件的头部通过
#! /usr/bin/env node
告诉系统将来这个文件需要在 NodeJS环境 下执行 -
3.在
package.json
中新增bin的key, 然后这个key的取值中告诉系统需要新增什么指令, 这个指令执行哪个文件"bin": { "nue-cli": "./bin/index.js" }
-
4.通过
npm link
将本地的包链接到全局
2.编码规范检查
1.安装
npm install eslint
2.初始化eslint配置
npx eslint --init
选择第三个:检查语法,发现问题,统一编码规范
后续的操作按照项目的内容进行选择…
初始化配置操作执行后,生成.eslintrc.js
文件
3. 添加帮助和版本号
1.process.argv获取传递的参数
if(process.argv[2] === '--help'){
// 输出帮助文档
}else if(process.argv[2] === '--version'){
// 输出当前版本号
}
2.使用第三方的工具包
commander包
能够快速的处理自定义指令传递进来的参数
安装
npm install commander
只需要将传递进来的参数直接传递给parse方法, 那么commander包就自动帮我们实现了–help
const program = require('commander');
program.parse(process.argv)
sue-cli --help
只需要在调用parse方法之前先调用version方法, 告诉它当前的版本号, 那么commander包就自动帮我们实现了–version
program.version('1.0.0').parse(process.argv);
动态version
const { version } = require("../package.json")
// console.log('version', version)
module.exports = {
version
};
const program = require('commander');
const { version } = require('./const')
program.version(version).parse(process.argv);
sue-cli --version
–help和–version是所有工具包通用的
4.添加自定义指令
4.1 自定义指令
不确定、非通用并且并非每个包都有的指令需要自己去实现
const program = require('commander');
program
.command('create') // 指令名称
.alias('c') // 指令简写
.description('create a new project powered by vue-cli-service') // 指令描述
.action(()=>{ // 指令具体的操作
console.log('创建一个Vue项目');
})
–help的时候想要输出一个示例
监听–help
program
.command('create') // 指令名称
.alias('c') // 指令简写
.description('create a new project powered by vue-cli-service') // 指令描述
.action(()=>{ // 指令具体的操作
console.log('创建一个Vue项目');
})
program.on('--help',()=>{
console.log('Example:');
console.log(' sue-cli create <app-name> ');
})
4.2 自定义多条指令
const program = require('commander');
const commandMap = {
create: {
alias:'c',
description:'create a new project powered by vue-cli-service',
example:'sue-cli create <app-name>'
},
add: {
alias:'a',
description:'install a plugin and invoke its generator in an already created project',
example:'sue-cli add [options] <plugin> [pluginOptions]'
},
// 不存在的使用通配符
'*':{
alias:'',
description:'',
example:''
}
}
// nodeJS中Reflect.ownKeys获取对象的key
// Reflect.ownKeys(commandMap) [create, add, *]
Reflect.ownKeys(commandMap).forEach(key=>{
const value = commandMap[key]
program
.command(key) // 指令名称
.alias(value.alias) // 指令简写
.description(value.description) // 指令描述
.action(()=>{ // 指令具体的操作
console.log('创建一个Vue项目');
if(key === '*'){
console.log('指令不存在');
}else {
console.log(value.description);
}
})
})
program.on('--help',()=>{
console.log('Example:');
// 自定义指令相关的示例
Reflect.ownKeys(commandMap).forEach(key=>{
const value = commandMap[key]
console.log(` ${value.description} `);
})
})
5.处理不同的指令
action方法中处理自定义指令
const program = require('commander');
const { version } = require('./const')
const path = require('path')
const commandMap = {
create: {
alias:'c',
description:'create a new project powered by vue-cli-service',
example:'sue-cli create <app-name>'
},
add: {
alias:'a',
description:'install a plugin and invoke its generator in an already created project',
example:'sue-cli add [options] <plugin> [pluginOptions]'
},
// 不存在的使用通配符
'*':{
alias:'',
description:'',
example:''
}
}
// nodeJS中Reflect.ownKeys获取对象的key
// Reflect.ownKeys(commandMap) [create, add, *]
Reflect.ownKeys(commandMap).forEach(key=>{
const value = commandMap[key]
program
.command(key) // 指令名称
.alias(value.alias) // 指令简写
.description(value.description) // 指令描述
.action(()=>{ // 指令具体的操作
console.log('创建一个Vue项目');
if(key === '*'){
console.log('指令不存在');
}else {
// console.log(value.description);
// console.log(process.argv.slice(3)); // 获取参数
require(path.resolve(__dirname, key))(...process.argv.slice(3)) // 文件的名称与key一致,通过require导入对应的文件方法去执行,处理不同指令
}
})
})
program.on('--help',()=>{
console.log('Example:');
// 自定义指令相关的示例
Reflect.ownKeys(commandMap).forEach(key=>{
const value = commandMap[key]
console.log(` ${value.description} `);
})
})
program.version(version).parse(process.argv)
6 实现create指令
create指令的本质
从网络上下载提前准备好的模板,然后再自动安装模板中的相关依赖
实现create指令分为两步
- 下载指定模板
- 安装相关依赖
6.1 获取项目模板名称
GET /orgs/:org(组织机构的名称)/repos
安装axios
npm i axios
action中的操作:
获取过程中,会卡,显示loading提示用户当前正在下载
ora 实现命令行loading效果
npm install ora
// create.js
const axios = require('axios')
const ora = require('ora');
const getTemplateNames = async ()=>{
const { data } = await axios.get('https://api.github.com/orgs/it666-com/repos')
return data
}
module.exports = async (projectName) =>{
/**
* 获取过程中,会卡,显示loading提示用户当前正在下载
* ora
*/
const spinner = ora('downloading template names')
spinner.start()
console.log('create', projectName);
let data = await getTemplateNames()
let templateNames = data.map(obj => obj.name) // 模板名称
spinner.succeed('downloading template names success')
console.log(templateNames);
}
添加终端用户交互
用户和终端进行交互:inquirer包
安装
npm install inquirer
参数的意义
- type:表示提问的类型,包括:input, confirm, list, rawlist, expand, checkbox, password, editor;
- name: 存储当前问题回答的变量;
- message:问题的描述;
- default:默认值;
- choices:列表选项,在某些type下可用,并且包含一个分隔符(separator);
- validate:对用户的回答进行校验;
- filter:对用户的回答进行过滤处理,返回处理后的值;
- transformer:对用户回答的显示效果进行处理(如:修改回答的字体或背景颜色),但不会影响最终的答案的内容;
- when:根据前面问题的回答,判断当前问题是否需要被回答;
- pageSize:修改某些type类型下的渲染行数;
- prefix:修改message默认前缀;
- suffix:修改message默认后缀。
const axios = require('axios');
const inquirer = require('inquirer');
const ora = require('ora');
const getTemplateNames = async () => {
const { data } = await axios.get('https://api.github.com/orgs/it666-com/repos');
return data;
};
module.exports = async (projectName) => {
const spinner = ora('downloading template names');
spinner.start();
const data = await getTemplateNames();
const templateNames = data.map((obj) => obj.name);
spinner.succeed('download template names successfully')
console.log(templateNames);
// 2.让用户选择制定的模板名称
const {currentTemplateName} = await inquirer.prompt({
name:"currentTemplateName",
type:"list",
choices:templateNames,
message:"请选择要使用哪个模板来创建项目"
})
console.log(currentTemplateName); // vue-simple-template
};
上面可以获取到用户选择的
模板名称
,可根据模板名称去下载对应的模板,但是模板区分版本号
6.2 获取版本号
GET / repos / owner (组织机构的名称)/ :repo(模板的名称) / tags
const axios = require('axios');
const inquirer = require('inquirer');
const ora = require('ora');
const getTemplateNames = async () => {
const { data } = await axios.get('https://api.github.com/orgs/it666-com/repos');
return data;
};
const getTemplateTags = async (currentTemplateName) => {
const { data } = await axios.get(`https://api.github.com/repos/it666-com/${currentTemplateName}/tags`);
return data;
};
module.exports = async (projectName) => {
const spinner = ora('downloading template names');
spinner.start();
const data = await getTemplateNames();
const templateNames = data.map((obj) => obj.name);
spinner.succeed('download template names successfully')
console.log(templateNames);
// 2.让用户选择制定的模板名称
const { currentTemplateName } = await inquirer.prompt({
name: "currentTemplateName",
type: "list",
choices: templateNames,
message: "请选择要使用哪个模板来创建项目"
})
console.log(currentTemplateName);
// 3.获取用户指定模板的所有版本号
spinner.start()
const data2 = await getTemplateTags(currentTemplateName);
const templateTags = data2.map((obj) => obj.name)
spinner.succeed("download template tags successfully")
console.log('templateTags', templateTags);
// 4.让用户选择使用指定模板的哪一个版本来创建项目
const { currentTemplateTagsName } = await inquirer.prompt({
name: "currentTemplateTag",
type: "list",
choices: templateTags,
message: "请选择要使用选择模板的哪一个版本来创建项目"
})
console.log(currentTemplateName, currentTemplateTagsName);
};
6.3 优化上面的代码
====》参考仿造
/*
function demo(a, b) {
return a + b;
}
const res = demo(10, 20);
console.log(res);
*/
function demo(a) {
return function (b) {
return a + b;
};
}
// const res = demo(10);
// const res2 = res(20);
// console.log(res2);
const res = demo(10)(20);
console.log(res);
// 给fn传参 async (...args) 参考上面
const waitLoading = (message, fn) => async (...args)=>{
const spinner = ora(message);
spinner.start();
const data = await fn(...args);
spinner.succeed(`${message}successful `)
return data
}
全部代码
const axios = require('axios');
const inquirer = require('inquirer');
const ora = require('ora');
const getTemplateNames = async () => {
const { data } = await axios.get('https://api.github.com/orgs/it666-com/repos');
console.log('data', data);
return data;
};
const getTemplateTags = async (currentTemplateName) => {
const { data } = await axios.get(`https://api.github.com/repos/it666-com/${currentTemplateName}/tags`);
return data;
};
const waitLoading = (message, fn) =>async (...args)=>{
const spinner = ora(message);
spinner.start();
const data = await fn(...args);
spinner.succeed(`${message}successful `)
return data
}
module.exports = async (projectName) => {
const data = await waitLoading('downloading template names', getTemplateNames)();
const templateNames = data.map((obj) => obj.name);
// console.log(templateNames);
// // 2.让用户选择制定的模板名称
const { currentTemplateName } = await inquirer.prompt({
name: "currentTemplateName",
type: "list",
choices: templateNames,
message: "请选择要使用哪个模板来创建项目"
})
console.log(currentTemplateName);
// 3.获取用户指定模板的所有版本号
const data2 = await waitLoading('downloading template tags', getTemplateTags)(currentTemplateName);
const templateTags = data2.map((obj) => obj.name);
// 4.让用户选择使用指定模板的哪一个版本来创建项目
const { currentTemplateTag } = await inquirer.prompt({
name: 'currentTemplateTag',
type: 'list',
choices: templateTags,
message: '请选择要使用选择模板的哪一个版本来创建项目',
});
console.log(currentTemplateName, currentTemplateTag);
};
6.4 获取下载目录
- 1.拿到
模板名称
和版本号
之后应该下载模板 - 2.如何下载?下载到什么地方
官方的Vue-CLI会先将模板下载到'用户目录'
中, 然后再拷贝到’执行指令的目录
'中 - 3.为什么要先下载到
用户目录
中?
因为下载好的模板可能还需要进行一些其它操作
process.env
USERPROFILE: ‘C:\Users\86182’ Windows当前电脑的用户目录
process.platform获取当前的平台
Windows和Mac的key不一样,需要做区分
const currentPlatformKey = process.platform === 'win32' ? 'USERPROFILE' : 'HOME';
const downloadDirPath = `${process.env[currentPlatformKey]}\\.nue-template`
\\.nue-template
是隐藏的文件夹路径,自定义放置create下载的模板的位置
6.5 如何从github下载模板?
可以借助 download-git-repo
这个库来下载我们指定的模板
download-git-repo可以下载git仓库
const axios = require('axios');
const ora = require('ora');
const inquirer = require('inquirer');
const { downloadDirPath } = require('./const')
let DownloadGitRepo = require('download-git-repo')
// 通过NodeJS的util中的promisify方法, 可以快速的将回调函数的API转换成Promise的API
const {promisify} = require('util')
DownloadGitRepo = promisify(DownloadGitRepo);
// ........
const downloadTemplate = async (templateName, templateTag) => {
let url = `it666-com/${templateName}`
if(templateTag){
url += `#${templateTag}`
}
let destPath = downloadDirPath + `\\${templateName}` // 指定下载放置的文件夹的名称与templateName一致
// 转成了promise,第三个参数:回调 就不需要了
await DownloadGitRepo(url, destPath)
return destPath
}
// .......1,2,3,4
// 5.下载用户选择的模板
const destPath = await waitLoading('', downloadTemplate)(currentTemplateName, currentTemplateTag)
console.log(destPath);
};
6.6 从用户目录拷贝到执行指令的目录当中
path.resolve() // 获取执行指令的目录
完整的目录:获取执行指令的目录 + 执行指令传递的项目名称(projectName)
path.resolve(projectName)
ncp:快速实现文件夹的拷贝
安装
npm install ncp
将回调转为promise处理
let ncp = require('ncp')
ncp = promisify(ncp)
// ...
let ncp = require('ncp')
ncp = promisify(ncp)
// ....
// 5.下载用户选择的模板
const destPath = await waitLoading('', downloadTemplate)(currentTemplateName, currentTemplateTag)
// 6.将用户目录中的模板拷贝到执行指令的路径中
await waitLoading('copying template', ncp)(destPath, path.resolve(projectName))
projectName从创建create指令的action内传入
6.7 自动安装依赖
shellJS
cd:进入目录
cd([dir])
exec:执行指令
exec(command [, options] [, callback])
// ....
const shell = require('shelljs');
const exec = promisify(shell.exec); // 将shell.exec中的回调转为promise
ncp = promisify(ncp);
DownloadGitRepo = promisify(DownloadGitRepo);
// .....
const installDependencies = async (projectName) =>{
// 1.进入创建的项目目录
shell.cd(projectName);
// 2.执行Npm install指令
await exec('npm install');
}
module.exports = async (projectName) => {
// ....1,2,3,4
// 5.下载用户选择的模板
const destPath = await waitLoading('downloading template', downloadTemplate)(currentTemplateName, currentTemplateTag);
// 6.将用户目录中的模板拷贝到执行指令的路径中
await waitLoading('copying template', ncp)(destPath, path.resolve(projectName));
// 7.安装相关的依赖
await waitLoading('install dependencies', installDependencies)(projectName);
};
6.8 完善提示信息
修改提示信息的文字颜色
nodeJS中修改文字颜色:chalk(粉笔库)
安装
npm install chalk
const axios = require('axios');
const ora = require('ora');
const inquirer = require('inquirer');
let DownloadGitRepo = require('download-git-repo');
// 通过NodeJS的util中的promisify方法, 可以快速的将回调函数的API转换成Promise的API
const { promisify } = require('util');
const path = require('path');
let ncp = require('ncp');
const shell = require('shelljs');
const chalk = require('chalk');
const { downloadDirPath } = require('./const');
const exec = promisify(shell.exec);
ncp = promisify(ncp);
DownloadGitRepo = promisify(DownloadGitRepo);
const getTemplateNames = async () => {
const { data } = await axios.get('https://api.github.com/orgs/it666-com/repos');
return data;
};
const getTemplateTags = async (currentTemplateName) => {
const { data } = await axios.get(`https://api.github.com/repos/it666-com/${currentTemplateName}/tags`);
return data;
};
const waitLoading = (message, fn) => async (...args) => {
const spinner = ora(message);
spinner.start();
const data = await fn(...args);
spinner.succeed(`${message} successfully`);
return data;
};
const downloadTemplate = async (templateName, templateTag) => {
// 组织机构的名称/模板名称#模板版本号
// 1.拼接模板在github上的路径
let url = `it666-com/${templateName}`;
if (templateTag) {
url += `#${templateTag}`;
}
// 2.拼接存储下载好的模板的路径
const destPath = `${downloadDirPath}\\${templateName}`;
// 3.下载模板
await DownloadGitRepo(url, destPath);
// 4.将保存模板的路径返回给调用者
return destPath;
};
const installDependencies = async (projectName) => {
// 1.进入创建的项目目录
shell.cd(projectName);
// 2.执行Npm install指令
await exec('npm install');
};
module.exports = async (projectName) => {
const destPath = path.resolve(projectName); // 一进来就获取destPath用于下面的creating提示信息
// 提示信息 ✨ Creating project in + 创建的目录
console.log(chalk.green('✨ Creating project in ') + chalk.red(`${destPath}`));
// 1.拉取所有模板名称
const data = await waitLoading('downloading template names', getTemplateNames)();
const templateNames = data.map((obj) => obj.name);
// 2.让用户选择指定的模板名称
const { currentTemplateName } = await inquirer.prompt({
name: 'currentTemplateName',
type: 'list',
choices: templateNames,
message: '请选择要使用哪个模板来创建项目',
});
// 3.获取用户指定模板的所有版本号
const data2 = await waitLoading('downloading template tags', getTemplateTags)(currentTemplateName);
const templateTags = data2.map((obj) => obj.name);
// 4.让用户选择使用指定模板的哪一个版本来创建项目
const { currentTemplateTag } = await inquirer.prompt({
name: 'currentTemplateTag',
type: 'list',
choices: templateTags,
message: '请选择要使用选择模板的哪一个版本来创建项目',
});
// 5.下载用户选择的模板
//提示信息:✨ Initializing git repository...
console.log(chalk.green('✨ Initializing git repository...'));
const sourcePath = await waitLoading('downloading template', downloadTemplate)(currentTemplateName, currentTemplateTag);
// 6.将用户目录中的模板拷贝到执行指令的路径中
await waitLoading('copying template', ncp)(sourcePath, destPath);
// 7.安装相关的依赖
// 提示信息:✨ Initializing dependencies...
console.log(chalk.green('✨ Initializing dependencies...'));
await waitLoading('install dependencies', installDependencies)(projectName);
// 8.显示创建成功之后的提示信息
console.log(chalk.green(' Successfully created project ') + chalk.red(`${projectName}.`));
console.log(chalk.green(' Get started with the following commands:'));
console.log(chalk.magenta(`$ cd ${projectName}`));
console.log(chalk.magenta('$ npm run serve'));
};
6.9 编译模板
// ask.js 配置文件
module.exports = [
{
type: 'input', // 项目的名称需要通过输入的方式配置
name: 'name',
message: 'project-name?',
},
{
type: 'confirm', // 项目是否是私有的需要通过确认(yes or no)的方式配置
name: 'private',
message: 'ths resgistery is private?',
},
{
type: 'input', // 项目的作者需要通过输入的方式配置
name: 'author',
message: 'author?',
},
{
type: 'input', // 项目的描述需要通过输入的方式配置
name: 'description',
message: 'description?',
}
]
通过
配置文件
告诉用户,哪些东西需要先配置,然后才能根据配置去编译模板
有了
配置文件
说明模板
需要编译
1.判断是否存在ASK.JS文件
// ...
const fs = require('fs');
// ...
const askPath = path.join(sourcePath, 'ask.js');
if (!fs.existsSync(askPath)) {
// 6.将用户目录中的模板拷贝到执行指令的路径中
await waitLoading('copying template', ncp)(sourcePath, destPath);
}else {
// 编译文件,使用第三方库:metalsmith
}
2.编译
安装
npm install metalsmith
导入
const Metalsmith = require('metalsmith');
if(){}else{
await new Promise((resolve, reject) => {
Metalsmith(__dirname)
.source(sourcePath) // 告诉Metalsmith真正需要遍历的目录是谁
.destination(destPath) // 告诉Metalsmith编译完的文件放到什么地方
.use((files, metal, done) => { // use方法可遍历所有方法:files被遍历目录下的文件路径,metal:多个use共享数据,done:表示执行完毕(前一个执行完,后一个use才可以执行)
done();
})
.use((files, metal, done) => {
done();
})
.build((err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
用户先填写配置信息,才能根据用户填写的配置信息编译,在use方法中编译的原因是:在use方法中能拿到所有的文件,就能对所有文件进行编译。写两个use的原因:为了保证方法的单一原则,一个方法只做一件事情。
编译模板:consolidate:利用用户填写的信息快速的填写模板(ejs)
安装EJS
npm install ejs
update-notifier
检查脚手架有没有更新
npm install update-notifier
boxen
提示信息
7.全部代码
// create.js
const axios = require('axios');
const ora = require('ora');
const inquirer = require('inquirer');
let DownloadGitRepo = require('download-git-repo');
// 通过NodeJS的util中的promisify方法, 可以快速的将回调函数的API转换成Promise的API
const { promisify } = require('util');
const path = require('path');
let ncp = require('ncp');
const shell = require('shelljs');
const chalk = require('chalk');
const fs = require('fs');
let { render } = require('consolidate').ejs;
const updateNotifier = require('update-notifier');
const pkg = require('../package.json');
const boxen = require('boxen');
render = promisify(render);
const exec = promisify(shell.exec);
const Metalsmith = require('metalsmith');
const { downloadDirPath } = require('./const');
ncp = promisify(ncp);
DownloadGitRepo = promisify(DownloadGitRepo);
const getTemplateNames = async () => {
const { data } = await axios.get('https://api.github.com/orgs/it666-com/repos');
return data;
};
const getTemplateTags = async (currentTemplateName) => {
const { data } = await axios.get(`https://api.github.com/repos/it666-com/${currentTemplateName}/tags`);
return data;
};
const waitLoading = (message, fn) => async (...args) => {
const spinner = ora(message);
spinner.start();
const data = await fn(...args);
spinner.succeed(`${message} successfully`);
return data;
};
const downloadTemplate = async (templateName, templateTag) => {
// 组织机构的名称/模板名称#模板版本号
// 1.拼接模板在github上的路径
let url = `it666-com/${templateName}`;
if (templateTag) {
url += `#${templateTag}`;
}
// 2.拼接存储下载好的模板的路径
const destPath = `${downloadDirPath}\\${templateName}`;
// 3.下载模板
await DownloadGitRepo(url, destPath);
// 4.将保存模板的路径返回给调用者
return destPath;
};
const installDependencies = async (projectName) => {
// 1.进入创建的项目目录
shell.cd(projectName);
// 2.执行Npm install指令
await exec('npm install');
};
const checkVersion = () => {
const notifier = updateNotifier({
pkg,
updateCheckInterval: 0,
});
const { update } = notifier;
if (update) {
const messages = [];
messages.push(
`${chalk.bgYellow.black(' WARNI: ')} Nue-Cli is not latest.\n`,
);
messages.push(
chalk.grey('current ')
+ chalk.grey(update.current)
+ chalk.grey(' → ')
+ chalk.grey('latest ')
+ chalk.green(update.latest),
);
messages.push(
`${chalk.grey('Up to date ')} npm i -g ${pkg.name}`,
);
console.log(boxen(messages.join('\n'), {
padding: 2,
margin: 2,
align: 'center',
borderColor: 'yellow',
borderStyle: 'round',
}));
}
};
module.exports = async (projectName) => {
// 0.检查脚手架更新
checkVersion();
const destPath = path.resolve(projectName);
console.log(chalk.green('✨ Creating project in ') + chalk.red(`${destPath}`));
// 1.拉取所有模板名称
const data = await waitLoading('downloading template names', getTemplateNames)();
const templateNames = data.map((obj) => obj.name);
// 2.让用户选择指定的模板名称
const { currentTemplateName } = await inquirer.prompt({
name: 'currentTemplateName',
type: 'list',
choices: templateNames,
message: '请选择要使用哪个模板来创建项目',
});
// 3.获取用户指定模板的所有版本号
const data2 = await waitLoading('downloading template tags', getTemplateTags)(currentTemplateName);
const templateTags = data2.map((obj) => obj.name);
// 4.让用户选择使用指定模板的哪一个版本来创建项目
const { currentTemplateTag } = await inquirer.prompt({
name: 'currentTemplateTag',
type: 'list',
choices: templateTags,
message: '请选择要使用选择模板的哪一个版本来创建项目',
});
// 5.下载用户选择的模板
console.log(chalk.green('✨ Initializing git repository...'));
const sourcePath = await waitLoading('downloading template', downloadTemplate)(currentTemplateName, currentTemplateTag);
const askPath = path.join(sourcePath, 'ask.js');
if (!fs.existsSync(askPath)) {
// 6.将用户目录中的模板拷贝到执行指令的路径中
await waitLoading('copying template', ncp)(sourcePath, destPath);
} else {
// 6.将用户目录中的模板编译后再拷贝到执行指令的路径中
await new Promise((resolve, reject) => {
Metalsmith(__dirname)
.source(sourcePath) // 告诉Metalsmith真正需要遍历的目录是谁
.destination(destPath) // 告诉Metalsmith编译完的文件放到什么地方
.use(async (files, metal, done) => {
// 1.让用户填写配置信息
const config = require(askPath);
const result = await inquirer.prompt(config);
const meta = metal.metadata();
Object.assign(meta, result);
done();
})
.use((files, metal, done) => {
const result = metal.metadata();
// 2.根据用户填写的配置信息编译模板
// 2.1遍历拿到所有文件路径
Reflect.ownKeys(files).forEach(async (filePath) => {
// 2.2提取我们需要处理的问题
if (filePath.includes('.js') || filePath.includes('.json')) {
// 2.3获取当前文件的内容
const fileContent = files[filePath].contents.toString();
// 2.4判断当前文件的内容是否需要编译
if (fileContent.includes('<%')) {
const resultContent = await render(fileContent, result);
files[filePath].contents = Buffer.from(resultContent);
}
}
});
done();
})
.build((err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
// 7.安装相关的依赖
console.log(chalk.green('✨ Initializing dependencies...'));
await waitLoading('install dependencies', installDependencies)(projectName);
// 8.显示创建成功之后的提示信息
console.log(chalk.green(' Successfully created project ') + chalk.red(`${projectName}.`));
console.log(chalk.green(' Get started with the following commands:'));
console.log(chalk.magenta(`$ cd ${projectName}`));
console.log(chalk.magenta('$ npm run serve'));
};
学习记录