1.初始化项目
npm init -y
2.创建目录bin,里面创建inde.js
#!/usr/bin/env node
// 上面的不是注释,非常重要,告诉命令使用node环境运行本文件
console.log("hellow cli...")
3.package.json中配置bin命令
...
"main": "index.js",
"bin": {
"kun": "./bin/index.js"
},
...
4.执行命令,创建软链接,把bin目录的路径暴露出来
npm link
成功后,在命令行尝试执行
kun
控制台打印 hellow cli...
commander
node.js命令行界面的完整解决方案 npm install commander -S
修改bin/index.js
#!/usr/bin/env node
// 上面的不是注释,非常重要,告诉命令使用node环境运行本文件
const program=require('commander');
program.version(require('./../package.json').version);
program.command("create <name>")
.description("create a koa project")
.action((name)=>{
console.log("name: "+name)
})
// 这行代码是解析参数
program.parse(process.argv)
执行kun create hellow
,打印name: hellow
。
现在支持 kun create <name>
,kun -V
,而且action中可以执行一下操作,并且能得到用户传入的参数。
6.安装 chalk.js
控制台粉笔工具,方便改变打印的颜色
npm install chalk -S
修改/bin/index.js,action中的function换成init导出的function
...
.description("create a koa project")
.action(require('./init'))
program.parse(process.argv)
根目录创建init.js ,主要功能就是创建一个文件夹,里面创建一个index.js和一个package.json。
const fs = require("fs");
const chalk = require("chalk");
const path = require("path");
const createLog = (type) => (content) => console.log(chalk[type](content));
const success = createLog("green");
const errorLog = createLog("red");
function getFilePath(name) {
return `./${name}`;
}
// 删除目录
function delDir(path) {
let files = [];
if (fs.existsSync(path)) {
files = fs.readdirSync(path);
files.forEach((file) => {
let curPath = path + "/" + file;
if (fs.statSync(curPath).isDirectory()) {
delDir(curPath); //递归删除文件夹
} else {
fs.unlinkSync(curPath); //删除文件
}
});
fs.rmdirSync(path);
}
}
// 这个name值是index.js中,`program.parse(argv)`解析的
module.exports = async (name) => {
const basePath = getFilePath(name);
if (fs.existsSync(basePath)) {
errorLog("同名文件已经存在");
return false;
}
// 创建目录
fs.mkdirSync(basePath);
try {
fs.writeFileSync(`${basePath}/index.js`, "index");
fs.writeFileSync(`${basePath}/package.json`,'package');
success("创建成功");
} catch (error) {
// 删除目录及文件
delDir(basePath);
errorLog("创建失败!");
}
};
7.有内味了。就是文件生成的确实low b点。安装ejs
高效的嵌入式 JavaScript 模板引擎
首先要创建模板目录template。里面创建index.ejs和package.ejs
//index.ejs
const Koa = require('koa');
<% if (middleware.router) { %>
const Router = require('koa-router');
<% } %>
<% if (middleware.static) { %>
const serve = require("koa-static");
<% } %>
<% if (middleware.views) { %>
const views = require("koa-views");
<% } %>
<% if (middleware.body) { %>
const body = require('koa-body');
<% } %>
const app = new Koa();
<% if (middleware.static) { %>
app.use(serve(__dirname, '/static'));
<% } %>
<% if (middleware.views) { %>
app.use(views(__dirname, '/views'), {
extension: 'pug'
})
<% } %>
<% if (middleware.body) { %>
app.use(body({
multipart: true
}))
<% } %>
<% if (middleware.router) { %>
const router = new Router();
router.get('/', ctx => {
ctx.body = "hellow world"
})
app.use(router.routes());
<% } %>
app.listen(<%= port %>, () => {
console.log("服务启动在localhost:<%= port %>")
})
//package.ejs
{
"name": "template",
"version": "1.0.0",
"description": "",
"main": "<%= packageName %>.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"koa": "^2.13.1"
<% if (middleware.body) { %>
,"koa-body": "^4.2.0"
<% } %>
<% if (middleware.router) { %>
, "koa-router": "^10.0.0"
<% } %>
<% if (middleware.static) { %>
,"koa-static": "^5.0.0"
<% } %>
<% if (middleware.views) { %>
,"koa-views": "^7.0.1"
<% } %>
}
}
创建目录createCode ,里面创建文件 inde.js
、 createIndexPage.js
、createPackagePage.js
。
//index.js
const createIndexPage =require('./createIndexPage')
const createPackagePage =require('./createPackagePage')
module.exports.createIndexPage=createIndexPage
module.exports.createPackagePage=createPackagePage
//createIndexPage.js
const ejs = require("ejs");
const fs = require("fs");
const path = require("path");
module.exports = () => {
const content = fs
.readFileSync(path.join(__dirname, "../template/index.ejs"))
.toString();
const code = ejs.render(content, { middleware: {}, port: 3000 });
return code;
};
// createPackagePage.js
const ejs = require("ejs");
const fs = require("fs");
const path=require('path');
module.exports = () => {
const content = fs
.readFileSync(path.join(__dirname, "./../template/package.ejs"))
.toString();
const code = ejs.render(content, { middleware: {}, packageName: 3000 });
return code;
};
init.js
稍微修改一下,改变文件写入的字符
const { createIndexPage, createPackagePage } = require("./createCode");
...
try {
fs.writeFileSync(`${basePath}/index.js`, createIndexPage());
fs.writeFileSync(`${basePath}/package.json`,createPackagePage());
success("创建成功");
} catch (error) {
...
8.来点交互更加炫酷
安装 inquirer
一个用户与命令行交互的工具
npm install inquirer -S
创建目录question,里面创建文件index.js
、packageName.js
、port.js
、middleware.js
//index.js
const inquirer = require("inquirer");
function getPromptList(name) {
return [
// 具体交互内容
require("./packageName.js")(name),
require("./port.js")(),
require("./middleware.js")(),
];
}
module.exports = (name) => {
return inquirer.prompt(getPromptList(name));
};
// packageName.js
module.exports = (name) => ({
type: "input",
name: "packageName",
message: "设置项目名称",
validate(val) {
if (!val) {
return "请输入项目名称";
} else {
return true;
}
},
default() {
return name;
},
});
//middleware.js
module.exports = (name) => ({
type: "checkbox",
name: "middleware",
message: "请选择使用的中间件",
choices: [
{
name: "KoaBody",
},
{
name: "Koaviews",
},
{
name: "KoaStatic",
},
{
name: "KoaRouter",
},
],
});
// port.js
module.exports = () => ({
type: "input",
name: "port",
message: "设置服务端口号",
default() {
return 8000;
},
validate: function (val) {
if (val > 3000 && val < 65535) {
// 校验位数
return true;
}
return "端口号范围应为:3000-65535";
},
});
init.js中执行交互,并且将用户的选择传入到生成代码的函数
const question = require("./question");
...
const data = await question();
console.log(data);
var config = {
packageName: data.packageName,
port: data.port,
middleware: {
body: data.middleware.indexOf("KoaBody") !== -1,
views: data.middleware.indexOf("KoaViews") !== -1,
static: data.middleware.indexOf("KoaStatic") !== -1,
router: data.middleware.indexOf("KoaRouter") !== -1,
},
};
// 创建目录
fs.mkdirSync(basePath);
try {
fs.writeFileSync(`${basePath}/index.js`, createIndexPage(config));
fs.writeFileSync(`${basePath}/package.json`, createPackagePage(config));
....
npm install
。安装 execa
将process_child pipe到主进程 npm install execa -S
init.js
const fs = require("fs");
const chalk = require("chalk");
const execa = require("execa");
const { createIndexPage, createPackagePage } = require("./createCode");
const question = require("./question");
const createLog = (type) => (content) => console.log(chalk[type](content));
const success = createLog("green");
const errorLog = createLog("red");
function getFilePath(name) {
return `./${name}`;
}
// 删除目录
function delDir(path) {
let files = [];
if (fs.existsSync(path)) {
files = fs.readdirSync(path);
files.forEach((file) => {
let curPath = path + "/" + file;
if (fs.statSync(curPath).isDirectory()) {
delDir(curPath); //递归删除文件夹
} else {
fs.unlinkSync(curPath); //删除文件
}
});
fs.rmdirSync(path);
}
}
module.exports = async (name) => {
const basePath = getFilePath(name);
if (fs.existsSync(basePath)) {
errorLog("同名文件已经存在");
return false;
}
const data = await question(name);
var config = {
packageName: data.packageName,
port: data.port,
middleware: {
body: data.middleware.indexOf("KoaBody") !== -1,
views: data.middleware.indexOf("KoaViews") !== -1,
static: data.middleware.indexOf("KoaStatic") !== -1,
router: data.middleware.indexOf("KoaRouter") !== -1,
},
};
// 创建目录
fs.mkdirSync(basePath);
try {
fs.writeFileSync(`${basePath}/index.js`, createIndexPage(config));
fs.writeFileSync(`${basePath}/package.json`, createPackagePage(config));
await execa("npm", ["install"], { cwd: `./${name}`, stdio: [2, 2, 2] });
success(`
恭喜!!!小项目创建完毕
-----------------------------------------------
***********************************************
cd ./${name}
npm run serve
===============================================
`);
} catch (error) {
// 删除目录及文件
delDir(basePath);
errorLog("创建失败!");
}
};