ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Node.js 技巧:利用 `module.parent` 让模块既可独立运行又可被 `require` 引用

Node.js 技巧:利用 `module.parent` 让模块既可独立运行又可被 `require` 引用 教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载导读在 Node.js 开发中同一个文件常常面临两种执行方式被node something.js直接运行或被其他模块通过require(./something.js)引入。本文基于 jstips 项目第 17 号技巧原文文档讲解如何用module.parent在代码中区分这两种场景让你写出既能独立启动、又能作为模块复用的通用文件例如带命令行调试入口的 Express 应用、可单测的脚本等。核心机制两种运行方式的本质区别在 Node.js 中一段.js文件被加载时Node 会为其创建一个module对象。该对象上有一个特殊属性module.parent它指向加载当前模块的那个父模块当文件通过node something.js直接运行时它是程序的入口模块没有父模块此时module.parent为null即 falsy当文件被其他代码require(./something.js)引用时module.parent指向发起require调用的那个模块对象。因此if (!module.parent)就是一条精确的运行方式探测器判断当前代码是被当作入口直接执行还是被当作依赖引入。原版示例一个文件两种行为原文档给出了一个 Express 风格的最小示例完整继承如下if (!module.parent) { // ran with node something.js app.listen(8088, function() { console.log(app listening on port 8088); }) } else { // used with require(/.something.js) module.exports app; }这段代码的意图非常清晰直接运行时node something.js立即启动 HTTP 服务监听8088端口并打印启动日志方便本地手动验证被引用时require(./something.js)不启动服务只导出app对象把启动权交给调用方例如测试框架、PM2、上级应用。注意原文档的require(/.something.js)写法是示意性注释实际引用时应使用相对路径require(./something.js)不带前导斜杠这与本仓库 README 中写一个能复用的模块的惯例一致。为什么有用独立交互与复用兼顾这个模式的核心价值在于打破要么是入口、要么是模块的二元对立让一个文件同时胜任两种角色典型场景包括独立调试与交互模块中包含的业务函数或服务可以被单独运行快速验证行为不必为了测试一个函数而把整个应用跑起来自动化测试测试代码require该文件拿到内部逻辑直接断言输出而不触发服务端口监听避免端口占用和副作用CLI 工具与库的双重形态同一份代码既可作为命令行工具执行又可作为库被编程式调用避免误启动当模块被他人引用时确保不会意外监听端口或执行副作用操作把控制权完整交给引用方。深入原理module对象与模块系统行为从 Node.js 模块系统的工作机制看这个技巧建立在两条事实之上每个文件都被包进一个模块作用域Node 加载文件时会包装成类似(function (exports, require, module, __filename, __dirname) { ... })的形式module是内置注入的对象module.parent在解析阶段即被赋值require解析成功后Node 内部会将正在加载的子模块的parent指向发起加载的模块。因此判断是同步的、确定的不存在竞态问题。从代码结构看module.exports app这一分支还利用了 Node 模块缓存的特性被require一次后模块会被缓存后续再次require直接返回同一个导出对象app在进程内是单例的。补充require.main module判定法除了module.parentNode.js 官方模块文档还提供了另一种等效判断require.main module。当文件是入口模块时require.main指向该模块自身该表达式为true否则为false。两种写法在是否为入口的判断上等价module.parent更直观地表达父模块是谁而require.main module在语义上更贴合入口程序概念可根据团队习惯选用。注意官方文档提示module.parent在特定加载方式如 REPL、node -e脚本下的取值可能不同因此需要明确程序支持的运行方式。在 jstips 项目中的上下文本技巧是 jstips 仓库README.md收录的第 17 号 JavaScript 技巧位于_posts/en/javascript/目录并提供了 简体中文、繁体中文、西班牙语 多语言版本方便跨语言读者对照理解。仓库本身是一个短小精悍的 JavaScript 技巧集按 POST_TEMPLATE.md 的规范组织文章结构包含tip-number、tip-username、tip-tldr等 front matter 字段并鼓励读者在 CONTRIBUTING.md 指导下提交自己的技巧。本技巧的 front matter 中tip-tldr已精炼概括其核心思想让程序根据运行自require(./something.js)还是node something.js而做不同的处理。实战一个完整可运行的示例把上面的模式落地为一段可直接复制的代码以一个导出sum函数的模块为例// math.js function sum(a, b) { return a b; } if (!module.parent) { // 直接运行node math.js const result sum(2, 3); console.log(sum(2, 3) , result); } else { // 被引用require(./math.js) module.exports sum; }运行node math.js控制台输出sum(2, 3) 5方便快速验证函数行为在其他文件中const sum require(./math.js)得到的是可调用的函数对象不会触发任何打印副作用。注意事项与边界入口模块判断与进程参数无关判断依据是加载方式而非命令行参数module.parent在加载阶段就已确定避免在分支外执行副作用代码建议把会立即产生副作用的逻辑如监听端口、读写文件、打印都放进if (!module.parent)分支被引用时保持纯净ESM 时代的迁移本技巧基于 CommonJS 模块系统若项目使用 ES Moduleimport/export没有module.parent属性通常改用import.meta.url与process.argv[1]对比或借助url.fileURLToPath判断是否为入口迁移时需注意模块缓存语义被require后模块即被缓存若希望每次引用都得到新实例需要额外设计工厂函数或清除缓存本模式默认按单例处理。总结if (!module.parent)是 Node.js 中一文件两用的经典惯用法直接运行时执行启动逻辑被引用时导出模块接口。掌握它能让你的脚本同时具备可交互、可调试、可测试、可复用四种能力是编写高质量 Node.js 模块时值得记下的一个实用技巧。赞分享教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载相关推荐Nexe让Node.js应用秒变独立可执行文件的革命性工具Nexe让Node.js应用秒变独立可执行文件的革命性工具 你还在为Node.js应用部署时需要安装Node环境而烦恼吗还在为用户抱怨缺少依赖无法运行而构建工具开发工具CLI告别复杂部署Nexe让Node.js应用秒变独立可执行文件的终极指南告别复杂部署Nexe让Node.js应用秒变独立可执行文件的终极指南 Nexe是一款强大的命令行工具能够将你的Node.js应用程序编译成单个可执行文件彻构建工具开发工具CLIpkg资源压缩技巧减小可执行文件体积pkg资源压缩技巧减小可执行文件体积 你是否还在为Node.js项目打包后的可执行文件体积过大而烦恼本文将详细介绍如何通过pkg工具的压缩功能有效减小最终开发工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表