在content_script上下文中加载webpack chrome扩展块

时间:2016-08-10 15:43:13

标签: google-chrome google-chrome-extension webpack content-script

我以amd方式开发chrome扩展。作为js bundler,我使用webpack。我已经提取了几个条目,webpack为它们构建了几个块。我的目标是在content_script的上下文中实现块加载。默认行为 webpack_require 确保函数将创建一个带有正确src的新脚本标记并将其注入dom:

__webpack_require__.e = function requireEnsure(chunkId, callback) {
/******/        // "0" is the signal for "already loaded"
/******/        if(installedChunks[chunkId] === 0)
/******/            return callback.call(null, __webpack_require__);
/******/
/******/        // an array means "currently loading".
/******/        if(installedChunks[chunkId] !== undefined) {
/******/            installedChunks[chunkId].push(callback);
/******/        } else {
/******/            // start chunk loading
/******/            installedChunks[chunkId] = [callback];
/******/            var head = document.getElementsByTagName('head')[0];
/******/            var script = document.createElement('script');
/******/            script.type = 'text/javascript';
/******/            script.charset = 'utf-8';
/******/            script.async = true;
/******/
/******/            script.src = __webpack_require__.p + "" + ({}[chunkId]||chunkId) + ".chunk.js";
/******/            head.appendChild(script); // INJECT INTO DOM
/******/        }
/******/    };

对于我的情况,我想将chunk作为单独的请求加载(就像它现在一样)但是在当前content_script代码的上下文中执行: eval function。

得到那样的东西:

/******/    __webpack_require__.e = function requireEnsure(chunkId, callback) {
/******/        // "0" is the signal for "already loaded"
/******/        if(installedChunks[chunkId] === 0)
/******/            return callback.call(null, __webpack_require__);
/******/
/******/        // an array means "currently loading".
/******/        if(installedChunks[chunkId] !== undefined) {
/******/            installedChunks[chunkId].push(callback);
/******/        } else {
/******/            // start chunk loading
/******/            installedChunks[chunkId] = [callback];
/******/            var head = document.getElementsByTagName('head')[0];
/******/            var src = __webpack_require__.p + "" + ({}[chunkId]||chunkId) + ".chunk.js";
/******/            var url = chrome.extension.getURL(src);
/******/            var xhr = new XMLHttpRequest(),
/******/            evalResponseText = function (xhr) {
/******/                eval(xhr.responseText + '//# sourceURL=' + url); // execute chunk's code in context of content_script
/******/                // context.completeLoad(moduleName);
/******/            };
/******/            xhr.open('GET', url, true);
/******/            xhr.onreadystatechange = function (e) {
/******/                if (xhr.readyState === 4 && xhr.status === 200) {
/******/                    evalResponseText.call(window, xhr);
/******/                }
/******/            };
/******/            xhr.send(null); // get chunk
/******/            
/******/        }

我已经通过自定义插件注入编译过程解决了这个问题。这个问题是否有可能实现“合法”的合法性。 (更简单)的方式?或者不使用自定义插件,它可以通过自定义加载器解决?

对任何想法都很感兴趣。

1 个答案:

答案 0 :(得分:1)

Chrome扩展程序注入新内容脚本的合法方式是通过chrome.tabs.executeScript在后台页面中执行此操作。注入的内容脚本共享其他内容脚本的执行环境,即所谓的isolated world

  • 内容脚本:

    function loadScript(fileName, callback) {
        // fileName: file name relative to the extension root folder: 'js/blah.js'
        // callback: receives an array,
        //           in our case there'll be only one element as we inject in one frame, 
        //           each element is an injected script's last evaluated expression 
        //           that underwent internal JSON.stringify + JSON.parse 
        //           thus losing anything except simple stringifiable data
        chrome.runtime.sendMessage({
            action: 'loadContentScript',
            fileName: fileName,
        }, callback);
    }
    

    用法:

    loadScript('js/lib/something.js', function(r) {
        console.log('something was dropped:', r);
        // call something in something
        .............
    }
    
  • 后台脚本:

    chrome.runtime.onMessage(function(msg, sender, sendResponse)) {
        if (msg.action == 'loadContentScript') {
            chrome.tabs.executeScript(sender.tab.id, {
                file: msg.fileName,
                frameId: sender.frameId,
                runAt: 'document_start', // just in case, force an immediate execution
            }, sendResponse);
        }
        return true; // keeps the message channel open while async executeScript runs
    });
    
  • 的manifest.json:

    允许chrome.tabs.executeScript注入https://example.com/(或使用<all_urls>):

    "permissions": ["tabs", "https://example.com/*"],
    

    或者,最好是在您的扩展程序由批准的用户手势激活时:

    "permissions": ["activeTab"],
    

    user gestures的列表:

    • 执行浏览器操作,即单击工具栏图标
    • 执行页面操作,即在现代Chrome中点击工具栏图标
    • 执行扩展程序的上下文菜单项
    • 从命令API
    • 执行扩展程序的键盘快捷方式
    • 从多功能框API接受您的扩展程序的建议