简体   繁体   中英

Chrome extension to modify page's script includes and JS

I work on a javascript library that customers include on their site to embed a UI widget. I want a way to test dev versions of the library live on the customer's site without requiring them to make any changes to their code. This would make it easy to debug issues and test new versions.

To do this I need to change the script include to point to my dev server, and then override the load() method that's called in the page to add an extra parameter to tell it what server to point to when making remote calls.

It looks like I can add JS to the page using a chrome extension, but I don't see any way to modify the page before it's loaded. Is there something I'm missing, or are chrome extensions not allowed to do this kind of thing?

I've done a fair amount of Chrome extension development, and I don't think there's any way to edit a page source before it's rendered by the browser. The two closest options are:

  • Content scripts allow you to toss in extra JavaScript and CSS files. You might be able to use these scripts to rewrite existing script tags in the page, but I'm not sure it would work out, since any script tags visible to your script through the DOM are already loaded or are being loaded.

  • WebRequest allows you to hijack HTTP requests, so you could have an extension reroute a request for library.js to library_dev.js .

Assuming your site is www.mysite.com and you keep your scripts in the /js directory:

chrome.webRequest.onBeforeRequest.addListener(
    function(details) {
        if( details.url == "http://www.mysite.com/js/library.js" )
            return {redirectUrl: "http://www.mysite.com/js/library_dev.js" };
    },
    {urls: ["*://www.mysite.com/*.js"]},
    ["blocking"]);

The HTML source will look the same, but the document pulled in by <script src="library.js"></script> will now be a different file. This should achieve what you want.

Here's a way to modify content before it is loaded on the page using the WebRequest API. This requires the content to be loaded into a string variable before the onBeforeRequest listener returns. This example is for javascript, but it should work equally well for other types of content.

chrome.webRequest.onBeforeRequest.addListener(
    function (details) {
        var javascriptCode = loadSynchronously(details.url);
        // modify javascriptCode here
        return { redirectUrl: "data:text/javascript," 
                             + encodeURIComponent(javascriptCode) };
    },
    { urls: ["*://*.example.com/*.js"] },
    ["blocking"]);

loadSynchronously() can be implemented with a regular XMLHttpRequest. Synchronous loading will block the event loop and isdeprecated in XMLHttpRequest, but it is unfortunately hard to avoid with this solution.

You might be interested in the hooks available in the Opera browser. Opera used to have* very powerful hooks , available both to User JavaScript files (single-file things, very easy to write and deploy) and Extensions. Some of these are:

BeforeExternalScript:

This event is fired when a script element with a src attribute is encountered. You may examine the element, including its src attribute, change it, add more specific event listeners to it, or cancel its loading altogether.

One nice trick is to cancel its loading, load the external script in an AJAX call, perform text replacement on it, and then re-inject it into the webpage as a script tag, or using eval.

window.opera.defineMagicVariable:

This method can be used by User JavaScripts to override global variables defined by regular scripts. Any reference to the global name being overridden will call the provided getter and setter functions.

window.opera.defineMagicFunction:

This method can be used by User JavaScripts to override global functions defined by regular scripts. Any invocation of the global name being overridden will call the provided implementation.


*: Opera recently switched over to the Webkit engine, and it seems they have removed some of these hooks. You can still find Opera 12 for download on their website, though.

When It comes to changing the page content (Be it HTML content or Scripts), Chrome extensions have technical constraints. The easiest way to solve this problem would be to intercept the HTML and allow the developer to override the HTML/JS response content pragmatically.

This is possible through Requestly Desktop App

Using Requestly Desktop App

  1. Install Requestly Desktop App
  2. Open Connected Apps and Launch any browser - Chrome, Firefox, etc
  3. Go to HTTP Rules and Create a New Modify Response Rule

Choose to override the content Programatically for your HTML Page . Write a simple JS script to do your modifications on top of the existing HTML/JS response.

Here is a sample screenshot of how you can do it. 请求修改响应规则

Using Requestly Chrome Extension

If Redirecting a script URL and Inserting a new Script suffices your use case then you can also use Requestly Chrome Extension and create two rules

  1. Redirect Rule - Redirect Production Script with Dev scripts
  2. Insert Script Rule - Inject Scripts on Page

Disclaimer - I built Requestly.

I had an idea, but I didn't try it, but it worked in theory.

Run content_script that was executed before the document was loaded, and register a ServiceWorker to replace page's requested file content in real time. (ServiceWorker can intercept all requests in the page, including those initiated directly through the dom)

Chrome extension (manifest v3) allow us to add rules for declarativeNetRequest :

chrome.declarativeNetRequest.updateDynamicRules({
    addRules: [
        {
            "id": 1002,
            "priority": 1,
            "action": { 
                "type": "redirect", 
                "redirect": { 
                    "url": "https://example.com/script.js" 
                } 
            },
            "condition": {
                "urlFilter": 'https://www.replaceme.com/js/some_script_to_replace.js',
                "resourceTypes": [
                    'csp_report',
                    'font',
                    'image',
                    'main_frame',
                    'media',
                    'object',
                    'other',
                    'ping',
                    'script',
                    'stylesheet',
                    'sub_frame',
                    'webbundle',
                    'websocket',
                    'webtransport',
                    'xmlhttprequest'
                ]

            }
        },
    ],
    removeRuleIds: [1002]

});

and debug it by adding listener:

chrome.declarativeNetRequest.onRuleMatchedDebug.addListener(
    c => console.log('onRuleMatchedDebug', c)
)

It's not a Chrome extension, but Fiddler can change the script to point to your development server (see this answer for setup instructions from the author of Fiddler). Also, with Fiddler you can setup a search and replace to add that extra parameter that you need.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM