资讯动态

Sails Hooks 使用指南:在 Sails 应用中加载、调用与配置自定义 Hook

发布时间:2026/9/20 20:29:49 来源:尧图企业网站定制
Sails Hooks 使用指南在 Sails 应用中加载、调用与配置自定义 Hook【免费下载链接】sailsRealtime MVC Framework for Node.js项目地址: https://gitcode.com/gh_mirrors/sa/sailsSails 的 Hook 系统允许开发者以模块化的方式向框架核心注入新功能。本文以官方文档 Using hooks in a Sails app 为主线系统讲解如何在 Sails 应用中接入项目 Hookapi/hooks与可安装 Hooknode_modules中的 npm 包、通过sails.hooks调用 Hook 暴露的方法、使用标准配置文件定制 Hook 行为以及如何借助sails.config.installedHooks解决命名冲突。读完本文你将掌握从「安装一个 Hook」到「按需重命名、重定向其配置键」的完整实战能力并能结合仓库源码理解 Sails 底层发现与加载 Hook 的完整机制。先厘清概念Sails 中的三类 Hook在动手之前先明确 Sails 生态中的三类 Hook详见 Hooks 总览核心 HookCore hooks随 Sails 内核分发内置提供请求处理、蓝图路由、Waterline 数据库集成等基础能力。核心 Hook 的清单定义在 lib/app/configuration/default-hooks.js例如moduleloader、logger、request、views、blueprints、responses、helpers、pubsub、policies、services、security、i18n、userconfig、session、http、userhooks等。日常开发中很少需要直接调用它们的方法。项目 HookProject hooks位于应用自身的api/hooks/文件夹用于在单个应用内复用 Hook 特性如defaults、routes无需跨应用共享。可安装 HookInstallable hooks通过npm install安装到node_modules的插件式模块便于在多个 Sails 应用之间共享功能或发布到 npm 与社区分享。本文聚焦的usinghooks.md文档正是指导你如何使用上述后两类自定义 Hook。使用项目 Hook从 api/hooks 加载要在应用中使用一个项目 Hook步骤如下检查应用的api/hooks文件夹是否存在不存在则创建参考 创建项目 Hook 的规范编写 Hook在api/hooks/hook-name/index.js中导出一个接收sails实例并返回配置对象的函数或将现成的 Hook 文件夹整体复制进api/hooks。项目 Hook 最简单的形态如下保存为api/hooks/my-basic-hook/index.jsmodule.exports function myBasicHook(sails) { return {}; };按 Hook 规范每个 Hook 都应保存在独立文件夹中、入口文件名为index.js文件夹名即 Hook 的唯一标识。用sails lift --verbose启动应用后若加载成功日志中会出现verbose: my-basic-hook hook loaded successfully.从源码看项目 Hook 的发现逻辑位于 lib/hooks/moduleloader/index.js 的loadUserHooks()方法它通过includeAll.optional()扫描sails.config.paths.hooks即api/hooks目录筛选出.js/.coffee等受支持扩展名的文件支持「单文件即 Hook」与「子文件夹 index.js」两种形式depth: 2。随后在 lib/hooks/userhooks/index.js 的initialize()中这些定义会被并入sails.hooks字典参与后续加载若设置了sails.config.loadHooks则只加载其中显式列出的用户 Hook。使用可安装 Hooknpm install 与手动放置可安装 Hook 是放在node_modules中的 Sails 插件使用方式有两种方式一npm 安装推荐npm install sails-hook-autoreload安装后 Sails 在启动时会自动从node_modules中识别它。识别依据是模块package.json中必须声明sails.isHook: true详见 创建可安装 Hook{ name: sails-hook-your-hook-name, version: 0.0.0, description: a brief description of your hook, main: index.js, sails: { isHook: true } }方式二手动复制或链接把你创建好的可安装 Hook 文件夹直接复制或使用npm link软链进应用的node_modules目录。底层识别规则moduleloader 如何判定「这是一个 Hook」lib/hooks/moduleloader/index.js 的loadUserHooks()中对node_modules的扫描严格遵循以下规则均有对应源码分支只读取各模块的package.json若sails.isHook缺失或为假则直接忽略第 454 行若模块没有被记录在应用package.json的dependencies/devDependencies/optionalDependencies中则忽略并输出 debug 提示第 458 行若该模块名命中默认核心 Hook 包名从 default-hooks.js 中过滤true之外的值得到则忽略以便可安装 Hook 安全地覆盖同名核心 Hook第 467 行递归扫描深度为 3支持 npm 命名空间scoped package即node_modules/scope/sails-hook-foo这种结构第 480 行。命名规则sails-hook- 前缀会被剥离可安装 Hook 的文件夹名通常以sails-hook-开头Sails 在加载时会剥离该前缀作为 Hook 的默认内部标识。剥离逻辑同样在 lib/hooks/moduleloader/index.js 第 529 行hookName identity.replace(/^(.?[\/\\])?(sails-hook-)?/, );即先去掉 npm 命名空间scope/再去掉sails-hook-前缀。例如node_modules/sails-hook-email的默认标识就是email。若文件夹名不带前缀如node_modules/shouty则直接用文件夹名shouty这一点在 test/integration/hook.3rdparty.test.js 第 248–308 行的shouty用例中得到了验证。调用 Hook 方法sails.hooks 字典Hook 通过主函数返回对象中暴露的任何自定义键都会挂载到sails.hooks[hook-name]上。例如社区常见的sails-hook-email提供了sails.hooks.email.send()方法注意sails-hook-前缀已被剥离因此是email而非sails-hook-email。具体某个 Hook 暴露了哪些方法以该 Hook 自身的文档为准。结合 Hook 规范 中的示例公开数据/函数与私有数据/函数的区分方式如下// File api/hooks/myhook/index.js module.exports function (sails) { // 这个变量是私有的 var foo bar; return { // 这个变量是公开的 abc: 123, // 这个函数是公开的 sayHi: function (name) { console.log(greet(name)); } }; // 这个函数是私有的 function greet (name) { return Hi, name !; } };上述公开的abc与sayHi将分别以sails.hooks.myhook.abc和sails.hooks.myhook.sayHi的形式对外可用。仓库中的 test/integration/fixtures/hooks/installable/shout/index.js 是一个完整的可安装 Hook 参考实现它通过defaults提供默认配置、在initialize中读取配置并设置公开属性this.isShoutyHook true、并通过routes.before绑定GET /shout路由。对应测试 test/integration/hook.3rdparty.test.js 第 67–77 行断言sails.hooks.shout存在且默认配置被正确合并。配置 Hook标准配置文件与命名空间可安装 Hook 安装完毕后可用 Sails 常规的配置文件对其进行配置例如config/local.js、config/env/development.js或自建的任意config/*.js文件。配置键的命名空间规则Hook 的配置通常以其名称去掉sails-hook-前缀为命名空间。以sails-hook-email为例其from设置项可通过sails.config.email.from访问。每个 Hook 支持哪些配置项以其文档说明为准。底层原理defaults 与configKeyHook 配置的合并机制由 Hook 规范中的.defaults特性定义defaults可以是对象或函数若是函数接收一个参数config即当前已生效的 Sails 配置可来自sails lift --prod命令行参数、编程式Sails.lift({...})参数或.sailsrc文件并返回一个代表配置默认值的纯对象对于可安装 Hook官方强烈建议使用特殊的__configKey__键来承载默认配置这样终端用户才可以通过installedHooks配置更换配置键。默认情况下使用__configKey__的 Hook其配置键就是 Hook 名。例如sails-hooks-myawesomehook声明如下defaults{ __configKey__: { name: Super Bob } }则默认向sails.config.myawesomehook.name提供默认值若用户将 Hook 名覆盖为foo则默认值改挂到sails.config.foo.name下。从源码看__configKey__的替换发生在 lib/app/private/loadHooks.js 的applyDefaults()中第 148–151 行将hook.defaults.__configKey__迁移到hook.defaults[hook.configKey]后删除原键再通过defaultsDeep(sails.config, defaults)做深合并。测试 test/integration/hook.3rdparty.test.js 第 162–186 行验证了把配置键改为shoutHook后shoutHook.phrase能正确覆盖默认值make it rain。加载顺序保证configure 先于 initialize需要留意的是Hook 的configure()在所有 Hook 的defaults合并完成后才会执行并且所有 Hook 的configure都先于任何initialize执行。因此你可以在initialize中安全地读取其他 Hook 的配置但不能在configure中依赖其他自定义 Hook 的配置自定义 Hook 的加载顺序不保证。configure内可通过this.configKey拿到当前 Hook 的配置键例如按ssl开关切换 API 端点configure: function() { if (sails.config[this.configKey].ssl true) { sails.config[this.configKey].url https:// sails.config[this.configKey].domain; } else { sails.config[this.configKey].url http:// sails.config[this.configKey].domain; } }这些阶段prepare → defaults → configure → load在 lib/app/private/loadHooks.js 中由async.series严格编排第 257–353 行其中moduleloader、userconfig、userhooks三个特殊 Hook 被优先单独处理其余 Hook 再统一经历 prepare/defaults/configure/load 四个阶段。更改 Sails 加载可安装 Hook 的方式installedHooks 配置在极少数情况下你可能需要更改 Sails 为某个可安装 Hook 使用的名称或更改其配置键。典型场景包括应用里已经有一个与可安装 Hook 同名的项目 Hook某个配置键已被其他用途占用。为规避这类冲突Sails 提供了sails.config.installedHooks.hook-identity配置项。Hook identity 永远是该 Hook 安装所在的文件夹名即node_modules中的目录名如sails-hook-email注意此处不带剥离后的短名。官方文档给出的完整示例需自行创建config/installedHooks.js文件// config/installedHooks.js module.exports.installedHooks { sails-hook-email: { // 将该 Hook 加载到 sails.hooks.emailHook 而非 sails.hooks.email name: emailHook, // 使用 sails.config.emailSettings 而非 sails.config.email 来配置该 Hook configKey: emailSettings } };要点说明name覆盖 Hook 在sails.hooks字典中的标识对应测试 test/integration/hook.3rdparty.test.js 第 188–223 行设置name: foobar后Hook 出现在sails.hooks.foobar默认配置挂在sails.config.foobar.phraseconfigKey覆盖配置命名空间键对应同文件第 162–186 行设置configKey: shoutHook后配置从sails.config.shoutHook读取两者可单独使用也可组合使用如果你把name设为某个已存在的核心 Hook 名如security则会覆盖核心 Hook——测试第 225–243 行验证了设置name: security后sails.hooks.security.isShoutyHook为真。源码中的解析优先级在 lib/hooks/moduleloader/index.js 第 516–530 行Hook 最终标识的解析优先级为package.json中sails.hookName字段高级用法通常用于 scoped 包覆盖核心 Hook详见 创建可安装 Hook 中的mycoolhooks/sails-hook-sockets示例sails.config.installedHooks[identity].name默认规则剥离命名空间与sails-hook-前缀后的文件夹名。配置键的赋值则在该文件第 559 行完成hook.configKey (installedHooks[identity] installedHooks[identity].configKey) || hookName。冲突时的行为从源码可见两条重要的冲突处理规则若node_modules中的可安装 Hook 与api/hooks中的项目 Hook 同名项目 Hook 优先同时会打印E_INVALID_HOOK_NAME警告第 541–553 行若可安装 Hook 与核心 Hook 同名可安装 Hook 会覆盖核心 Hook第 537–539 行打印 verbose 日志。验证与排错确认 Hook 真正被加载安装或编写 Hook 后可通过以下方式确认其已被正确加载verbose 日志运行sails lift --verbose加载成功的 Hook 会打印verbose: hook-name hook loaded successfully.该日志由 lib/app/private/loadHooks.js 第 237 行输出并附带耗时信息。Hook 加载事件每个 Hook 初始化完成后会触发hook:hook-name:loaded事件由 lib/app/private/loadHooks.js 第 238 行sails.emit(hook: id :loaded)发出。这让一个 Hook 可以等待另一个 Hook 就绪例如在initialize()中用sails.on(hook:orm:loaded, ...)等待 orm或用sails.after([hook:orm:loaded, hook:mygreathook:loaded], ...)等待多个 Hook。超时设置Hook 的initialize默认有 10 秒文档层面完成时限从源码看lib/app/private/loadHooks.js 第 177 行定义的默认超时为DEFAULT_HOOK_TIMEOUT 4000040 秒优先取sails.config[configKey]._hookTimeout其次取sails.config.hookTimeout。若 Hook 初始化耗时较长可在其defaults中设置_hookTimeout毫秒来放宽限制参见 hookspec/defaults.md 与 hookspec/initialize.md。集成测试仓库的 hook.3rdparty.test.js 与 hooks.user.test.js 覆盖了安装、禁用hooks.shout: false/false、配置覆盖、installedHooks重命名等典型场景可作为排查问题的参照。延伸阅读Hooks 总览含三类 Hook 定义Hook 规范defaults / configure / initialize / routes / registerActions创建项目 Hook创建可安装 Hook含 hookName、测试与发布核心 Hook 默认清单Hook 发现与解析源码Hook 加载流程源码prepare / defaults / configure / load【免费下载链接】sailsRealtime MVC Framework for Node.js项目地址: https://gitcode.com/gh_mirrors/sa/sails创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价