Google chrome 在内容\脚本上下文中加载webpack chrome扩展块

Google chrome 在内容\脚本上下文中加载webpack chrome扩展块,google-chrome,google-chrome-extension,webpack,content-script,Google Chrome,Google Chrome Extension,Webpack,Content Script,我正在以amd的方式开发chrome扩展。作为js bundler,我正在使用webpack。我提取了几个条目,webpack为它们构建了几个块。我的目标是在content_脚本的上下文中实现块加载。默认情况下,行为webpack\u require确保函数将使用正确的src创建一个新的脚本标记,并将其注入dom: __webpack_require__.e = function requireEnsure(chunkId, callback) { /******/ // "0"

我正在以amd的方式开发chrome扩展。作为js bundler,我正在使用webpack。我提取了几个条目,webpack为它们构建了几个块。我的目标是在content_脚本的上下文中实现块加载。默认情况下,行为webpack\u 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
/******/        }
/******/    };
在我的例子中,我希望将块作为单独的请求加载(就像现在一样),但在当前内容的上下文中执行脚本代码:eval函数

要获得这样的smth:

/******/    __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
/******/            
/******/        }
我已经通过在编译过程中注入自定义插件解决了这个问题。问题是是否有可能以“合法”(更简单)的方式实现?或者不使用自定义插件,它可以通过自定义加载程序解决


任何想法都有很多建议。

chrome扩展注入新内容脚本的合法方式是通过在后台页面中进行。注入的内容脚本共享其他内容脚本的执行环境,即所谓的

  • 内容脚本:

    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/
    (或使用

    • 执行浏览器操作,即工具栏图标单击
    • 执行页面操作,即在现代Chrome中单击工具栏图标
    • 执行扩展的上下文菜单项
    • 从commands API执行扩展的键盘快捷键
    • 接受来自omnibox API的扩展的建议

    • chrome extension注入新内容脚本的合法方式是通过在后台页面中进行。注入的内容脚本共享其他内容脚本的执行环境,即所谓的

      • 内容脚本:

        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/
        (或使用

        • 执行浏览器操作,即工具栏图标单击
        • 执行页面操作,即在现代Chrome中单击工具栏图标
        • 执行扩展的上下文菜单项
        • 从commands API执行扩展的键盘快捷键
        • 接受来自omnibox API的扩展的建议

      谢谢回复!实际上,最初的问题是关于webpack以及修改/更改块加载代码生成机制的最佳方式=)但您的回答给了我一个如何避免eval()的答案调用我的代码,这也很棒!我已经尝试了你对chrome.executeScript的建议,但得到了一些令人困惑的错误消息。我试图做的是使用override requirejs.load全局函数在后台页面上调用sendMessage和executeScript。chrome能够找到模块,但由于某些原因无法执行。嗯,webpack无法绕过chrome扩展的固有限制,因此它所能提供的任何特定于扩展的脚本加载功能基本上都是这样。也许在光明的未来,当chrome为扩展实现ES6模块时。如果你试图执行响应对象,它只不过是上一代的遗留物通过内部字符串化(参见我代码中的注释)对其进行评估。因此只需直接访问新模块(例如,它应该在全局
      modules
      exports
      对象中注册自身)。不确定我是否清楚地理解了你关于stringify的话……我正在尝试加载内容脚本,其中amd模块由executeScript加载,如你所述。因此,想法非常简单:我在chrome扩展中有requirejs作为内容脚本。我只想能够加载任何请求的amd模块(按要求(['./my/file.js']I.e.)作为内容脚本。ExecuteSXcript非常适合,但requirejs无法处理响应模块..现在不知道为什么..谢谢回答!实际上最初的问题是指webpack,以及修改/更改块加载代码生成机制的最佳方式=)但您的回答告诉我如何避免eval()调用我的代码,这也很棒!我已经尝试了你对chrome.executeScript的建议,但得到了一些令人困惑的错误消息。我试图做的是使用override requirejs.load全局函数在后台页面上调用sendMessage和executeScript。chrome能够找到模块,但由于某些原因无法执行。嗯,webpack无法绕过chrome扩展的固有限制,因此它所能提供的任何特定于扩展的脚本加载功能基本上都是这样。也许在光明的未来,当chrome为扩展实现ES6模块时。如果你试图执行响应对象,它只不过是上一代的遗留物通过内部字符串化(参见我代码中的注释)对其进行评估。因此只需直接访问新模块(例如,它应该在全局
      modules
      exports
      对象中注册自身)。不确定我是否清楚地理解了你关于stringify的话……我正在尝试加载内容脚本,其中amd模块由executeScript加载,如你所述。因此,想法非常简单:我在chrome扩展中有requirejs作为内容脚本。我只想能够加载任何请求的amd模块(按要求(['./my/file.js']I.e.)同样也是内容脚本。ExecutesXcript非常适合,但requirejs无法处理响应模块。目前不知道原因。。