Как импортировать модули ES6 в Content script для расширения Chrome

на хром 61 добавлена поддержка модулей в JavaScript. Прямо сейчас я запускаю Chrome 63.

Я пытаюсь выяснить, как использовать синтаксис импорта/экспорта в сценарии содержимого расширения Chrome для использования модулей.

на манифест.в JSON:

"content_scripts": [ {

        "js": [
            "content.js"
        ],

на my-script.js каталог контента.js

'use strict';

const injectFunction = () => window.alert('hello world');

export default injectFunction;

In содержание.js

'use strict';

import injectFunction from './my-script.js';
injectFunction();

я получаю эту ошибку: непойманные синтаксис ошибка: неожиданный идентификатор

если я изменю синтаксис импорта на import {injectFunction} from './my-script.js'; Я получаю эту ошибку: Uncaught SyntaxError: неожиданный токен {

есть ли проблема с использованием этого синтаксиса в содержании.JS в расширении Chrome, так как в HTML вы должны использовать <script type="module" src="script.js"> синтаксис, или я делаю что-то неправильно? Кажется странным, что Google игнорирует поддержку увеличение.

4 ответов


мне удалось найти решение.

прежде всего важно сказать, что сценарии контента не поддерживают модули с января 2018 года. Но вы можете заставить его работать, встраивая тег сценария модуля в страницу, которая ведет обратно к вашему расширению.

это в моем манифесте

"content_scripts": [ {
   "js": [
     "content.js"
   ]
}],
"web_accessible_resources": [
   "main.js",
   "my-script.js"
]

обратите внимание, что у меня есть два скрипта на веб-доступных ресурсов.

мой содержание.js содержит только этот логика:

'use strict';

const script = document.createElement('script');
script.setAttribute("type", "module");
script.setAttribute("src", chrome.extension.getURL('main.js'));
const head = document.head || document.getElementsByTagName("head")[0] || document.documentElement;
head.insertBefore(script, head.lastChild);

это вставит main.js на веб-страницу в качестве сценария модуля. Вся моя бизнес-логика теперь в основном.js и main, а также все скрипты, которые я буду импортировать, должны быть в web_accessible_resources в манифесте.

Это пример контент my-script.js:

'use strict';

const injectFunction = () => window.alert('hello world');

export {injectFunction};

и main.js это пример импорта скрипт:

'use strict';

import {injectFunction} from './my-script.js';
injectFunction();

это работает, никаких ошибок не выдается, и я счастливый:)


Я просто наткнулся на этот вопрос, пытаясь решить то же самое сам.

В любом случае, я думаю, что есть более простое решение для инъекции ваших собственных пользовательских модулей в ваш скрипт контент. Я смотрел, как вводится jQuery, и мне кажется, что вы можете сделать то же самое, создав жизнь (немедленно вызывается выражение функции) и объявляет его в вашем манифест.в JSON

Это что-то вроде это:

в манифесте.в JSON:

"content_scripts": [
{
  "matches": ["https://*"],
  "css": ["css/popup.css"],
  "js": ["helpers/helpers.js"]
}],

тогда просто создайте IIFE в своих помощниках / помощниках.js:

var Helpers = (function() {
  var getRandomArbitrary = function(min, max) {
    return Math.floor(Math.random() * (max - min)) + min;
  }
  return {
    getRandomArbitrary: getRandomArbitrary
  }
})()

Теперь, вы можете свободно использовать свои вспомогательные функции в вашем скрипте содержание:

Helpers.getRandomArbitrary(0, 10) // voila!

Я думаю, что это здорово, если вы используете этот метод для рефакторинга некоторых ваших общих функций. Надеюсь, это поможет!


Короткий Ответ:

вы можете имитировать некоторые функции и преимущества import/export в расширениях браузера, создав следующий файл и перечислить его в самом начале manifest.json:

let exportVars, importVarsFrom;
{
  const modules = {};
  exportVars = varsObj => ({
    from(nameSpace) {
      modules[nameSpace] || (modules[nameSpace] = {});
      for (let [k,v] of Object.entries(varsObj)) {
        modules[nameSpace][k] = v;
      }
    }
  });
  importVarsFrom = nameSpace => modules[nameSpace];
}

затем экспортируйте из одного файла/модуля следующим образом:

exportVars({ var1, var2, var3 }).from('my-utility');

импорт в другой файл / модуль, как это:

const { var1, var3: newNameForVar3 } = importVarsFrom('my-utility');

Обсуждение:

этот стратегия:

  • позволяет модульный код в расширении браузера, так что вы можете разделить код на несколько файлов, но не имеют переменных столкновений из-за общей глобальной области между различными файлами,
  • позволяет экспорт и импорт переменных из и в различные JavaScript-файлы/модули
  • представляет только две глобальные переменные, а именно функции экспорта и импорта функции
  • поддерживает полная функциональность расширения браузера в каждом файле (например,chrome.runtime, etc.) это устраняется, например, подходом в другом ответе (в настоящее время принятый ответ) с использованием встраивания тега скрипта модуля,
  • использует краткий синтаксис похож на true import и export функции в JavaScript
  • позволяет имя-интервал которые могут быть именами файлов экспортирующих модулей в подобно тому, как истинно import и export команды работают в JavaScript, но не должны быть (т. е. имена имен-пробелов могут быть чем угодно), и
  • позволяет переменной переименования при импорте аналогично how import { fn as myFn }... строительство.

для этого manifest.json необходимо загрузить JavaScript следующим образом:

  • файл, устанавливающий сначала функции экспорта / импорта (с именем modules-start.js в Примере ниже),
  • следующий экспорт файлов и
  • импорт файлов последний.

конечно, у вас может быть файл, который импортирует и экспортирует. В этом случае просто убедитесь, что он указан после файлов, из которых он импортирует, но до файлов, в которые он экспортирует.

Пример Работающего

следующий код демонстрирует эту стратегию.

важно отметить, что весь код в каждой модуль / файл содержится в фигурных скобках. Единственным исключением является первая строка modules-start.js который устанавливает функции экспорта и импорта в качестве глобальных переменных.

код в приведенном ниже фрагменте обязательно содержится в одном "месте". Однако в реальном проекте код можно разделить на отдельные файлы. Обратите внимание, однако, что даже в этом искусственном контексте здесь (т. е. в одном фрагменте кода ниже) эта стратегия позволяет различным разделам кода содержит быть модульным и все еще все еще Соединенным.

// modules-start.js:
let exportVars, importVarsFrom; // the only line NOT within curly braces
{
  const modules = {};
  exportVars = varsObj => ({
    from(nameSpace) {
      modules[nameSpace] || (modules[nameSpace] = {});
      for (let [k,v] of Object.entries(varsObj)) {
        modules[nameSpace][k] = v;
      }
    }
  });
  importVarsFrom = nameSpace => modules[nameSpace];
}


// *** All of the following is just demo code
// *** showing how to use this export/import functionality:

// my-general-utilities.js (an example file that exports):
{
  const wontPolluteTheGlobalScope = 'f';
  const myString = wontPolluteTheGlobalScope + 'oo';
  const myFunction = (a, b) => a + b;
  
  // the export statement:
  exportVars({ myString, myFunction }).from('my-general-utilities');
}

// content.js (an example file that imports):
{
  // the import statement:
  const { myString, myFunction: sum } = importVarsFrom('my-general-utilities');

  console.log(`The imported string is "${myString}".`);
  console.log(`The renamed imported function shows that 2 + 3 = ${sum(2,3)}.`);
}

С этим примером, ваш manifest.json должна перечислить файлы в следующем порядке:

{ ...
  "content_scripts": [
    {
      "js": [
        "modules-start.js",
        "my-general-utilities.js",
        "content.js"
      ]
    }
  ], ...
}

экспорт в модуле объекта:

'use strict';

const injectFunction = () => window.alert('hello world');

export {injectFunction};

затем вы можете импортировать его имущества:

'use strict';
import {injectFunction} from './my-script.js';