Chrome扩展中的多个JS文件 - 如何加载它们?

39

我编写了一个Chrome扩展程序。我的background.js文件相当大,因此我想将它分成较小的部分,并在需要时加载指定的方法(一种懒加载)。

我已经在Firefox中做到了这一点:

// ( call for load specified lib )
var libPath = redExt.basePath + 'content/redExt/lib/' + redExt.browser + '/' + libName + '.js';
var service = Components.classes["@mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.mozIJSSubScriptLoader);
service.loadSubScript("chrome://" + libPath);
// ( executing loaded file )

是否有可能在基于Webkit的浏览器中以类似的方式执行?我已经找到了关于如何将多个JS文件注入匹配页面的解决方案(使用 manifest.json ),但找不到一种只为扩展包含JS文件的方法。

6个回答

49

更新:此解决方案仅适用于使用清单V2的情况。

您还可以按照此处描述的极其简单的方式执行此操作: https://developer.chrome.com/extensions/background_pages#manifest

{
  "name": "My extension",
  ...
  "background": {
    "scripts": [
      "lib/fileone.js",
      "lib/filetwo.js",
      "background.js"
    ]
  },
  ...
}

您不会进行惰性加载,但它确实允许您将代码拆分为多个文件并指定它们在后台页面上加载的顺序。


我能理解你回答的意思,但是很难理解(你在那个页面中具体指的是什么?)。一个小的代码片段会大大改善你的回答。现在这个回答只有链接,可能会被删除。 - Xan
@Omn,您的方法与rsanchez上面建议的方法相比有哪些优缺点? - user5508297
10
请注意:scripts 文件夹中的文件顺序很重要! - Kamafeather
@Kamafeather,这就是为什么答案说这允许您“指定将[文件]加载到后台页面的顺序”的原因。 - Omn

16

如果你想在后台页面的上下文中加载一个javascript文件并且想避免使用eval,你可以向后台页面的DOM添加一个script标签。例如,如果你的文件存在于扩展的lib文件夹中,则可以这样做:

function loadScript(scriptName, callback) {
    var scriptEl = document.createElement('script');
    scriptEl.src = chrome.extension.getURL('lib/' + scriptName + '.js');
    scriptEl.addEventListener('load', callback, false);
    document.head.appendChild(scriptEl);
}

那么你是指定一个背景页面而不是脚本,然后将脚本添加到该页面中吗? - mdenton8
@mdenton8 你可以将这个函数包含在你的后台页面脚本中。这样就可以调用它来运行该页面中的脚本。 - rsanchez
@rsanchez 这个回答是否已经过时了?现在你会推荐按照Omn在他2015年的回答中建议的方式去做吗?或者这两种方法都有优缺点吗? - user5508297
我可以确认这个解决方案对我有效,并且仍然有效。 - Farzad Yousefzadeh

4
尽管这是一篇老帖子,但我想在这里分享我的经验,特别是因为 Manifest V3 已经有了很多改变,importScripts
importScripts('foo.js');

1
非常好用,而且非常简单,谢谢! - JLowther

4
您可以尝试使用Web Worker。在您的background.js中,包含以下内容:
var worker = new Worker('new-script.js');

Web workers可以生成新的worker,甚至拥有一个importScript("new-script.js")方法。

然而,Web workers的功能往往非常有限。在这里查看有关Web workers的一篇优秀文章:here

不过,我不知道它们是否可行。另一个选择是使用XMLHTTPRequest(AJAX)动态检索脚本并进行评估。然而,在非HTTPS连接上,由于中间人攻击的原因,这可能会被阻止。 或者,您可以通过将以下内容添加到manifest.json来强制Chrome从非加密连接中评估脚本(但不要这样做):

"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"permissions": ["http://badpractic.es/insecure.js"]

请参见如何在Chrome扩展程序的后台页面中加载远程网页,以深入讨论AJAX方法。

所以你的选择似乎很有限。

当然,这会一次性加载它们:

{
  "name": "My extension",
  ...
  "background": {
    "scripts": ["background.js","background2.js","background3.js"] //and so on
  },
  ...
}

1
哦,抱歉,我没有意识到你想要懒加载。我会去找的,对不起。 - mdenton8
好的,但我想要防止一次性加载所有文件。我的扩展有时不会使用所有方法,因此我只想加载当前必需的内容。在FireFox中,我有一个use方法(例如storage = myExtension.use('storage'),它会加载/lib/storage.js),并希望在Chrome / Safari中创建类似的解决方案 :) - Tomasz Banasiak
我给了你一些更多的建议。可以再检查一下我的回答吗?- Matt - mdenton8
工人是某种解决方案,但它们的限制在我的情况下使它们不合格 - 而且我几乎需要重写所有代码才能将其用作工人服务。但我已经为你的答案点赞了,因为如果有人在编写任何代码之前寻找这个答案,它将会很有帮助。 - Tomasz Banasiak
感谢您的点赞。也许使用AJAX方法会更有帮助,您尝试过吗? - mdenton8

2
当我点击Chrome扩展图标时,我并没有使用懒加载,但我会在其他文件之前加载一些文件。在我的情况下,我希望我的工具文件先于其他使用它们的文件被加载。
chrome.browserAction.onClicked.addListener(function() {
  chrome.tabs.executeScript(null, {file: "src/utils/utilFunction1.js"});
  chrome.tabs.executeScript(null, {file: "src/utils/utilFunction2.js"});
  chrome.tabs.executeScript(null, {file: "src/main.js"});
  chrome.tabs.executeScript(null, {file: "src/otherFeature.js"});
});

1
发现了一个可能的解决方案。RequireJS的主要方法require有一个简单的实现,它使用JavaScript回调跟踪来查找加载主扩展文件的事件,并将其绑定到扩展上下文中执行。 https://github.com/salsita/browser-require/blob/master/require.js 看起来这个解决方案很有效,但也存在一些缺点:
  • 错误报告显示为“第1行,第1列”,因为此解决方案直接注入代码到func.call中,调试非常困难
  • 加载的JS文件不会出现在控制台/ chromebug中
  • 如果当前选项卡使用HTTPS,则Chrome将禁止从本地上下文(file:///)eval scripts,因此有时它不能按预期工作

你说得对,这个扩展确实很不错。基本上是AJAX方法的良好实现。当然,你可以允许不安全地评估脚本,但你知道这样做可能会对下载你的扩展的用户构成一种信任破坏。祝你好运。 - mdenton8
想问一下,对于第一个问题,你不能在Chrome开发者工具中按F11来进入下一个函数调用吗? - mdenton8

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接