如何在浏览器扩展上下文中通过 TypeScript 访问全局变量(如果可能,部分输入)

How to Access a Global Variable through TypeScript in a Browser Extension Context (and partially type it if possible)

1。问题

我正在尝试通过 TypeScript 从网站访问全局变量 — random OGS Example — 以便从当前的棋盘游戏中获取数据。

我是 TS 的新手,所以我也不确定我将如何输入这个变量。 The global variable itself was originally created in TS actually,但它有无数的方法和属性,因为有这么多的功能。所以,如果我要自己打字,我宁愿只打我需要的东西,如果可能的话,或者以某种方式从某个地方的包中导入它——我认为作者没有在任何地方公开发布它。

与所有这些并行的是,还有一个问题,即默认情况下全局变量是否可用于浏览器扩展,which might not be the case

2。我一直在尝试的

所以,我一直在尝试(我已经尝试了一百万种其他变体...)做的是类似* — 在 content.ts 内,在 运行 内时OGS 域 —:

interface Goban {
  bounded_height: number;
}

declare var goban: Goban;

goban = window["global_goban"];

console.log(goban.bounded_height.toString());

我通常得到的错误是:

Uncaught ReferenceError: goban is not defined

那我错过了什么?我是否必须创建声明文件 (.d.ts)?处理这种从第 3 方代码导入全局变量的正确方法是什么?

*:根据您尝试处理 window 对象的方式,您可能需要将 "suppressImplicitAnyIndexErrors": true 添加到 tsconfig.json 以便让TS不静态抱怨。

3。如何完全重现我的问题

对于那些不熟悉如何开发浏览器扩展的人来说,在 TS 中开始的最简单方法是:

  1. 创建一个简单的manifest.json,例如:
    {
        "manifest_version": 2,
        "name": "Name",
        "version": "0.0.2",
        "description": "Description.",
        "content_scripts": [
            {
                "matches": ["*://*.online-go.com/*"],
                "js": ["content.js"]
            }
        ]
    }
    
  2. 使用上一节中的代码创建一个 content.ts 文件。
  3. tsc 编译成 JS。
  4. manifest.jsoncontent.js 作为解压缩的浏览器扩展导入浏览器。
  5. 加载 random OGS game 并检查它。

如果您在浏览器中在线打开控制台-go.com,您可以输入 goban 并看到它是全球可用的。因此,window.goban 将是访问变量的方式。我会做类似的事情:

interface Goban {
  bounded_height: number;
}

const local_goban: Goban = window.goban;

console.log(local_goban.bounded_height.toString());

或者只是

interface Goban {
  bounded_height: number;
}

const goban: Goban = window.goban;

console.log(goban.bounded_height.toString());

在您的代码中您定义了 global_goban,但随后只访问了 goban。请确保您的变量名称一致。

就自动从该页面输入全局变量而言,我认为这不太可能。 Typescript 在浏览器中不起作用,它总是必须编译成普通的 JS,所以你只需要手动编写你想要的类型......你可以检查 Definitely Typed 之类的东西,但正如你提到的,如果他们没有在 code/package 中发布任何 public 存储库,那么您可能找不到任何相关内容。

编辑:为了让打字稿不抱怨 window 变量,您可能需要添加更多类似的内容:

type Goban = {
  bounded_height: number;
}

declare global {
   var goban: Goban;
}

阅读更多关于:Declaring Global Variables

1。要点

内容脚本无法直接访问全局变量,它们在“孤立的世界”中工作。来自 Content Script Environment MDN Docs:

However, content scripts get a "clean" view of the DOM. This means:

  • Content scripts cannot see JavaScript variables defined by page scripts.

但是您仍然可以通过 manifest.json 中的 web_accessible_resources 键共享资源来解决这个问题。

2。一种可能的解决方法

这是一种实现方法:

manifest.json:

{
  "manifest_version": 2,
  "name": "Name",
  "version": "0.0.2",
  "description": "Description.",
  "content_scripts": [
    {
      "matches": ["*://*.online-go.com/*"],
      "js": ["content.js"]
    }
  ],
  "web_accessible_resources": ["script.js"]
}

您可以将您可能需要的任何脚本添加到 web_accessible_resources 键,就像上面 matches 键中使用的脚本一样。您也可以使用 wildcards,如 *,同时匹配多个。

You might still need to add this to your compilerOptions inside your tsconfig.json: "suppressImplicitAnyIndexErrors": true.

script.ts:

interface Goban {
  bounded_height: number;
}

declare var goban: Goban;

goban = window['global_goban'];

console.log(goban.bounded_height.toString());

content.ts:

const script = document.createElement('script');
script.src = chrome.extension.getURL('script.js');
document.head.append(script);

您可能还需要安装 @types/chrome,例如 npm i --save @types/chrome

3。更多资源

此外,内容脚本可以使用 window.postMessagewindow.addEventListener 与页面脚本通信。

更多资源: