Wednesday, September 20, 2017

Greasemonkey 4 For Script Authors

As mentioned in the main post, Greasemonkey 4 is changing to be compatible with the Browser Extension API.  At its core, this set of APIs is completely asynchronous.  Greasemonkey's old "GM_" APIs are typically synchronous.

Why?

There exist other user script engines which have already done the work of bridging the gap.  Greasemonkey has elected to move exclusively towards a more performant asynchronous model.  Eventually in the future, such scripts will be faster.

What?

The Greasespot Wiki will be updated to explain Greasemonkey 4 in detail.  Until then, here's a quick summary.

First, there is only an embedded editor.  Browser Extensions have no access to the file system, so you can no longer author user scripts in your familiar text editor.

There is only one object provided to user scripts now, named GM.  It has several properties.  One of them is info – the equivalent of the old GM_info.  There are also several methods of this object: getResourceUrl, deleteValue/getValue/listValues/setValue, xmlHttpRequest.

To use these methods you still need @grant, and use the new name, e.g.:
// @grant GM.setValue
The new form has a dot, where the old form has an underscore.  You may specify both @grants, if you'd like to be compatible with Greasemonkey 4 and other user script engines at the same time.  As of today, there is no support for: GM_log (use console.log), GM_addStyle, GM_registerMenuCommand, nor GM_getResourceText.

In general these methods work like their old counterparts, but their return values are Promises. The async and await keywords make asynchronous promises easy to work with.  For example:
// ==UserScript==
// @name     GM set/get demo
// @grant    GM.getValue
// @grant    GM.setValue
// ==/UserScript==

(async function() {
console.log('Starting the get/set demo ...');
let i = await GM.getValue('i', 0);
console.log(`This time, i was ${i}.`);
GM.setValue('i', i+1);
})();
Here the GM.getValue() method actually returns a promise, but the await keyword transparently converts that to its resolved value, allowing us to write code just as if the value was directly returned – with neither callbacks nor promise resolution.  See the documentation on async and await.

We welcome feedback, reach out via the greasemonkey-users discussion group.  Please also keep in mind the volunteer nature of this open source project when doing so!

4 comments:

example.com said...

Will GM_openInTab be supported in version 4? I use this feature to allow my script to open pages in new tabs in the background.

Noah said...

For those of us who support older browsers (ie pre-FF52), it'd be really nice if GM.getResourceText were supported, as eval(GM.getResourceText(...)) would be an easy way to load Greasemonkey-4 versions of scripts.

arantius said...

GM.getResourceText: https://github.com/greasemonkey/greasemonkey/issues/2548

Stig Nygaard said...

> As of today, there is no support for: GM_log (use console.log),
> GM_addStyle, GM_registerMenuCommand, nor GM_getResourceText.

"As of today", does that means not planned/possible - or just not implemented yet?

Regarding GM_registerMenuCommand, doesn't it sound like it is possible to implement it (or something very similar) with WebExtensions menus API?