abpVNext 如何在vue3中使用angular代理的依赖注入
invmor
编辑于 2023年07月27日 06:27
收录于文集
共1篇

         abp最方便的莫过于它提供了一套完整的脚手架,给新手以方向,给老手以时间。在众多方便的功能中莫过于生成angular的proxy代理(js代理无类型提示),如何在vue3中使用typescript的proxy呢。

        本文主要设计三个知识点。

  1. 符号链接

  2. 核心替换

首先符号链接功能可参考pnpm的实现方式,源文件在其他项目中,并不在根目录中,我们可通过符号链接,让编译器认为在根目录中。通过angular生成的proxy在angular目录中(必须在angular根目录里面才能生成typescrpt代理),以下为生成代理及符号链接的命令。

代码块
Shell
自动换行
复制代码
abp generate-proxy -t ng -s dcp --target dcp --source dcp
复制成功

代码块
Shell
自动换行
复制代码
mklink /d mini-app\\src\\proxy ..\\..\\angular\\src\\app\\proxy
复制成功

此时,proxy文件夹已经在vue3根目录下,可以通过tsc的路径引用添加快捷路径,由于proxy文件夹里面包含了@abp/ng.core和@angular/core的引用,所以需要通过tsc和webpack进行替换。

tsconfig.json

代码块
JavaScript
自动换行
复制代码
  "paths": {
      "@abp/ng.core": ["src/replace/mockAbp/index.ts"],
      "@angular/core": ["src/replace/mockNg/index.ts"],
      "@proxy": ["src/proxy/index.ts"],
      "@proxy/*": ["src/proxy/*"],
   ........
复制成功

package.json

代码块
JavaScript
自动换行
复制代码
 "browser": {
    "@abp/ng.core": "./src/replace/mockAbp",
    "@angular/core": "./src/replace/mockNg"
  }
复制成功

代码中出现的mockAbp和mockNg是@abp/ng.core和@angular/core的替换实现。

代码块
Shell
自动换行
复制代码
├───replace
│   ├───mockAbp
│   │   │   index.ts
│   │   │   rest.service.ts
│   │   │
│   │   └───mock
│   │           auth.config.ts
│   │           common.ts
│   │           dto.ts
│   │           environment.ts
│   │           index.ts
│   │           mapEnumToOptions.ts
│   │
│   └───mockNg
│           index.ts
│           injectable.ts
│
├───services
│       authService.ts
│       configService.ts
复制成功

这里主要说两个文件rest.service.ts和injectable.ts文件,其他文件可以从源码直接复制。

rest.service.ts主要实现了http请求,代码如下。主要进行了实现替换,注意angular版本返回Observable,这里返回Promise,也可修改为返回Observable,在vue3中类型提示为Promise,同时下面代码接入了部分angular的interceptor功能,依实际情况调整。

代码块
ts
自动换行
复制代码
import axios, {
  AxiosHeaders,
  AxiosInstance,
  AxiosRequestConfig,
  AxiosResponse,
} from "axios";

import config from "../../app.consts";
import { useTokenStore } from "../../stores/token";

const tokenStore = useTokenStore();

export class RestService {
  http: AxiosInstance;
  constructor() {
    this.http = axios.create({
      baseURL: config.account.url,
      headers: new AxiosHeaders({
        Authorization: `Bearer ${tokenStore.token}`,
      }),
    });
  }
  async request<T = any, R = any, D = any>(
    config: HttpRequest<D>,
    _option: Record<string, string>
  ): Promise<R> {
    config.body && (config.data = config.body);
    let res = await this.http.request<T, AxiosResponse<R>>(config);
    if (res.data?.toString()?.includes("<!DOCTYPE html>")) {
      const token = await tokenStore.login();
      this.http.defaults.headers.Authorization = `Bearer ${token}`;
      res = await this.http.request<T, AxiosResponse<R>>(config);
    }
    return res.data;
  }
}
export interface HttpRequest<D> extends AxiosRequestConfig<D> {
  body?: D;
}
复制成功

injectable.ts主要实现了vue3的依赖注入功能,需要获取vue3的app全局实例,这样才能实现全局注入,这里需要更改服务类名称,因为在打包的时候会丢失这些信息。

代码块
ts
自动换行
复制代码
import Taro from "@tarojs/taro";
import { inject } from "vue";
import { RestService } from "../mockAbp/rest.service";

let serviceIndex: number = 0;

export function Injectable(_option: Record<string, any>) {
  return function (_ctor: new (...args: readonly any[]) => unknown) {
    const app = Taro.getApp();
    if (app?.instance) {
      Reflect.defineProperty(_ctor, "name", {
        value: `restService(${_ctor.name})-${serviceIndex++}`,
        writable: false,
      });
      const ctor = Reflect.construct(_ctor, [new RestService()]);
      app.instance.provide(_ctor.name, ctor);
    }
  };
}
复制成功

以上步骤完成后,在vue文件中即可注入以上服务,如下所示。

代码块
ts
自动换行
复制代码
const projectService = inject<ProjectService>(ProjectService.name)!;
复制成功