今天我们来为我们昨天做的「Click! Serve!」增加一些「设定」。
昨天我们用最简单的设定让 pkg 可以将程序打包成可执行档,今天我们让它不要乱放产生出来的档案,以及让产生出来的档案不要叫「index.exe」。
我们更新我们的 package.json 档:
{
"name": "serv",
"version": "1.0.0",
"description": "",
"main": "index.js",
"bin": {
"serv": "index.js"
},
"scripts": {
"build": "pkg ."
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"koa": "^2.13.3",
"koa-static": "^5.0.0"
},
"devDependencies": {
"pkg": "^5.3.3"
},
"pkg": {
"outputPath": "dist"
}
}
增加了一个 bin
的项目,告诉 pkg 我们的 entry 是 index.js。
然後把 script
中的 pkg index.js
改成 pkg .
代表读这个专案资料夹的 package.json 的设定。
最後加上 pkg
让 pkg 把产生的档案输出至 dist
资料夹。
因为多了一些功能,所以将程序分档案放到 src 资料夹中。
然後把 index.js 改成:
require("./src/main");
main.js 是主程序,它把处里参数的工作跟服务器分开给两个档案,看起来很简单。
const config = require("./config");
const createServer = require("./server");
createServer(config);
流程看起来好舒服,不用管到底怎麽抓参数或建立服务器的。
这个档案用来处理参数,并将处里好的参数 exports 出去。
const process = require("process");
const path = require("path");
// 预设参数,如果用户没设定,就用它
const defaultConfig = {
port: 80,
folder: "www",
log: false,
logFile: "log.txt",
};
// 抓参数,第一个是 Node.js 位置,第二个是 js 档位置,虽然打包但不变
const argv = process.argv.slice(2);
const config = extractConfig(argv);
// 如果使用者想要 help 的话,给简单的 help
if (config["help"] || config["h"] || config["?"] || config["-help"] || config["-h"] || config["-?"] || config["--help"] || config["--h"] || config["--?"]) {
console.log("Usage: serv [port=80] [folder=www] [log] [logFile=log.txt]");
process.exit(0);
}
// 参数本来应为 key=val 或 key,这里把他们拆开
function extractConfig(argv) {
let config = {};
for (let i = 0; i < argv.length; i++) {
let arg = argv[i];
arg = arg.split("=");
const key = arg.shift();
let value = arg.join("=") || true;
if (value[0] === '"' && value[value.length - 1] === '"') value = value.substring(1, value.length - 1);
config[key] = value;
}
return check(config);
}
// 处里一些转型问题或相对绝对路径的转换
function check(config) {
if (config.port) config.port = parseInt(config.port);
if (config.log) config.log = config.log !== "false" && config.log !== "0";
if (config.folder) config.folder = path.isAbsolute(config.folder) ? config.folder : path.join(process.cwd(), config.folder);
if (config.logFile) config.logFile = path.isAbsolute(config.logFile) ? config.logFile : path.join(process.cwd(), config.logFile);
return config;
}
// 合并预设与自订参数後汇出
module.exports = Object.assign({}, defaultConfig, config);
参数的抓取、合并以及型别路径转换等都在此完成。
这个档案会 exports 一个建立 server 用的函式,然後由 main.js 把处里好的参数丢进去用。
const fs = require("fs");
const Koa = require("koa");
function createServer({ port, folder, log, logFile }) {
const app = new Koa();
// 因为 log 会一直写入,所以用 stream
let logFileStream;
if (log) logFileStream = fs.createWriteStream(logFile, { flags: "a" });
app.use(async (ctx, next) => {
console.log(`Process ${ctx.request.method} ${ctx.request.url} from ${ctx.request.ip}`);
if (log) logFileStream.write(`${new Date().toISOString()} ${ctx.request.method} ${ctx.request.url} from ${ctx.request.ip}\n`);
await next();
});
app.use(require("koa-static")(folder));
app.listen(port);
console.log(`Server started at port ${port}`);
console.log(`Serving static files from ${folder}`);
console.log(`Visit http://localhost:${port}/ to see your website.`);
if (log) console.log(`Log file: ${logFile}`);
if (log) logFileStream.write(`=====\n${new Date().toISOString()} Server Started.\n`);
if (log) logFileStream.write(`${new Date().toISOString()} Serving static files from ${folder}\n`);
}
module.exports = createServer;
基本上这个部分跟昨天的程序相似度非常高,只是多了些 log 的部分而已。
来实测程序吧!
help 指令 OK!
不输入任何参数执行也 OK!(当然你可以 Click 点开)
带入参数执行也都 OK!!
同时在不同 port 执行两个 server 也 OK!
而且,log 有正常运作:
基本上都 OK 啦!(不会写测试)
赞赞!写出一个应该可以有用的程序了。
再来我们看看能不能用 Electron 给他个 GUI 吧!
以 10/08 20:00 ~ 10/09 20:00 文章观看数增加值排名
+190
[访谈] APCS x 竞程选手 Colten
+133
LeetCode 双刀流:62. Unique Paths
+117
【Day24】维持权限 — 隐藏後门(一)
+116
Day27 vue.js简易照片上传功能(base64)
+114
Angular 深入浅出三十天:表单与测试 Day24 - Reactive Forms 进阶技巧 - Auto-Complete Searching
+110
【在 iOS 开发路上的大小事-Day27】透过 Firebase 来管理资料 (Cloud Firestore 篇) Part1
+108
Day 24 快速启动个 JSON Server
+108
Day24-按钮分身术(下)_我的分身想去哪
+108
Day24 read-write lock
+106
Day24 Let's ODOO: Discuss
恭喜 Sky Hong 同学封顶!!
今天访谈说好久喔,差点来不及写了 XD
<<: Day-28 Breadth-First Search(BFS), 广度优先搜寻
一、主题内容 虽然知道全端工程师的路不好走,自己目前也还不是很称职,仍想以自己转职的角度、回顾的方式...
Docker 发展之路 过去什麽都没有的黑暗时代,所有的Application都是直接放在服务器上的...
这篇接续上一篇,将电影名称爬取後转为json档,今天就要再转为xlsx档,使资料以表格方式呈现。废话...
Youtube 连结:https://bit.ly/3FNg3KA 对於「 分散式架构 」主题,数...
Whenever a perfect ERP installation is expected, o...