扩展框架

扩展框架

AdonisJS 的架构让扩展框架变得非常容易。我们通过"自己吃自己的狗粮"的方式,利用框架核心 API 构建出由第一方软件包组成的生态。

在本指南中,我们将探索你可以用来通过软件包或在应用代码库中扩展框架的不同 API。

宏与 getter

宏(macro)和 getter 提供了一种向类的原型添加属性的 API。你可以把它们看作 Object.defineProperty 的语法糖。在底层,我们使用了 macroable 软件包,你可以参考它的 README 来了解深入的技术说明。

由于宏和 getter 是在运行时添加的,你需要通过声明合并告知 TypeScript 所添加属性的类型信息。

你可以把添加宏的代码写在一个专用文件(例如 extensions.ts)中,并在服务提供者的 boot 方法里导入它。

providers/app_provider.ts
export default class AppProvider {
async boot() {
await import('../src/extensions.js')
}
}

在下面的示例中,我们向 Request 类添加了 wantsJSON 方法,并同时定义了它的类型。

src/extensions.ts
import { Request } from '@adonisjs/core/http'
Request.macro('wantsJSON', function (this: Request) {
const firstType = this.types()[0]
if (!firstType) {
return false
}
return firstType.includes('/json') || firstType.includes('+json')
})
src/extensions.ts
declare module '@adonisjs/core/http' {
interface Request {
wantsJSON(): boolean
}
}
  • declare module 调用中的模块路径必须与你导入该类时使用的路径相同。
  • interface 名称必须与你添加宏或 getter 的类名相同。

Getter

Getter 是添加到类上的惰性求值属性。你可以使用 Class.getter 方法添加一个 getter。第一个参数是 getter 名称,第二个参数是用于计算属性值的回调函数。

Getter 回调不能是异步的,因为 JavaScript 中的 getters 无法是异步的。

import { Request } from '@adonisjs/core/http'
Request.getter('hasRequestId', function (this: Request) {
return this.header('x-request-id')
})
// 你可以按如下方式使用该属性。
if (ctx.request.hasRequestId) {
}

Getter 可以是单例的,即用于计算 getter 值的函数只会被调用一次,其返回值会被缓存,供该类的实例复用。

const isSingleton = true
Request.getter('hasRequestId', function (this: Request) {
return this.header('x-request-id')
}, isSingleton)

可扩展的类

以下是可以使用宏和 getter 进行扩展的类的列表。

ClassImport path
Application@adonisjs/core/app
Request@adonisjs/core/http
Response@adonisjs/core/http
HttpContext@adonisjs/core/http
Route@adonisjs/core/http
RouteGroup@adonisjs/core/http
RouteResource@adonisjs/core/http
BriskRoute@adonisjs/core/http
ExceptionHandler@adonisjs/core/http
MultipartFile@adonisjs/core/bodyparser

扩展模块

大多数 AdonisJS 模块都提供了可扩展的 API 来注册自定义实现。以下是这些 API 的汇总列表。