Remix 中没有中间件,面对重复的代码应该如何是好?

一、问题

Remix 目前还没有中间件,开发路由时,有些公用的代码需要重复的编写。例如每一个路由 action/loader 都需要判断是否授权。

重复是我们不愿意看到的。

那么有没有办法解决重复的问题?

二、别的框架是如何解决重复问题的?

  • express: 中间件

大部分框架都是使用中间件来解决重复的代码问题。但是明显现在 Remix 还没有中间件支持。

  • 装饰器函数

一个装饰器在写好了,可以在类中各种装饰。但是装饰器也是有限制了的。只能在 class 中使用。

到此我们就引出了我们的正题:

在 Remix 中使用 class static method + 装饰器,解决重复代码大量重复的问题。

三、问题代码

ts 复制代码
export const action: ActionFunction = async ({
  request,
  params,
}: ActionFunctionArgs) => {
  const session = await getSession(request.headers.get("Cookie"));
  const lang = params?.lang || defaultLang;

  const dataDto = await request.json();
  let validateDataDto: TLogin;
   // 登录流程...
};

这是一个简单的 action 处理,如果我们登录,每次进入需要授权的页面都需要先进行授权和认证,显示的调用与正常业务无关的内容。

四、为什么会思考到静态函数?

ts 复制代码
const date = Date.now()

Date 是 JS 内置的一个函数,now 方法就是一个静态方式,说明其实我们隐式写 JS、TS 的时候一直在与静态方法打交道。然后再 TS 装饰器中不能直接修饰函数,而可以修饰静态方式。这样我们就可以使用装饰器,在对静态函数进行修饰了。

五、ts 中的 class + 静态函数

ts 复制代码
function console() {
    console.log("loader call")
}
export class LoginHandler {
    @console
    static loader() {}
     @console
    static action() {}
}

console 的函数用于装饰 loader 在 loader 函数调用之前调用。在我们 Remix 路由中,我们就可以直接导入class类型和静态方法。

ts 复制代码
import {LoginHandler} from '~/LoginHandler'

export const action: ActionFunction = LoginHandler.action
export const loader: ActionFunction = LoginHandler.loader

当然如果有更加项目可能逻辑比这个复杂,下面我们系统的 TS 的装饰器内容。

六、装饰器学习资源

七、在 TS stage 2 下中使用装饰器需要完成以下步骤

注意:虽然装饰器已经到了第三个阶段,但是以下还是

ts.config 配置: 基础配置

ts 复制代码
{
  "compilerOptions": {
    "target": "ES5",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
  }
}

如果要支持反射

sh 复制代码
npm i reflect-metadata --save
ts 复制代码
{
  "compilerOptions": {
    "target": "ES5",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
  }
}

八、装饰器分类

  • 类装饰器:应用于类构造函数,可以用来修改类的行为或元数据。
  • 方法装饰器:应用于类的方法,可以修改方法的行为或元数据。
  • 访问符装饰器: 应用于类的放问题,可以修改该访问器的行为和元数据。
  • 属性装饰器:应用于类的属性,可以修改属性的行为或元数据。
  • 参数装饰器:应用于类的构造函数或方法的参数,可以修改参数的行为或元数据。

九、普通装饰器和装饰器工厂

就是一个带有 target 参数的函数:

ts 复制代码
function console(target) {
    // do some things
}

target 就是我们装饰的目标(类,函数,属性,函数参数)

装饰器工厂,其实就是一个典型的 JavaScript 闭包函数:

ts 复制代码
function color(value: string) {
  return function (target) {
    // do something with 'target' and 'value'...
  };
}

很简单:函数和闭包函数,以及它们的参数需要熟悉。

十、方法装饰器

ts 复制代码
function MethodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log("Method Decorator called on: ", propertyKey);
}
  1. target: 装饰的目标类的原型对象。
  2. propertyKey: 被装饰的方法的名称。
  3. descriptor: 被装饰方法的属性描述符。

场景需求,我们将装饰的目标方法重写

ts 复制代码
function MethodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log("Method Decorator called on: ", propertyKey);

    const originalMethod = descriptor.value; // 保存原有方法

    // 重写原始方法
    descriptor.value = function(...args: any[]) {
        console.log("Method execution starts");
        const result = originalMethod.apply(this, args); // 调用原始方法
        console.log("Method execution ends");
        return result;
    };

    return descriptor;
}

其实就是简单存储原有方法,然后干一些需要自定义事情,然后再调用原来的方式,返回结果的过程。

十一、多装饰器执行顺序

  • 对于类的装饰器,执行顺序是从类的上方向下执行。
  • 而对于类的方法、属性或参数的装饰器,执行顺序是从左到右执行。

十二、有一个定义良好的顺序的装饰器应该这样做:

ts 复制代码
// 1. 类装饰器
function ClassDecorator(target: any) {
    console.log("Class Decorator");
}

// 2. 方法装饰器
function MethodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log("Method Decorator on: ", propertyKey);
}

// 3. 属性装饰器
function PropertyDecorator(target: any, propertyKey: string) {
    console.log("Property Decorator on: ", propertyKey);
}

// 4. 参数装饰器
function ParameterDecorator(target: any, propertyKey: string, parameterIndex: number) {
    console.log("Parameter Decorator on: ", propertyKey, " with index: ", parameterIndex);
}

@ClassDecorator
class ExampleClass {
    @PropertyDecorator
    exampleProperty: string;

    @MethodDecorator
    exampleMethod(@ParameterDecorator param1: string, @ParameterDecorator param2: number) {
        console.log("Example method called");
    }
}
  1. 类装饰器:放在最上面,因为它们应用于整个类,影响类的构造函数及其行为。
  2. 方法装饰器:在类装饰器之后,因为它们应用于类的方法,可以修改方法的行为或元数据。
  3. 属性装饰器:在方法装饰器之后,因为它们应用于类的属性,可以修改属性的行为或元数据。
  4. 参数装饰器:放置在最后,因为它们应用于类的构造函数或方法的参数,可以修改参数的行为或元数据。

十三、内置装饰器

内置装饰器:TypeScript提供了一些内置的装饰器,例如

  • @deprecated: 表示废弃
  • @sealed: 表示冻结
  • @readonly: 表示只读
  • @experimental:试验性质
  • @abstract:表示抽象方法
  • ...

十四、为什么需要 reflect-metadata

reflect-metadata 提供了一种在 JavaScript 运行时获取 TypeScript 类的装饰器和类型信息的方式,使得开发者能够更灵活地处理类的元数据和类型信息,从而实现一些高级的编程模式和功能。

十五、使用装饰器库的框架和库类

  • class-transformer
  • typeorm
  • Angular
  • NestJS

十六、小结

相关推荐
柯克七七14 小时前
我把 bug 修得太干净了,测试组以为这个模块本来就没问题
前端·javascript·typescript
退休倒计时15 小时前
【每日一题】LeetCode 39. 组合总和 TypeScript
算法·leetcode·typescript
yyt36304584115 小时前
KlineChartQuant Tooltip 高频交互 200FPS 性能优化完整复盘
前端·经验分享·性能优化·typescript·vue·交互·chrome devtools
用户09340777351420 小时前
HarmonyOS WPS Open SDK 实践:办公审批附件「打开—编辑—回传」代码实现
typescript·harmonyos
Flynt21 小时前
TypeScript 5.8 让我少踩了一个大坑,顺手再聊聊 --erasableSyntaxOnly
前端·javascript·typescript
掰头战士2 天前
你本地的LLM有时会胡乱使用tools?不妨用MCP规范LLM工具调用!
node.js·llm·全栈
退休倒计时2 天前
【每日一题】LeetCode 17. 电话号码的字母组合 TypeScript
算法·leetcode·typescript
前端双越老师2 天前
AI 编程普及,初学者还要不要学习基础语法?
agent·ai编程·全栈
无情的西瓜皮3 天前
MCP 协议实战:从零搭建一个 MCP 服务器(Node.js 版)
vue.js·人工智能·typescript·node.js
退休倒计时3 天前
【每日一题】LeetCode 78. 子集 TypeScript
算法·leetcode·typescript