在 Angular 2 打字稿中导入gapi.auth2

2024-02-05

我尝试在打字稿中从 Googlegapi.auth2 导入一些类或函数。但即使我在typings目录中正确添加了gapi.auth2类型,下面的代码也永远不会工作。

import { GoogleAuth } from 'gapi.auth2';

我总是遇到错误:

Error TS2307: Cannot find module 'gapi.auth2'

我应该使用一些相对目录搜索吗,例如../../typings/gapi.auth2?

或者也许我使用gapi的方式完全错误?

Thanks!


To use gapi and gapi.auth对于 Angular2,使用 NPM 安装类型脚本定义。

npm install --save @types/gapi
npm install --save @types/gapi.auth2

这将安装两个包,@类型/gapi https://www.npmjs.com/package/@types/gapi and @类型/gapi.auth2 https://www.npmjs.com/package/@types/gapi.auth2 to the node_modules文件夹并将配置保存在package.json.

检查你的node_modules文件夹以检查它们安装是否正确。如果您的 Angular 应用程序名为“main-app”,您应该看到:

main-app/
  node_modules/
    @types/
      gapi/
      gapi.auth2/

The 红色药丸和蓝色药丸 https://en.wikipedia.org/wiki/Red_pill_and_blue_pill设想:

  • 如果没有提供任何类型编译器选项 https://www.typescriptlang.org/v2/en/tsconfig#types应该不需要显式添加gapi or gapi.auth2 to the "types": []编译器选项在tsconfig.json because
  1. 默认情况下所有可见@types编译期间包含软件包。
  2. 包裹在node_modules/@types(任何封闭文件夹的)被视为可见。
  • But. If types已经指定,则TS配置参考 https://www.typescriptlang.org/v2/en/tsconfig#types说明您必须添加gapi or gapi.auth2否则默认情况下将不包含它们。在此场景中,编辑tsconfig.json包括新的gapi and gapi.auth2 types:
{
   "compilerOptions": {
     "types": ["jest", "lodash", "gapi", "gapi.auth2"]
    }
}

此时,如果你觉得有足够的动力,你可以阅读Typescript 模块分辨率 https://www.typescriptlang.org/docs/handbook/module-resolution.html,你可以直接跳到Node.js 如何解析模块:

节点将在名为的特殊文件夹中查找您的模块 node_modules. A node_modules文件夹可以与 当前文件,或目录链中的更高位置。节点会向上走 目录链,逐一查看node_modules直到找到 您尝试加载的模块。

因此,您不需要在 Angular2 服务或组件(或者您使用的任何地方)中添加对类型定义的引用gapi or gapi.auth2).

但是,如果您确实添加了对gapi or gapi.auth2TypeScript 定义,它必须引用.ts使用安装的文件npm install(注意,您必须保留///否则你会得到一个错误):

/// <reference path="../../node_modules/@types/gapi/index.d.ts" />

该路径是相对的,因此您的路径可能会有所不同,具体取决于您所在的位置.ts文件与您安装 TypeScript 定义的位置相关。

无论您添加显式引用还是使用 TypeScript 的 Node 模块解析机制,您仍然需要在.ts文件以便 Angular 了解窗口gapi编译时变量。添加declare var gapi: any;给你的.ts文件但做not将其放在类定义中。我把我的放在所有进口的下面:

// You may not have this explicit reference.
/// <reference path="../../node_modules/@types/gapi/index.d.ts" />
import { NgZone, Injectable, Optional } from '@angular/core';
declare var gapi: any;

使用其他 JavaScript 库 in TypeScript 文档 https://www.typescriptlang.org/docs/handbook/namespaces.html值得阅读以了解我们通过所有这些工作得到了什么。

接下来,加载gapi来自您自己的函数的客户端(可能在 Angular 服务中):

 loadClient(): Promise<any> {
     return new Promise((resolve, reject) => {
         this.zone.run(() => {
                gapi.load('client', {
                    callback: resolve,
                    onerror: reject,
                    timeout: 1000, // 5 seconds.
                    ontimeout: reject
                });
         });
    });
}

这个函数并不简单,原因如下......

首先,请注意我们正在调用间隙负载 https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiloadlibraries-callbackorconfig with a 配置对象而不是一个callback. The GAPI 参考 https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiloadlibraries-callbackorconfig状态可以使用:

  • 库完成时调用的回调函数 加载中。
  • 封装各种配置参数的对象 对于这个方法。只需要回调即可。

使用配置选项使我们能够reject加载库时的 Promise 超时,或者只是错误。根据我的经验,加载库比初始化它更容易失败——这就是为什么配置对象比回调更好的原因。

其次,我们要包装gapi.load in

this.zone.run(() => {
  // gapi.load
});

NgZone.run 已记录 https://angular.io/api/core/NgZone#run和国家

通过运行函数zone.run允许您重新进入 Angular 区域 在 Angular 区域之外执行的任务 [...]

这正是我们想要的,因为调用gapi.load离开角区。忽略这一点可能会导致非常奇怪的结果,并且很难调试。

第三,loadClient()返回一个已解决的承诺 - 允许调用者选择他们如何处理gapi.load。例如如果我们的loadClient方法属于 Angular 服务,apiLoaderServce,一个组件可以使用ngOnInit加载gapi:

ngOnInit(): void {
    this.apiLoaderService.loadClient().then(
        result => this.apiLoaded = true,
        err => this.apiLoaded = false
    );
}
  

Once gapi.load已被称为,gapi.client将准备就绪,您应该使用它通过 API 密钥、OAuth 客户端 ID、范围和 API 发现文档来初始化 JavaScript 客户端:

initClient(): Promise<any> {
    var API_KEY = // Your API key.
    var DISCOVERY_DOC = // Your discovery doc URL.
    var initObj = {
        'apiKey': API_KEY,
        'discoveryDocs': [DISCOVERY_DOC],
    };

    return new Promise((resolve, reject) => {
        this.zone.run(() => {
            gapi.client.init(initObj).then(resolve, reject);
        });
    });
}

注意我们的朋友NgZone.run https://angular.io/api/core/NgZone#run再次使用以确保重新进入角度区域。

在实践中,我添加loadClient() and initClient()到 Angular 服务。在高级 Angular 组件(通常位于应用程序组件下方)中,我加载并初始化ngOnInit:

ngOnInit(): void {
    this.apiLoaderService.loadClient().then(
        result => {
            this.apiLoaded = true;
            return this.apiLoaderService.initClient()
        },
        err => {
            this.apiFailed = true;
        }
    ).then(result => {
        this.apiReady = true;
    }, err => {
        this.apiFailed = true;
    });
}

最后,您需要将gapi 脚本文件添加到您的文件中。

<html>
  <head>
    <script src="https://apis.google.com/js/api.js"></script>

您不得使用async or defer属性,因为它们会导致 Angular 世界在 gapi 库加载之前进入。

<!-- This will not work. -->
<html>
  <head>
    <script async defer src="https://apis.google.com/js/api.js"></script>

我之前建议通过加载本地的缩小版副本来保持页面加载速度快加皮图书馆 https://apis.google.com/js/api.js in the /main-app/src/assests文件夹并导入:

    <html>
      <head>
        <script src="assets/api.js"></script>

但是,我strongly推荐不做这。谷歌可能会更新https://apis.google.com/js/api.js https://apis.google.com/js/api.js你的客户就会崩溃。我已经被这个问题迷惑过两次了。最后最好是从//apis.google.com/js/并将其保留为阻塞调用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Angular 2 打字稿中导入gapi.auth2 的相关文章

随机推荐