如何在我最喜欢的 IDE 中开发用户脚本并避免每次都将其复制粘贴到 Tampermonkey 的编辑器中?

How can I develop my userscript in my favourite IDE and avoid copy-pasting it to the Tampermonkey's editor every time?

出于安全原因,Tampermonkey 脚本不会保存在可访问的文件中,而是保存在插件数据中。编辑它们的唯一方法是使用 Tampermonkey 的集成编辑器。

但是,我宁愿使用 IDE,它的所有功能。我也想用webpack从多个文件中打包脚本

为此,我需要一种方法来以编程方式将 Tampermonkey 中的脚本更改为新版本。到目前为止,我所做的是手动将新脚本复制并粘贴到 Tampermonkey 的编辑器中,这真的很累人。

我怎样才能自动执行此操作?

我找到了自己的方法,所以它不是官方的或任何东西,请随意进行自己的调整。您将能够在您的编辑器中编写代码并在浏览器中看到反映的更改,而不会造成任何麻烦。

设置

我们将使我们的 TM 脚本没有代码,但@require 本地文件。这样我们就可以在本地编辑它,并且更改将在浏览器重新加载时生效,而无需 copy-pasting.

  1. 转到 Chrome -> 扩展(或将 'chrome://extensions' 粘贴到您的 URL 栏)并找到 TamperMonkey 'card'。单击详细信息。在打开的页面上,允许它访问文件 URLs:

  1. 将脚本文件保存在文件系统中的任何位置。保存整个内容,包括 ==UserScript== header。我使用的是 macOS,所以我的路径是:/Users/me/Scripts/SameWindowHref.user.js

  2. 现在,在浏览器中转到 TM 的仪表板,在其 TM 编辑器中打开有问题的脚本并删除所有内容 除了 整个 ==UserScript== header

  3. 在header中添加一个@require属性指向脚本的绝对路径。

此时,TM 的编辑器应如下所示:

可能的陷阱: 现在需要在 @require 路径的开头使用 file:// URI scheme。在 Windows 系统上将是:

// @require      file://C:\path\to\userscript.user.js

对于 macOS 和 *nix,您需要连续三个斜杠:

// @require      file:///path/to/userscript.user.js

执行上下文

如果您有多个 JavaScript 文件,每个文件都指定了一个 @require 键,了解每个脚本的执行方式和时间很重要。这在使用外部库(如 jQuery)或在几个文件中分解脚本的整体时很重要。

@require 路径可以引用 *.user.js 或简单的 *.js 文件,并且这些文件中的任何 UserScript-style 注释 header 具有 没有效果.

从主脚本的 ==UserScript== header 开始,所有 @require 文件都是 text-concatenated 指定的顺序 ,带有单个换行符分隔每个文件。然后将此合并作为一个大脚本执行。请注意,这意味着在任何文件的最外层范围内声明的任何函数或变量的行为就好像它是在每个文件的最外层范围内声明的一样,并且一个文件中的某些语法错误可能会影响后续文件的解释方式。此外,要在所有文件上启用 Strict mode'use strict'; 必须是 first first statement @require的文件。

在所有 @require 文件都是 运行 之后,主要的 UserScript(TamperMonkey 的编辑器访问的那个)在单独的上下文中是 运行。如果需要严格模式,也必须在此处启用。

考虑到这种混淆的机会,最好将每个文件的所有代码包装在 IIFE(和 function-level 'use strict';)中,以便将范围限制为个人文件。

工作流程

现在每次脚本匹配 (@match) 时,TamperMonkey 将直接从磁盘上的文件中直接加载和 运行 代码,以 @require 中的路径为准。

我使用 VSCode,所以这是我处理脚本的地方,但任何文本编辑器都可以。它应该是这样的:

请注意 TM 的编辑器和您的 IDE/Editor 如何 相同 header。您现在可以关闭 TM 的编辑器。如果一切正确,您将不再需要打开它。

现在,代码中的每个更改都会由这个特定的编辑器自动保存。如果你的没有自动保存,记得先保存再去浏览器测试它。

最后,您必须重新加载网站才能看到更改,就像以前一样。

奖金提示

考虑使用它 git。它不是 beginner-friendly 但它会让你看起来很酷,有助于拥有理智的开发体验(可以回滚更改并轻松尝试平行的想法),如果你将它与 GitHub 配对,你可以发布新的更新免费提供给您未来的用户。

使用 GitHub(或其他 SCM)

您必须添加一个 @updateURL 标签,后跟 URL 以及来自 GitHub 或您选择的任何提供商的 raw 文件。 GitHub的例子:

请注意,需要 @version 标记才能进行更新检查。绝大多数开发者不需要 @downloadURL 标签,所以除非你的脚本有大量的追随者,否则请使用 @updateURL.

TM 将按照配置的频率检查更新;从设置选项卡:

Externals 设置从您的脚本 @require 调用的脚本检查更新的频率(例如,jQuery)。

您还可以“强制”更新检查:

使用外部库(如jQuery)

它必须存在于 至少 TM 编辑器中显示的 header 中,Chrome 才能加载它。然而,我建议保持 headers 相同(在 TM 和本地文件中显示)以避免混淆和可能出现奇怪的错误。然后,你就 @require 像这样:

// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js

RTFM

看看TM's documentation page;它不咬人! 它实际上非常简洁,通过快速阅读,您将清楚地了解您可以毫不费力地完成哪些工作!

我确实会使用@require,但如果您有设计更改也可以使用GM_addStyle

// @require     file:///
// @grant       GM_addStyle

Trim21提供,可能是目前最好的large-scale UserScript development solution,使用webpack配合LiveReloadPlugin实现模块化开发和自动化测试

Here is the project.

可以使用ES5/ES6和TypeScript在IDE上开发模块化脚本。真的好用!

集成LiveReloadPlugin,可以直接刷新任意@matchURL.

比之前的方案更好,大大提高了UserScript的开发效率!

破解: 我需要引用静态图像文件,所以我将 图像转换为 base64 字符串 ,然后将其直接添加到脚本中。我相信,类似的方法也适用于其他小文件。

I'd like to add a rather nice solution for Firefox devs (or any other) where local file access is not possible中的@require方法:

使用nginx作为简单的本地HTTP服务器如下:

  • download nginx 并在某处解压,例如C:\nginx

  • 调整 <nginx-dir>/conf/nginx.conf 以在访问时直接并立即(无缓存)为您的项目(例如 C:\my-project\src\tampermonkey.myapp.js)提供脚本服务:

    server {
      ...
      location / {
        #root   html;
        root    C:/my-project/;
        ...
    
        # kill cache
        expires -1;
    
  • 启动nginx,例如通过 cmd /c "C:\nginx\nginx.exe"

    • (稍后停止,例如通过 cmd /c "C:\nginx\nginx.exe -s stop"
  • 相应地更改 @require(删除 //==/UserScript== 下面的所有内容)(并保存):

    // ==UserScript==
    //@name         My App Addon
    //@match        http://foo
    //@require      http://localhost/src/tampermonkey.myapp.js
    //==/UserScript==
    
  • 完成

无需设置 Nginx,或必须配置 Chrome 以允许本地文件,您只需使用 ngrok 来代理本地文件。

此示例假设您的文件位于 /dist 目录中并且您已经安装了 nodejs.

npx serve -p 5000 ./dist & npx ngrok http 5000 --log stdout

或使用 package.json,您可以 运行 使用 npm start:

  "scripts": {
    "start": "npm-run-all -l -p serve watch ngrok",
    "build": "webpack",
    "watch": "webpack --watch",
    "serve": "npx serve -p 5000 ./dist",
    "ngrok": "ngrok http 5000 --log stdout"
  },

这将在端口 5000 上提供文件并为您提供外部 URL,在控制台输出中查找此行:

addr=http://localhost:5000 url=https://101b-110-150-114-111.ngrok.io

然后像这样创建一个用户脚本:

// ==UserScript==
// @name         Script Name
// @namespace    http://example.com/
// @version      0.1
// @description  Description
// @author       Your Name
// @match        https://example.com/*
// @grant        none
// ==/UserScript==

(function() {
  var ngrokUrl = 'https://101b-110-150-114-111.ngrok.io'; // <-- Update this
  var remoteScript = document.createElement('script');
  remoteScript.src = ngrokUrl  + '/bundle.js?ts='+(+new Date());
  document.body.appendChild(remoteScript);
})();

这将注入存储在 ./dist/bundle.js 中的脚本,并在每次刷新页面时重新加载它。

Note If you don't sign up for ngrok account your connection will time out after two hours and you will need to restart it and update the ngrokUrl URL.