我该如何自动重新加载正在开发的Chrome扩展程序?

352

我希望我的Chrome扩展程序每当我在扩展文件夹中保存一个文件时都能重新加载,而无需在chrome://extensions/中显式地单击“重新加载”。 这是可能的吗?

编辑:我知道我可以更新Chrome重新加载扩展程序的时间间隔,这是一种折衷的解决方案,但我宁愿让我的编辑器(emacs或textmate)在保存时触发重新加载或要求Chrome监视目录的更改。


2
当从chrome://flags/#enable-apps-devtool-app启用的UI触发重新加载时,似乎速度更快。 - Eric
你的 LiveJS 分支在哪里,@Oz Ramos? - Josh
啊,我明白了:你的“LiveJS”链接实际上是链接到你的分支,而不是LiveJS。 - Josh
9
这并没有按照问题所问的回答,但我想要提一下,当我意识到我可以通过在扩展程序的背景窗口中按下ctrl-R或cmd-R(取决于操作系统)来轻松重新加载扩展程序时,我停止了对此(或任何其他扩展加载助手扩展)的需求。我发现这比我尝试过的任何其他方法都更适合我的工作流程,它还避免了文件处于不一致状态时自动重新加载的问题。 - Don Hatch
1
@DonHatch,“扩展后台窗口”在哪里? - Iulian Onofrei
显示剩余8条评论
31个回答

197
你可以使用Chrome浏览器的"Extensions Reloader"

通过浏览器访问"http://reload.extensions"或使用扩展工具栏按钮重新加载所有未打包的扩展程序。

如果你曾经开发过Chrome扩展程序,你可能需要自动化重新加载未打包的扩展程序而不需要通过扩展程序页面进行操作。

"Extensions Reloader" 允许您使用两种方式重新加载所有未打包的扩展程序:

1 - 使用扩展程序工具栏按钮。

2 - 浏览到 "http://reload.extensions"。

工具栏图标可通过单击重新加载未打包的扩展程序。

“浏览器访问重新加载”旨在使用“构建后”脚本自动化重新加载过程—仅需将浏览器访问添加到脚本中的 "http://reload.extensions",您将拥有刷新后的Chrome窗口。

更新:截至2015年1月14日,该扩展已开源并可在GitHub上获取。


5
目前这是最佳解决方案,但每次修改正在使用的文件时更新扩展并不容易,这正是我理想中的。 - Andrey Fedorov
2
感谢。想提一下我使用 PhpStorm,并添加了一个工具栏按钮,调用 chrome.exe 并使用“reload.extensions”URL。每当我想测试代码时,我按下该按钮,Chrome 就会弹出更新的插件。 - Arik
32
哇,我刚刚成功地使用 grunt-open 插件将 gruntjs 与此插件配合使用,当文件被修改时,它通过打开 http://reload.extensions 来实现与 livereload 完全一样的效果,但是每次修改一个指定的插件文件时都会弹出一个令人讨厌的 Chrome 窗口:P。谢谢! - GabLeRoux
1
@GabLeRoux 我来这里只是为了看看是否有人已经做过了。它运行得非常好。 - polkovnikov.ph
1
@AlexanderMills 很遗憾我没能找到不需要每次都打开新标签页的解决方案。如果你找到更好的方法,至少可以使用 https://github.com/arikw/chrome-extensions-reloader 重新加载插件。 - GabLeRoux
显示剩余11条评论

66

更新: 我添加了一个选项页面,这样你就不必再手动查找和编辑扩展程序的ID了。CRX和源代码在:https://github.com/Rob--W/Chrome-Extension-Reloader
更新2: 添加了快捷键 (请见我在 Github 上的存储库)。
下面是包含基本功能的原始代码。


创建一个扩展程序,并使用Browser Action方法结合chrome.extension.management API来重新加载未打包的扩展程序。

下面的代码会向 Chrome 添加一个按钮,点击该按钮会重新加载扩展程序。

manifest.json

{
    "name": "Chrome Extension Reloader",
    "version": "1.0",
    "manifest_version": 2,
    "background": {"scripts": ["bg.js"] },
    "browser_action": {
        "default_icon": "icon48.png",
        "default_title": "Reload extension"
    },
    "permissions": ["management"]
}

bg.js

var id = "<extension_id here>";
function reloadExtension(id) {
    chrome.management.setEnabled(id, false, function() {
        chrome.management.setEnabled(id, true);
    });
}
chrome.browserAction.onClicked.addListener(function(tab) {
    reloadExtension(id);
});

icon48.png: 选择任何漂亮的 48x48 图标,例如:
Google Chrome Google Chrome


1
@trusktr Scott的回答只重新加载了背景页面。但是,这两个答案可以结合起来(Scott的答案+辅助扩展程序),以便在扩展程序文件更改时自动重新加载扩展程序。然而,我建议不要这样做,因为重新加载扩展程序会关闭开发工具。我经常摆弄测试扩展程序,并经常保存我的更改,即使语法不完整。如果启用了真正的自动重新加载,则会崩溃我的扩展程序。 - Rob W
@RobW 说得好。我经常在编写代码的过程中保存,所以代码肯定会破坏相关的插件。 - trusktr
1
@Sudarshan 您建议使用 chrome.i18n.getMessage("@@extension_id")。但是,这将返回当前扩展的 extensionID,这并不有用,因为扩展无法使用 管理 API 重新加载自己(在禁用后,它没有机会再次启用扩展)。 - Rob W

54

我编写了一个简单的嵌入式脚本,用于实现热重载:

https://github.com/xpl/crx-hotreload

它监控扩展目录中文件的更改。当检测到更改时,它会重新加载扩展并刷新活动选项卡(以重新触发更新后的内容脚本)。

  • 通过检查文件时间戳工作
  • 支持嵌套目录
  • 在生产配置中自动禁用自己

3
如果你正在寻找一种“口感类似于gulp的”解决方案,那么这就是它。 - ow3n
1
工作得很好。你考虑过制作一个npm包吗? - pixelearth
1
@MilfordCubicle 我建议导出一个对象,该对象具有您可以在background.js文件中调用的方法。因此,可以使用import reloader from 'hot-reload'来实现某些功能,然后在脚本中使用reloader.check()。 - pixelearth
5
这个答案需要更多的赞同。与Webpack的--watch结合使用效果很好,因为你可以将它放在构建文件夹中,这样它只会在构建过程完成后更新。无需复杂的Webpack后构建命令插件。 - V. Rubinetti
3
不支持清单版本3。 - polendina
显示剩余4条评论

53

在任何函数或事件中

chrome.runtime.reload();

将重新加载您的扩展程序 (文档)。您还需要更改 manifest.json 文件,添加:

...
"permissions": [ "management" , ...]
...

对我来说,这个解决方案只有在我在index.html的脚本中编写chrome.runtime.reload()时才有效,而在清单文件中指定的方式是:** "background": { "page": "index.html", **。在我的content_script js文件中,我无法访问此函数。我相信这是出于安全原因。 - titusfx
你的内容脚本无法与 Chrome API 进行通信。为了使其正常工作,你需要使用消息 - marcelocra
当您调用 chrome.runtime.reload() 时,实际上会发生什么?多个页面/选项卡是否会刷新? - Alexander Mills
5
我猜我们应该在后台脚本中调用 chrome.runtime.reload() - Alexander Mills
1
对我有用。谢谢。 - MikeMurko
有没有办法从background.js脚本连接到WebSocket服务器? - undefined

26

我正在使用快捷方式进行重新加载。当我保存文件时,我不想一直重新加载。

因此,我的方法很轻便,您可以保留重新加载功能。

manifest.json

{
    ...
    "background": {
        "scripts": [
            "src/bg/background.js"
        ],
        "persistent": true
    },
    "commands": {
        "Ctrl+M": {
            "suggested_key": {
                "default": "Ctrl+M",
                "mac": "Command+M"
            },
            "description": "Ctrl+M."
        }
    },
    ...
}

src/bg/background.js

chrome.commands.onCommand.addListener((shortcut) => {
    console.log('lets reload');
    console.log(shortcut);
    if(shortcut.includes("+M")) {
        chrome.runtime.reload();
    }
})

现在在Chrome浏览器中按下 Ctrl + M 来重新加载。


你也可以在 browserAction 中使用 reload 函数,这样它就会在按钮点击时重新加载。https://stackoverflow.com/questions/30427908/how-can-i-reload-my-chrome-extension-by-javascript/ - powerd
是的,您可以在任何地方加载chrome.runtime.reload()。我使用:编辑器> ctrl + s> alt + tab> ctrl + m。同时打开background.js控制台。这很快,而且不需要使用鼠标。 - Johan Hoeksma
这很完美。只需在编辑器中修改代码(我的是VS Code),Alt Tab到任何Chrome窗口(不必是后台控制台),然后按Ctrl M。在开发DOM修改的内容脚本时,需要使用Alt Tab,Ctrl M,Ctrl R(重新加载“主世界”页面)。 - Thach Lockevn
我认为这是所有解决方案中最简单和最好的一个。 - dipenparmar12
这个解决方案应该排在最顶部! - Simon
这是否包括您添加到扩展中的任何新文件或清单更改? - Andrew

16

TL;DR

创建一个WebSocket服务器将消息分发到处理更新的后台脚本。如果您正在使用webpack并且不打算自己处理,可以使用webpack-run-chrome-extension.

答案

您可以创建一个WebSocket服务器来与扩展作为WebSocket客户端(通过window对象)通信。然后,扩展程序会通过将WebSocket服务器附加到某个监听器机制(如webpack devServer)来监听文件更改。

文件是否更改?将服务器设置为向扩展程序发送请求更新的消息(广播ws消息到客户端),然后扩展程序重新加载,回复“好的,已重新加载”并继续监听新的更改。

enter image description here

计划

  1. 设置WebSocket服务器(以分派更新请求)
  2. 找到一个能够告诉您何时进行文件更改的服务(webpack /其他捆绑软件)
  3. 更新发生时,向客户端分派请求更新的消息
  4. 设置WebSocket客户端(用于接收更新请求)
  5. 重新加载扩展

如何实现

使用 ws 作为 WebSocket 服务器。对于文件更改,使用一些监听器/钩子(例如 webpack 的 watchRun 钩子)。客户端部分使用 本地 WebSocket。然后,扩展程序可以将 WebSocket 客户端附加到后台脚本中,以在服务器(由 webpack 托管)和客户端(附加在扩展后台的脚本)之间保持同步。

现在,要使扩展程序重新加载自身,您可以在每次从服务器收到上传请求消息时,在其中调用chrome.runtime.reload(),或者甚至创建一个“重新加载扩展程序”,使用chrome.management.setEnabled()(需要清单中的"permissions": ["management"])来代替您进行操作。

在理想情况下,像webpack-dev-server 或任何其他 Web 服务器软件都可以本地支持chrome-extension URLs。在发生这种情况之前,将文件更改代理到您的扩展程序的服务器似乎是目前最好的选择。

可用的开源替代方案

如果您正在使用webpack,并且不想自己创建所有内容,我制作了一个名为“webpack-run-chrome-extension”的工具(链接),它可以实现我上面计划的功能。

11

另一个解决方案是创建自定义的实时重新加载脚本(extension-reload.js):

// Reload client for Chrome Apps & Extensions.
// The reload client has a compatibility with livereload.
// WARNING: only supports reload command.

var LIVERELOAD_HOST = 'localhost:';
var LIVERELOAD_PORT = 35729;
var connection = new WebSocket('ws://' + LIVERELOAD_HOST + LIVERELOAD_PORT + '/livereload');

connection.onerror = function (error) {
  console.log('reload connection got error:', error);
};

connection.onmessage = function (e) {
  if (e.data) {
    var data = JSON.parse(e.data);
    if (data && data.command === 'reload') {
      chrome.runtime.reload();
    }
  }
};

这个脚本使用websocket连接到livereload服务器。然后,当接收到重载消息时,它将发出chrome.runtime.reload()调用。下一步是将此脚本添加为后台脚本在您的manifest.json中运行,简单易懂!请注意:这不是我的解决方案。我只是发布它。我在Chrome Extension generator(很棒的工具!)生成的代码中找到了它。我在这里发布它,因为它可能有所帮助。

10

2
这对我来说是最好的解决方案。我也用它来签署我的扩展。 - Johan Hoeksma

9
Chrome扩展具有 权限系统,因此它不允许这样做(一些人在SO上遇到了与您相同的问题),因此要求他们“添加此功能”在我看来是行不通的。有一个来自Chromium Extensions Google Groups的电子邮件提供了一种理论上的解决方案, 使用chrome.extension.getViews(),但并不能保证工作。
如果可以将一些Chrome内部页面添加到manifest.json中,例如chrome://extensions/,那么就可以创建一个插件,该插件将与Reload锚点进行交互,并使用像XRefresh(Firefox插件 - 有一个使用Ruby和WebSocket的 Chrome版本)这样的外部程序,就可以实现你所需的功能。
XRefresh是一款浏览器插件,可以在选定文件夹中的文件更改时刷新当前网页,使您可以使用最喜爱的HTML/CSS编辑器进行实时页面编辑。
虽然不可能直接实现,但我认为您可以以不同的方式使用相同的概念。您可以尝试寻找第三方解决方案,当看到文件中的修改时(我不知道Emacs和Textmate,但在Emacs中,可以在“保存文件”操作中绑定一个应用程序调用),只需单击特定应用程序的特定坐标:在这种情况下,是开发扩展名中的“重新加载”锚点(您仅保留一个Chrome窗口以进行此重新加载)。
(疯狂但可能有效)

7

以下是一个函数,您可以使用它来监视文件的更改,并在检测到更改时重新加载文件。它通过 AJAX 轮询文件并通过 window.location.reload() 重新加载文件。我认为您不应该在分发包中使用此函数。

function reloadOnChange(url, checkIntervalMS) {
    if (!window.__watchedFiles) {
        window.__watchedFiles = {};
    }

    (function() {
        var self = arguments.callee;
        var xhr = new XMLHttpRequest();

        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4) {
                if (__watchedFiles[url] &&
                    __watchedFiles[url] != xhr.responseText) {
                    window.location.reload();
                } else {
                    __watchedFiles[url] = xhr.responseText
                    window.setTimeout(self, checkIntervalMS || 1000);
                }
            }
        };

        xhr.open("GET", url, true);
        xhr.send();
    })();
}

reloadOnChange(chrome.extension.getURL('/myscript.js'));

可以这样做,添加:reloadOnChange(chrome.extension.getURL('/manifest.json')); - Scott
我已经尝试过http://pastebin.com/mXbSPkeu,但扩展程序**未**更新(清单条目、内容脚本、浏览器操作)(Ubuntu 11.10,Chrome 18)。唯一更新的文件是后台页面(更改的console.log消息确实显示出来)。 - Rob W
监听文件变化,如果检测到变化则重新加载。我真的不知道它是如何知道文件已经改变的?请帮助我理解,因为这听起来很棒! - JasonDavis
哦,我现在明白了,它存储文件内容的副本并将缓存版本与ajax实时版本进行比较...聪明! - JasonDavis

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