前言
- 计算机系统为Windows 10 专业版
修改package.json配置
原package.json文件中scripts字段的配置字段为:
在终端运行
npm run dev
可能会报错
‘.’ 不是内部或外部命令,也不是可运行的程序或批处理文件。
解决方法就是修改package.json文件中dev指令:
"dev": "nodemon bin/www",
修改之后package.json文件中scripts字段的配置字段为:
修改/bin/www.js文件
能不能像vue-cli启动前端项目时在控制台(终端)输出服务器地址和启动时间:
服务器启动时间输出
使用console.time()
和console.timeEnd()
组合即可输出代码运行时间(计算是的他俩之间同步代码的运行时间,点这里查看使用方法)
var app = require("../app");
var debug = require("debug")("demo:server");
var http = require("http");
console.time("Time");
/**
......
此处省略好多字
*/
console.timeEnd("Time");
命令行颜色输出
使用console.log()
可以输出带颜色的文字,甚至可以加上一点点小样式。点这里查看console家族的趣事。
console.log("给你点%c颜色", "color: yellow; ");
其中 %c 之后的字符就会应用color: yellow;
样式。
但是这个只是在浏览器控制台才会起效果,而node的console输出是在命令行(终端)。问题不大,可以这样写:
console.log("%s\x1B[31m%s\x1B[0m", "给你点", "颜色");
麻!拆开来看:
%s:字符串占位符,输出时会将console.log剩下的参数匹配替换进来(相当于console.log('给你点\x1B[31m颜色\x1B[0m')
)
\x1B[31m:ANSI转义码(ANSI escape code) 它将被终端拦截并指示它切换到红色。
\x1B[0m:ANSI转义码(ANSI escape code)表示重置终端颜色,使其在此之后不再继续成为所选颜色。
也可以安装colors-console插件
npm i -D colors-console
/bin/www.js:
const colors = require('colors-console')
console.log('给你点' + colors('red', '颜色'))
ANSI转义码对照表:
ANSI转义码 | colors-console插件对应参数 | 描述 |
---|---|---|
\x1B[0m | 重置样式 | |
\x1B[1m | bright | 字体颜色:亮色(应该是粗体) |
\x1B[2m | grey | 字体颜色:灰色 |
\x1B[3m | italic | 斜体 |
\x1B[4m | underline | 下划线 |
\x1B[7m | reverse | 反向 |
\x1B[8m | hidden | 隐藏 |
\x1B[30m | black | 字体颜色:黑色 |
\x1B[31m | red | 字体颜色:红色 |
\x1B[32m | green | 字体颜色:绿色 |
\x1B[33m | yellow | 字体颜色:黄色 |
\x1B[34m | blue | 字体颜色:蓝色 |
\x1B[35m | magenta | 字体颜色:品红 |
\x1B[36m | cyan | 字体颜色: 青色 |
\x1B[37m | white | 字体颜色:白色 |
\x1B[40m | blackBG | 字体背景:黑色 |
\x1B[41m | redBG | 字体背景:红色 |
\x1B[42m | greenBG | 字体背景:绿色 |
\x1B[43m | yellowBG | 字体背景:黄色 |
\x1B[44m | blueBG | 字体背景:蓝色 |
\x1B[45m | magentaBG | 字体背景:品红 |
\x1B[46m | cyanBG | 字体背景:青色 |
\x1B[47m | whiteBG | 字体背景:白色 |
如果在引入插件有灰色三个小点的提示,那不是错误,不影响运行,只是提示没找到声明文件(.d.ts)。
如果看着不得劲,在终端尝试安装其声明文件(.d.ts)
npm i --save-dev @types/colors-console
若没有找到该声明文件,则可以在根目录新建一个koa.d.ts(koa只是文件名,随便取名)。添加如下声明代码:
declare module "colors-console";
ANSI转义码(ansi escape code):
ANSI是国际标准,所以(应该是)兼容所有平台。
以下是原文摘抄,原文在这里
\x1B表示ACSII执行escape命令,也可写作\033。
原文图片
\x1B加上 [ ,他们一起组成的部分通常被称为CSI (Control Sequence Introducer)。
ansi escape code的语法:
0x1B + "[" + <params> + <fn>
- <params> 由0个或者多个数字组成,是函数的参数,多个参数之间由分号进行分割。
- <fn> 是一个字母,是ansi escape code需要调用的函数名。
因此: \x1b[0;1;34m 可以理解为 m(0, 1, 34); 同样,\x1b[A 可以理解为: A()。
<fn>可用的函数 :
函数名 | 描述 |
---|---|
A | 将光标向上移动n行 |
B | 将光标向下移动n行 |
C | 将光标向前移动n个字符 |
D | 将光标向后移动n个字符 |
E | 将光标向下移到到n行的行首 |
F | 将光标向上移到到n行的行首 |
G | 将光标移动到当前行中的第n列 |
H | 将光标移动到第m行,第n列(以左上为起点) |
J | 清除部分屏幕。0、1、2和3有各种特定的功能 |
K | Clear part of the line. 0, 1, and 2 have various specific functions |
S | 将窗口向上滚动到n行 |
T | 将窗口向下滚动到n行 |
s | 保存当前光标位置以供u函数使用 |
u | 将光标设置回s函数最后保存的位置 |
f | 和G函数一样 |
m | 设置图形模式(SGR) |
m函数参数说明:
参数值 | 描述 |
---|---|
0 | 重置:关闭所有属性 |
1 | 粗体 |
3 | 斜体 |
4 | 下划线 |
30–37 | 从0-7的基本颜色板中设置文本颜色,即前景色 |
38;5;n | 从256色调色板中将文本颜色设置为n,例如:\x1b[38;5;34m |
38;2;r;g;b | 将文本颜色设置为rgb,例如:\x1b[38;2;255;255;0m |
40–47 | 从0-7的基本颜色板中设置背景色 |
48;5;n | 从256色调色板中将背景色设置为n,例如:\x1b[48;5;34m |
48;2;r;g;b | 将背景色设置为rgb,例如:\x1b[48;2;255;255;0m |
90–97 | 从0-7的明亮调色板中设置文本颜色 |
100–107 | 从0-7的明亮调色板中设置背景色 |
本地服务器和局域网服务器
本地服务器地址就是localhost(或者127.0.0.1),只有本机能够访问。
局域网服务器地址是本机的IP(IPv4),只有连接此局域网的设备可以访问。
vue-cli的Network就是用的该IP:
查看本机IP地址:
有两种方法查看-图形化界面查看和命令行查看
图形化界面查看步骤:桌面-网络(鼠标右击)-属性-已连接的网路(鼠标左击)- 详细信息
图形化界面查看的缺点是:不同版本的Window系统查看方式可能略微不同。
所以推荐命令行查看本机IP地址:
在终端(cmd)输入如下指令:
ipconfig
即可。
其中的IPv4地址即是以后node服务器的局域网地址。
node获取本机的IP地址(IPv4)
获取本机的IP地址需要用到node的os模块,具体代码如下:
var os = require("os");
function getIPAdress() {
var interfaces = os.networkInterfaces();
for (var devName in interfaces) {
var iface = interfaces[devName];
for (var i = 0; i < iface.length; i++) {
var alias = iface[i];
if (
alias.family === "IPv4" &&
alias.address !== "127.0.0.1" &&
!alias.internal
) {
return alias.address;
}
}
}
}
此方法只适用本地开发使用,打包发布到服务器后会失效。
os.networkInterfaces()的返回值格式为:
{
'以太网 2': [
{
address: '',//用于指定分配的网络地址,即IPv4或IPv6
netmask: '',//指定IPv4或IPv6网络掩码
family: 'IPv6',//值为IPv4或IPv6之一
mac: '',//指定网络接口的MAC地址
internal: false,//如果接口为环回一则为true,否则为false
cidr: '',//用于指定分配的IPv4或IPv6地址以及CIDR表示法中的路由前缀。如果网络掩码无效,则将其设置为null
scopeid: 4//指定IPv6的作用域ID
}
]
}
设置服务器端口
var app = require("../app");
var http = require("http");
var port = normalizePort(process.env.PORT || "3000");
var server = http.createServer(app.callback());
server.listen(port);
normalizePort(process.env.PORT || "3000");
这段代码就是获取端口号:先从环境变量中取,没有的话,默认3000。
normalizePort()是koa-generator中引入的,他的作用就是规范化端口的值,其定义是:
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
server.listen(port);
用于监听端口,也可以这样写server.listen(port,host);
port是端口,host是主机ip地址。
- 如果port省略或是0,系统会随意分配一个,在server的listening事件触发后能被通过server.address().port检索到。
- 如果host省略,若IPv6可用,服务器将会接收基于IPv6地址(默认host为 :: 双冒号,
server.address().address
返回的也是该值)的连接,否则接收基于IPv4地址(默认host为0.0.0.0,server.address().address
返回的也是该值)的连接。并且127.0.0.1也可连接。若host有指定地址,那么只该指定的host可连接。
所以server.listen(port)
相当于server.listen(port,'::')
或server.listen(port,'0.0.0.0')
。
process.env
属性返回一个包含用户环境信息的对象。
修改环境变量的方法有两种,第一种是在运行中修改:
设置或新增process.env的属性:
process.env.PORT = 3000;//设置的值会自动转成字符串'3000'
删除process.env的属性:
delete process.env.PORT;
注意:在Windows系统下,环境变量是不区分大小写的:
process.env.TEST === process.env.test;//true
第二种是在package.json中设置命令:
{
"name": "server2",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "set PORT=5252 && nodemon bin/www localhost"
}
}
这两种方式都是临时修改环境变量,当程序关闭变量也都会还原。
若要永久,需要在操作系统中设置,比如window系统:
此电脑(鼠标右击)- 属性 - 高级系统设置 - 环境变量
命令行参数
-process.argv
返回node启动时的命令行参数数组。
比如:
修改package.json中的start命令:
{
"scripts": {
"start": "node bin/www --param1 --param2=5152"
}
}
在/bin/www.js中打印命令行参数:
console.log(process.argv);
启动服务器
npm run start
会得到如下输出:
[
'E:\\Node\\install\\node.exe',
'F:\\test\\vue_node\\hello-node\\server2\\bin\\www',
'--param1',
'--param2=5152'
]
命令行参数约定是以 --
(两个破折号) 作为前缀。
- 数组的第一个元素process.argv[0]——返回启动Node.js进程的可执行文件所在的绝对路径
- 第二个元素process.argv[1]——为当前执行的JavaScript文件路径
- 剩余的元素为其他命令行参数,注意是字符串。也就是说命令行参数是从数组的第二个元素开始的。
(nodemon指令同理,因为其也是执行node指令)
解析命令行参数可以手写:
function getProcessArgv(){
const argvs = process.argv.splice(2);
const r = {};
argvs.forEach((item)=>{
const v = item.split('=');
const key = v[0].replace(/^-+/gim,"");
const value = v[1] || true;
r[key] = value;
});
return r;
}
或者安装Yargs插件
npm i yargs@6.0.0
使用方法:
//node指令: node bin/www --name=xiaoyang --age=18
var argv = require('yargs').argv;
console.log(argv.name,argv.age);//xiaoyang 18
注意!使用npm run指令时,使用参数需要加--
,这是npm传递参数给script的方法。
比如:
package.json
"scripts": {
"start": "node bin/www"
},
在终端执行:
npm run start -- --port=5152
相当于执行:
node bin/www --port=5152
如果npm run 中的参数与package.json中相应指令中的参数名一样,不会覆盖。
比如:
"scripts": {
"start": "node bin/www --port=5153"
},
在终端执行:
npm run start -- --port=5152
相当于执行:
node bin/www --port=5153 --port=5152
process.argv的值为:
[
'E:\\Node\\install\\node.exe',
'F:\\test\\vue_node\\hello-node\\server2\\bin\\www',
'--port=5153',
'--port=5152'
]
yargs插件的返回值为:
{
port: [ 5153, 5152 ]
}
修改app.js文件
路由目录自动加载
实现此功能需要遍历路由目录,需要加载node的fs模块和path模块。
遍历路由目录:
const Koa = require("koa");
const app = new Koa();
var fs = require("fs");
var path = require("path");
//要遍历的文件夹所在的路径
var routesDir = path.resolve("routes/");
//根据文件路径读取文件,返回文件列表
function loadRoutes(dirPath) {
fs.readdir(dirPath, { withFileTypes: true }, function (err, files) {
if (err) {
console.warn(err, "读取文件夹错误!");
} else {
//遍历读取到的文件列表
files.forEach(function (dirent) {
const currentPath = path.join(dirPath, dirent.name);
if (dirent.isDirectory()) {
//文件夹
loadRoutes(currentPath);
} else if (dirent.isFile()) {
//文件
const relativePath = path.relative(__dirname, currentPath);
const router = require(relativePath);
app.use(router.routes(), router.allowedMethods());
}
});
}
});
}
-
path.resolve([…paths])
该方法将路径或路径片段的序列解析为绝对路径。
给定的路径序列从右到左处理,每个后续的 path 会被追加到前面,直到构建绝对路径。
如果在处理完所有给定的 path 片段之后,还没有生成绝对路径,则使用当前工作目录(__dirname);如果没有传入 path 片段,则 path.resolve() 将返回当前工作目录的绝对路径(相当于__dirname)。path.resolve('/foo','/bar', './baz'); // 返回: '/bar/baz' path.resolve('/foo/bar', './baz'); // 返回: '/foo/bar/baz' path.resolve('/foo/bar', '/tmp/file/'); // 返回: '/tmp/file' path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif'); // 如果当前工作目录是 F:/test/vue_node/hello-node/server2, // 则返回 'F:/test/vue_node/hello-node/server2/wwwroot/static_files/gif/image.gif'
-
path.join([…paths])
使用特定于平台的分隔符作为定界符将所有给定的 path 片段连接在一起,然后返回规范化生成的路径。如果连接的路径字符串是零长度字符串,则将返回 ‘.’,表示当前工作目录。返回的路径类型与其第一个参数的路径类型一致:第一个参数为绝对路径,则返回绝对路径;第一个参数为相对路径,则返回相对路径。path.join('/foo', 'bar', 'baz/asdf', 'quux', '..'); // 返回: '/foo/bar/baz/asdf' path.join('foo', 'bar', 'baz/asdf', 'quux', '..'); // 返回: 'foo/bar/baz/asdf'
-
path.relative(from, to)
path.relative() 方法根据当前工作目录返回从 from 到 to 的相对路径。 如果 from 和 to 都解析为相同的路径(在分别调用 path.resolve() 之后),则返回零长度字符串。
如果零长度字符串作为 from 或 to 传入,则将使用当前工作目录而不是零长度字符串。path.relative('C:\\orandea\\test\\aaa', 'C:\\orandea\\impl\\bbb'); // 返回: '..\\..\\impl\bbb'(Window系统返回反斜杠 \ )
-
__dirname
当前模块的目录名。
例如,在 F:/test/vue_node/hello-node/server2/app.js 中使用__dirname,其值则为 F:/test/vue_node/hello-node/server2 -
__filename
当前模块的目录名。
例如,在 F:/test/vue_node/hello-node/server2/app.js 中使用__filename,其值则为 F:/test/vue_node/hello-node/server2/app.js -
fs.readdir(path[, options], callback)
读取目录的内容。
path:读取的目录路径(绝对路径或相对路径)、Buffe类或URL类:<string> | <Buffer> | <URL>。
callback:回调函数,有两个参数 (err, files),其中 files 是目录中文件或目录信息的数组(<string>[] | <Buffer>[] | <fs.Dirent>[]),默认返回的是文件或目录名称数组。
options:【可选】,<Object>- encoding:指定用于传给回调的文件名的字符编码,默认’utf-8。如果 encoding 设置为 ‘buffer’,则回调函数返回的files将作为 <Buffer> 对象数组传入。
- withFileTypes :默认false。若为true,则回调函数返回的files将作为<fs.Dirent>对象数组传入。
-
<fs.Dirent>对象
- isDirectory():如果\ <fs.Dirent> 对象描述文件系统目录,则返回 true。
- isFile():如果 <fs.Dirent> 对象描述常规文件,则返回 true。
- name:此 <fs.Dirent> 对象引用的文件名或目录名。若为目录则返目录名(比如routes),若为文件则返文件名(有后缀,比如index.js)
路由命名空间
由于路由是可以分几个文件的(/routes/),因此不可避免会碰到不同路由文件有相同的路由地址,这会照成路由冲突,解决办法就是使用命名空间:以/routes/ 为根目录,路由文件的绝对路径就是该文件中所有路由的命名空间。
比如:/routes/index.js 的命名空间是 /index。/routes/login/index.js 的命名空间是 /login/index。
然后用路由的prefix()方法设置路由命名空间:
/routes/index.js:
const router = require("koa-router")();
router.prefix("/index");
//请求路径为:/index
router.get("/", async (ctx, next) => {
ctx.body = "koa2";
});
//请求路径为:/index/string
router.get("/string", async (ctx, next) => {
ctx.body = "koa2 string";
});
自定义中间件
可以把 路由目录自动加载 的loadRoutes()方法做成中间件:新建/middleware/目录,用于存放中间件文件。同时可以把添加命名空间的代码也移到这个中间件中,而不用分散到各个路由文件中。
/middleware/loadRoutes.js
var fs = require("fs");
var path = require("path");
//要遍历的文件夹所在的路径
var routesDir = path.resolve("routes/");
//根据文件路径读取文件,返回文件列表
function loadRoutes(app, dirPath) {
fs.readdir(dirPath, { withFileTypes: true }, function (err, files) {
if (err) {
console.warn(err, "读取文件夹错误!");
} else {
//遍历读取到的文件列表
files.forEach(function (dirent) {
const currentPath = path.join(dirPath, dirent.name);
if (dirent.isDirectory()) {
//文件夹
loadRoutes(app, currentPath);
} else if (dirent.isFile()) {
//文件
const relativePath = path.relative(__dirname, currentPath);
const router = require(relativePath);
//命名空间
const routerNamespace = path
.relative(routesDir, currentPath)
.replace(/\.js$/, "");
router.prefix("/" + routerNamespace); //Note: prefix always should start from / otherwise it won't work.
app.use(router.routes(), router.allowedMethods());
}
});
}
});
}
module.exports = function (app) {
loadRoutes(app, routesDir);
};
app.js
const load = require("./middleware/loadRoutes.js");
//加载全部路由
load(app);
webpack打包
一般情况node代码不需要打包,直接放到node服务器,即可运行。如果你的代码需要保护,防止别人滥用你的代码,可以考虑webpack打包,以增加别人滥改你代码的成本。
可以使用@vercel/ncc插件打包:
安装:
npm i @vercel/ncc
打包命令:
ncc build app.js -m -o dist
- -m #混淆、压缩代码
- -o #指定输出目录(这里根目录下的dist/)
- app.js 项目入口文件(在 koa框架中是 app.js)
打包之后生成dist目录:
修改服务器入口文件(\bin\www.js)项目的引入:
将var app = require("../app");
修改为var app = require("../dist/index.js");
即可。
你可能会遇到这种情况,明明写了路由,但是在请求时却是Not Found。原因可能是:
router.get("/", async (ctx, next) => {
await ctx.render("index", {
title: "Hello Koa 2!",
});
next();
});
ctx.render会解析pug文件为html,但是我们打包的时候并没有加载Pug解析器,所以代码会报错,从而Not Found。
不用纠结,因为本项目是前后端分离,后端只负责返回数据就好:
router.get("/", async (ctx, next) => {
ctx.body = "Hello Koa 2!";
next();
});
有个小插曲:我在百度查 打包node项目 时,看到了有@vercel/ncc、@zeit/ncc、pkg (前两个是webpack打包成单文件,pkg是编译成二进制文件)。于是就挑了一个,过几天写这篇文章时,忘了安装的是哪个了,只记得是全局安装,项目中的package.json文件无迹可查,还好有npm list -g --depth 0
。
修改的文件总览
package.json文件
{
"name": "server2",
"version": "0.1.0",
"private": true,
"scripts": {
"start": "node bin/www",
"dev": "nodemon bin/www --port=5152",
"prd": "pm2 start bin/www",
"build": "ncc build app.js -m -o dist",
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"debug": "^4.1.1",
"koa": "^2.7.0",
"koa-bodyparser": "^4.2.1",
"koa-convert": "^1.2.0",
"koa-json": "^2.0.2",
"koa-logger": "^3.2.0",
"koa-onerror": "^4.1.0",
"koa-router": "^7.4.0",
"koa-static": "^5.0.0",
"koa-views": "^6.2.0",
"pug": "^2.0.3",
"yargs": "^6.0.0"
},
"devDependencies": {
"colors-console": "^1.0.3",
"nodemon": "^1.19.1"
}
}
/bin/www.js文件
var app = require("../app");
var debug = require("debug")("demo:server");
var http = require("http");
var colors = require("colors-console");
var os = require("os");
var argv = require("yargs").argv;
console.time("Time");
//命令行参数:--port
if (argv.port && /^\d+$/.test(argv.port)) {
process.env.PORT = argv.port;
}
var port = normalizePort(process.env.PORT || "3000");
var server = http.createServer(app.callback());
server.listen(port);
server.on("error", onError);
server.on("listening", onListening);
//获取本机IPv4
function getIPAdress() {
var interfaces = os.networkInterfaces();
for (var devName in interfaces) {
var iface = interfaces[devName];
for (var i = 0; i < iface.length; i++) {
var alias = iface[i];
if (
alias.family === "IPv4" &&
alias.address !== "127.0.0.1" &&
!alias.internal
) {
return alias.address;
}
}
}
}
//规范化接口格式
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
return val;
}
if (port >= 0) {
return port;
}
return false;
}
function onError(error) {
if (error.syscall !== "listen") {
throw error;
}
var bind = typeof port === "string" ? "Pipe " + port : "Port " + port;
switch (error.code) {
case "EACCES":
console.error(bind + " requires elevated privileges");
process.exit(1);
break;
case "EADDRINUSE":
console.error(bind + " is already in use");
process.exit(1);
break;
default:
throw error;
}
}
//
function onListening() {
console.log("Node running at:");
console.log("- Local: ", colors("cyan", `http://localhost:${port}/`));
console.log("- Network:", colors("cyan", `http://${getIPAdress()}:${port}/`));
console.timeEnd("Time");
debug("Listening on " + bind);
}
新增koa.d.ts文件
declare module "colors-console";
新增/middleware/loadRoutes.js文件
var fs = require("fs");
var path = require("path");
const defaultOptions = {
extname: [".js"], //要加载的文件扩展名,非此扩展名不加载
root: "routes/", //要遍历的路由文件的根目录
//不添加命名空间的文件或目录,相对于root的路径,比如['login/'],表示/routes/login/ 下的所有文件
prefixIgnore: ["main.js"],
};
//要遍历的文件夹所在的路径
const routesDir = path.resolve(defaultOptions.root);
//根据文件路径读取文件,返回文件列表
function loadRoutes(app, dirPath) {
fs.readdir(dirPath, { withFileTypes: true }, function (err, files) {
if (err) {
console.warn(err, "读取文件夹错误!");
} else {
//遍历读取到的文件列表
files.forEach(function (dirent) {
const currentPath = path.join(dirPath, dirent.name);
if (dirent.isDirectory()) {
//文件夹
loadRoutes(app, currentPath);
} else if (dirent.isFile()) {
//文件
const relativePath = path.relative(__dirname, currentPath);
const extname = path.extname(relativePath); //文件扩展名
if (defaultOptions.extname.includes(extname)) {
const router = require(relativePath);
const extnameReg = new RegExp(defaultOptions.extname.join("|"));
const prefixIgnore = defaultOptions.prefixIgnore.some((s) => {
const ignoeSrc = path.resolve(defaultOptions.root, s);
return currentPath.indexOf(ignoeSrc) === 0;
});
if (!prefixIgnore) {
//命名空间
const routerNamespace = path
.relative(routesDir, currentPath)
.replace(extnameReg, "");
router.prefix("/" + routerNamespace); //Note: prefix always should start from / otherwise it won't work.
}
app.use(router.routes(), router.allowedMethods());
}
}
});
}
});
}
module.exports = function (app, opt = {}) {
Object.assign(defaultOptions, opt);
loadRoutes(app, routesDir);
};
app.js文件
const Koa = require("koa");
const app = new Koa();
const json = require("koa-json");
const onerror = require("koa-onerror");
const bodyparser = require("koa-bodyparser");
const logger = require("koa-logger");
const load = require("./middleware/loadRoutes.js");
onerror(app);
// middlewares
app.use(
bodyparser({
enableTypes: ["json", "form", "text"],
})
);
app.use(json());
app.use(logger());
app.use(require("koa-static")(__dirname + "/public"));
// logger
app.use(async (ctx, next) => {
const start = new Date();
await next();
const ms = new Date() - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});
//加载路由
load(app);
// error-handling
app.on("error", (err, ctx) => {
console.error("server error", err, ctx);
});
module.exports = app;
参考资料:
CSDN:nodejs遍历文件夹下所有文件
百度:查看电脑IP地址的CMD命令是多少?老王教你如何使用,很简单
知乎:node.js express模板初学遇到.address().address为"::"为什么?
CSDN:node.js获取计算机本地ip
CSDN:node环境实现console输出不同颜色
CSDN:ANSI转义代码(ansi escape code)
博客园:nodejs 修改端口号 process.env.PORT(window环境下)
ncc - koa 后台源码加密打包工具 @vercel/ncc - webpack node打包更正规
nodejs 几个方便的打包工具