0

Я разрабатываю расширение chrome в amd способом. Как js bundler я использую webpack. Я извлек несколько записей, webpack построил для них несколько кусков. Моя цель - добиться загрузки кусков в контексте content_script. По умолчанию поведение webpack_require. обеспечить функцию создаст новый тег сценария с правильным ЦСИ и ввести его в DOM:webpack chrome extension chunk загрузка в контексте content_script

__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 
/******/  } 
/******/ }; 

Для моего случая я хотел бы загрузить кусок в виде отдельного запроса (как это работает сейчас), но выполняется в контексте текущий код контента_script: eval функция.

Чтобы получить то вроде этого:

/******/ __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 
/******/    
/******/  } 

Я уже решил его нестандартной инъекцию плагина в процесс компиляции. Вопрос, можно ли достичь «законным» (более простым) способом? Или не использовать пользовательский плагин, и его можно решить с помощью пользовательского загрузчика?

Thx много для любых идей.

ответ

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
    • Принимая предложение вашего расширения из omnibox API
+0

Thx для ответа!На самом деле исходный вопрос был обращен к webpack, и какой лучший способ изменить/изменить механизм генерации кода загрузки блока =) Но ваш ответ дает мне ответ, как избежать вызова eval() в моем коде, и это тоже здорово! Я уже пробовал ваше предложение с ** chrome.executeScript **, но получил некоторые путаные сообщения об ошибках. Я пытаюсь использовать глобальную функцию override requirejs.load для вызова sendMessage и executeScript на странице фона. Chrome может найти модуль, но по какой-то причине выполнить его невозможно. – SchmerZ

+0

Ну, webpack не может обойти присущие ограничениям chrome-расширений, поэтому любые функциональные возможности загрузки скриптов, специфичные для конкретного экземпляра, могут быть в основном в этих строках. Возможно, в светлое будущее, когда Chrome реализует ES6-модули для расширений. – wOxxOm

+0

Если вы пытаетесь выполнить объект ответа, это просто остаток того, что было последним оценено, кастрированное внутренней строкой (см. Комментарии в моем коде). Поэтому просто обращайтесь к новому модулю напрямую (он должен зарегистрироваться, например, в глобальном «модуле» или «экспорте»). – wOxxOm