📜 ⬆️ ⬇️

Userscripts. We pack user scripts for Chrome

Good day, dear habrazhiteli.

Today we will talk in more detail about the cross-browser user scripting technology mentioned above , namely the packaging of the user script into the simplest extension for Google Chrome.

Below I will try to answer the questions "why?" And "how?".

Prelude


As you remember, Google Chrome browser supports scripts natively (without the need to install third-party components). Script support is implemented at a fairly good level, but there is one BUT : Google Chrome developers care about our security and limit everything that can be limited.
')
In view of these limitations, non-trivial scripts have to be wrapped into an extension.

What are the limitations?


The most important limitations are:
  1. The script should do cross-domain queries.
  2. The script needs access to window.frames [i]
  3. The script needs elevated localStorage limits
  4. Etc.

The above three restrictions can not be emulated and okostyleny. It is necessary to pack yuzerskript.

What do we get at the output?


If we speak strictly, then at the output we will get the extension , not the user script. But given that:

I allow myself to talk about user scripts.

Packaging


A simple extension consists of:
  1. Description file manifest.json
  2. Background page background.html
  3. User script file


manifest.json


This file describes the extension: permissions, constituting resources, launch method, etc.
As the name implies, the entire configuration is a json object.
More information about this file can be found in the official dock .

I will consider the necessary minimum for turning user scripts into extensions:
{ "background_page" : "background.html", "content_scripts" : [ { "js":[ "my.user.js" ], "matches":[ "http://*/*" ], "run_at":"document_end" } ], "description" : "", "name" : "My Userscript", "permissions" : [ "http://*/*", "unlimitedStorage"], "version" : "1.3.0" } 


ParameterPurposeComment
background_pageDefines a background page file.Appointment see below
content_scriptsContent Script Connection SectionThis is where the information is written.
about our user script
jsAn array containing the name of the content script filesHere is the name
our only script
matchesArray containing url masks for running scriptsEach element of the array corresponds to
by index of an array of content scripts.
This parameter determines which pages
corresponding scripts will be run.
In our case, the mask indicates
that the script runs on all pages,
available on http.
run_atThe order of launching content scriptsdocument_end means
that the script will run
after building a DOM tree
descriptionExpansion DescriptionFree text describing our user script
nameExtension nameThe name of the script in any form
permissionsPermissions for our extensionSecurity permissions required.
The first parameter in the example
- mask of domain requests http: // * / * .
It allows the background page to send requests to any domains.

The second parameter sets non-limited localStorage .
versionExtension versionVersion in xxxx format


background.html


The background page is a regular html page that is loaded into the “invisible tab” when the extension is launched and runs in the background during the entire life cycle of the extension.
Background page security restrictions are configured via the permissions parameter in the manifest file. It is through the background page that user scripts are limited . The background page for packaged userscripts is a proxy, which can “communicate” with userscripts via chrome.extension api ( Description ).

The theory is done, time to hang out practice!
Let's take a closer look at proxying cross-domain requests from user scripts.

Code background.html:
 <!DOCTYPE html> <html> <head> </head> <body> <script> /** *    . * XMLHttpRequest      CORP (Cross Origin Request Policy), * ..      . *     GET */ function get(url, callback) { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function (data) { if (xhr.readyState == 4) { if (xhr.status == 200) { callback(data.srcElement.responseText); } else { callback(null); } } } // Note that any URL fetched here must be matched by a permission in // the manifest.json file! xhr.open('GET', url, true); xhr.send(); }; /** *   chrome.extension api. *     * @param request Object   api-. * @param sender Object ,    . * @param callback Function ,      api-. * / function onRequest(request, sender, callback) { //       xget. //        RPC-c if (request.action == 'xget') { get(request.url, callback); } }; //   . chrome.extension.onRequest.addListener(onRequest); //        : // chrome.extension.sendRequest({'action' : 'xget', 'url':url}, callback); </scrip> <body></html> 


The code with English comments is available on pastebin.com

Call from user script:
 /** *      *  : get("http://example.com",alert); */ function get(url, callback) {& chrome.extension.sendRequest({ 'action':'xget', 'url':url}, callback); } 


This method works in Google Chrome. Cross-domain queries from userscripts in other browsers will be covered in one of the following articles.

We collect, we test


To build the extension we need:
  1. Create a separate folder (for convenience)
  2. Put manifest.js, background.html and user script file in it
  3. Pack an extension with Chrome (Settings - Extensions - Pack an extension. See screenshot)




For testing, we can install the unpacked extension (thanks to the OnlyBoy tip). Instead of packing (item 3), click “Install unpacked extension”.
As a result, our extension will be installed like a regular packaged (plus there will be a nice and convenient Reload link for reloading the extension, see screenshot).

Conclusion


That's it for today, stay with us!
Waiting for questions, criticism and discussion in the comments.


List of articles:
  1. Learning to write userscript
  2. Userscripts. Go deep
  3. » Userscripts. We pack user scripts for Chrome
  4. Usersctripts. Cross Domain Queries

Source: https://habr.com/ru/post/130436/


All Articles