【免费下载链接】nodebestpractices
✅ The Node.js best practices list (July 2026)
项目地址:
https://gitcode.com/GitHub_Trending/no/nodebestpractices
点击查看 免费下载
本篇文章源自 nodebestpractices(The Node.js best practices list,Node.js 最佳实践清单)的"项目结构(Project Structure)"章节。该章节的核心主张是:把 Express 的 应用声明(app) 与 服务器网络配置(server) 拆分为两个文件。本文将完整展开这一实践的原理、双语言代码范式、进程内测试方法,并结合仓库源码与示例,说明它如何提升可测试性、可部署性与代码整洁度。
为什么要把 app 与 server 分离
最新版本的 Express 应用生成器自带一项值得保留的实践:API 的声明与网络相关配置(端口、协议等)彼此分离。换言之,负责"应用长什么样"(路由、中间件、业务逻辑)的代码,与负责"应用如何监听网络"(端口号、HTTP 协议、进程启动)的代码,应当放在不同的文件中。
这一拆分带来的核心收益有四点:
从仓库的文档组织看,这一实践位于 sections/projectstructre 目录下,与"将 Express 保持在自身边界内"的分层实践(createlayers.md)同属一个主题序列:后者从纵向上把组件划分为 entry-points(入口层)、domain(领域层)、data-access(数据访问层),而本实践从横向上先把"应用本体"与"网络入口"切割开——可以看作是分层思想在 Express 项目里最轻量、最易落地的一步。
app.js / app.ts:只声明 API,不监听端口
按照该实践,API 声明应当位于 app.js(或 TypeScript 项目的 app.ts)中。这里只做三件事:创建 Express 实例、挂载全局中间件、挂载路由模块:
const app = express();
app.use(bodyParser.json());
app.use('/api/events', events.API);
app.use('/api/forms', forms);
关键点是:这段代码没有任何 app.listen() 调用。文件在模块加载完成后即返回一个可被其他模块引用的 app 实例。它既可以被 /bin/www 这样的启动器拿去创建服务器,也可以被测试框架直接拿去发起进程内请求——这正是后面"进程内测试"能够成立的前提。
从仓库示例看,sections/examples/dockerfile/src/app.ts 中的最小 Express 应用采用了同一形态:先 import * as express from 'express' 并创建 const app = express(),再定义路由处理器。虽然该示例为了演示的简洁性直接调用了 app.listen(3000)(将其作为 Docker 演示入口),但在正式项目中,这正是应当被拆分出去的那一行——把"创建应用"与"启动监听"从同一个文件里剥离开来。
/bin/www:服务器网络声明的唯一归属
网络层的声明应当位于 /bin/www(Express 生成器约定的启动器文件位置)。它的职责是:从环境变量读取端口、把端口写入 Express、创建 HTTP 服务器:
const app = require('../app');
const http = require('http');
// Get port from environment and store in Express.
const port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
// Create HTTP server.
const server = http.createServer(app);
对应 TypeScript 版本:
import app from '../app';
import http from 'http';
// Get port from environment and store in Express.
const port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
// Create HTTP server.
const server = http.createServer(app);
这里有三个值得注意的实现细节:
- normalizePort:这是 Express 生成器自带的工具函数,负责把端口值规范化为合法数字、具名管道或 false(表示端口无效),确保后续 server.listen() 拿到的是安全可用的端口值;
- process.env.PORT || '3000':端口优先从环境变量注入,缺省回退到 3000。这让同一个 API 在本地、CI、容器和集群环境中都可以复用——容器平台只需注入 PORT 环境变量即可改变监听端口,无需改动任何代码;
- http.createServer(app):把 Express 应用实例作为请求处理回调交给 Node 原生 HTTP 服务器。这意味着协议层(HTTP/HTTPS/HTTP2)的切换发生在 /bin/www 这一层,app 模块本身完全不感知网络协议细节。这也印证了分层文档 createlayers.md 中的论断:当领域/应用层不感知任何边缘协议时,它就能服务于任意客户端,而不只是 HTTP 调用。
进程内测试:用 supertest 在不启动网络的情况下验证 API
分离 app 与 server 最直接的收益体现在测试环节。supertest(原文档称之为"流行的测试包")允许直接把 Express 应用实例传入并发起 HTTP 风格的请求断言,全程不绑定端口、不做真实网络调用:
const app = express();
app.get('/user', (req, res) => {
res.status(200).json({ name: 'tobi' });
});
request(app)
.get('/user')
.expect('Content-Type', /json/)
.expect('Content-Length', '15')
.expect(200)
.end((err, res) => {
if (err) throw err;
});
TypeScript 版本(带类型标注):
const app = express();
app.get('/user', (req: Request, res: Response) => {
res.status(200).json({ name: 'tobi' });
});
request(app)
.get('/user')
.expect('Content-Type', /json/)
.expect('Content-Length', '15')
.expect(200)
.end((err: Error) => {
if (err) throw err;
});
这段代码演示了 supertest 的核心用法:request(app) 直接接收 app 实例;.get('/user') 指定方法与路径;链式 .expect(…) 可以同时断言响应头(Content-Type、Content-Length)与状态码(200);最后 .end(callback) 收尾,回调中抛出任何断言错误。
这种测试方式的优势与文件拆分直接相关:测试只需 require('../app')(或 import app from '../app')就能拿到完整的应用实例,而 /bin/www 里的端口逻辑被完全旁路——不需要关心端口是否被占用、不需要等服务器就绪、不产生额外的网络开销。配合 sections/testingandquality 目录下的测试最佳实践(如 AAA 模式 aaa.md、测试命名三段式 3-parts-in-name.md、中间件测试 test-middlewares.md),可以构建出又快又稳的 API 测试套件。
与容器化部署的配合
app/server 拆分在容器化场景中同样适用。仓库的 Docker 示例 展示了这一点:Dockerfile 的构建阶段先执行 npm ci(以 lockfile 为准)再 npm run build,运行阶段则通过
CMD [ "node", "dist/app.js" ]
启动构建产物(见 Dockerfile,对应 package.json 中的 build: tsc –outDir dist … 脚本)。容器启动命令指向的正是应用入口文件——这与"应用模块(app)与进程启动(entry)分离"的思路一脉相承:镜像内部通过 EXPOSE 3000 声明端口,实际端口在运行时由 PORT 环境变量注入,应用代码本身不硬编码监听端口。这也呼应了仓库 Docker 章节中关于生产镜像、多阶段构建的最佳实践。
落地建议:从拆分到分层
综合本节文档(separateexpress.chinese.md 与英文原版 separateexpress.md 同属该主题)及 createlayers.md 的论述,落地时可以遵循以下递进式步骤:
完成这三步后,项目将获得:毫秒级的进程内测试、可移植的网络部署、清晰的职责边界——这正是 Node.js 项目结构最佳实践希望达成的最终状态。
赞
【免费下载链接】nodebestpractices
✅ The Node.js best practices list (July 2026)
项目地址:
https://gitcode.com/GitHub_Trending/no/nodebestpractices
点击查看 免费下载
相关推荐
IPTVnator 官网博客封面设计:一张“官方信号”插画如何贯通 Astro 内容集合与 Open Graph 元数据
BetterNCM完整安装指南:3分钟搞定网易云插件管理终极方案
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网硕互联帮助中心






评论前必须登录!
注册