javascript - modules - Cómo importar módulos ES6 en el script de contenido para Chrome Extension
script type module (5)
En Chrome 61 se agregó soporte para módulos en JavaScript. Ahora mismo estoy ejecutando Chrome 63.
Estoy tratando de averiguar cómo usar la sintaxis de importación / exportación en el script de contenido de la extensión de Chrome para usar los módulos.
En manifest.json :
"content_scripts": [{
"js": [
"content.js"
],
En my-script.js en el mismo directorio que content.js
''use strict'';
const injectFunction = () => window.alert(''hello world'');
export default injectFunction;
En content.js
''use strict'';
import injectFunction from ''./my-script.js'';
injectFunction();
Recibo este error: Uncaught SyntaxError: identificador inesperado
Si cambio la sintaxis de importación a import {injectFunction} from ''./my-script.js'';
Me sale este error: Error de sintaxis no detectada: token inesperado {
¿Hay algún problema con el uso de esta sintaxis en content.js en la extensión de Chrome, ya que en HTML tiene que usar la sintaxis de <script type="module" src="script.js">
o estoy haciendo algo mal? Parece extraño que Google ignore el soporte para extensiones.
Como ya se mencionó, para el script de fondo, es una buena idea usar background.page
y usar <script type="module">
para activar tu JavaScript.
El problema es la content script
, e inyectar la etiqueta <script>
con atributo de type
puede ser una solución.
Otro enfoque que la inyección de etiquetas de script es utilizar dynamic import
función de dynamic import
. Con este enfoque, no es necesario perder el alcance del módulo de chrome
y aún puede utilizar chrome.runtime
u otros módulos.
En content_script.js
, parece que
(async () => {
const src = chrome.extension.getURL("your/content_main.js");
const contentMain = await import(src);
contentMain.main();
})();
Para más detalles:
- Cómo utilizar la "importación" de ES6 con Chrome Extension
- Ejemplo de trabajo de importación ES6 en Chrome Extension
Espero eso ayude.
Exportar el módulo como un objeto:
''use strict'';
const injectFunction = () => window.alert(''hello world'');
export {injectFunction};
Entonces puedes importar su propiedad:
''use strict'';
import {injectFunction} from ''./my-script.js'';
Me las arreglé para encontrar una solución .
En primer lugar, es importante decir que las secuencias de comandos de contenido no son compatibles con los módulos a partir de enero de 2018. Pero puede hacer que funcione incorporando una etiqueta de secuencia de comandos de módulo en la página que conduce a su extensión.
Esto está en mi manifiesto
"content_scripts": [ {
"js": [
"content.js"
]
}],
"web_accessible_resources": [
"main.js",
"my-script.js"
]
Tenga en cuenta que tengo dos scripts en recursos accesibles a la web.
Mi content.js contiene solo esta lógica:
''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);
Esto insertará main.js en la página web como un script de módulo. Toda la lógica de mi negocio está ahora en main.js y main, así como todos los scripts que importaré tienen que estar en web_accessible_resources en el manifiesto.
Este es el contenido de ejemplo de my-script.js :
''use strict'';
const injectFunction = () => window.alert(''hello world'');
export {injectFunction};
Y en main.js, este es un ejemplo de importación del script:
''use strict'';
import {injectFunction} from ''./my-script.js'';
injectFunction();
Esto funciona, no se lanzan errores y estoy feliz :)
Me topé con esta pregunta mientras trataba de resolver lo mismo yo mismo.
De todos modos, creo que hay una solución más sencilla para inyectar sus propios módulos personalizados en su script de contenido . Estaba viendo cómo se inyecta Jquery y se me ocurre que puedes hacer lo mismo creando un IIFE (Expresión de función inmediatamente invocada) y declarándolo en tu manifest.json
Es algo parecido a esto:
En tu manifiesto.json:
"content_scripts": [
{
"matches": ["https://*"],
"css": ["css/popup.css"],
"js": ["helpers/helpers.js"]
}],
Luego simplemente crea un IIFE en tus helpers / helpers.js:
var Helpers = (function() {
var getRandomArbitrary = function(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
return {
getRandomArbitrary: getRandomArbitrary
}
})()
Ahora, puede usar libremente sus funciones de ayuda en su secuencia de comandos de contenido:
Helpers.getRandomArbitrary(0, 10) // voila!
Creo que es genial si usa este método para refactorizar algunas de sus funciones genéricas. ¡Espero que esto ayude!
Respuesta corta:
Puede imitar algunas de las funciones y obtener algunos de los beneficios de import
/ export
en las extensiones del navegador creando el siguiente archivo y enumerándolo al principio en su archivo 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];
}
Luego, exporta desde un archivo / módulo como este:
exportVars({ var1, var2, var3 }).from(''my-utility'');
Importar en otro archivo / módulo como este:
const { var1, var3: newNameForVar3 } = importVarsFrom(''my-utility'');
Discusión:
Esta estrategia:
- permite el código modular en una extensión del navegador, de modo que puede dividir el código en varios archivos pero no tener conflictos variables debido al alcance global compartido entre diferentes archivos,
- aún le permite exportar e importar variables desde y hacia diferentes archivos / módulos de JavaScript,
- introduce solo dos variables globales , a saber, la función de exportación y la función de importación,
- mantiene la funcionalidad completa de la extensión del navegador en cada archivo (p
chrome.runtime
ejchrome.runtime
,chrome.runtime
, etc.) que se elimina, p. ej., el enfoque en otra respuesta (actualmente la respuesta aceptada) mediante la inclusión de etiquetas de módulos en el script, - utiliza una sintaxis concisa similar a las verdaderas funciones de
import
yexport
en JavaScript, - permite el espacio entre los nombres que podrían ser los nombres de archivo de los módulos de exportación de una manera similar a como funcionan los verdaderos comandos de
import
yexport
en JavaScript, pero no tiene que serlo (es decir, los nombres de espacio de nombres pueden ser lo que usted quiera) y - permite el cambio de nombre de variable al importar similar a cómo funciona la
import { fn as myFn }...
Para hacer esto, su manifest.json
necesita cargar su JavaScript de la siguiente manera:
- el archivo que establece primero las funciones de exportación / importación (denominadas
modules-start.js
en el ejemplo a continuación), - los archivos de exportación a continuación, y
- Los archivos importadores últimos.
Por supuesto, es posible que tenga un archivo que importe y exporte. En ese caso, solo asegúrese de que aparezca en la lista después de los archivos de los que importa pero antes de los archivos a los que exporta.
Ejemplo de trabajo
El siguiente código demuestra esta estrategia.
Es importante tener en cuenta que todo el código en cada módulo / archivo está contenido entre llaves. La única excepción es la primera línea en modules-start.js
que establece las funciones de exportación e importación como variables globales.
El código en el fragmento de código a continuación está necesariamente contenido en un solo "lugar". Sin embargo, en un proyecto real, el código podría dividirse en archivos separados. Tenga en cuenta, sin embargo, que incluso en este contexto artificial aquí (es decir, dentro del fragmento de código único a continuación), esta estrategia permite que las diferentes secciones del código que contiene sean modulares y aún así estén interconectadas.
// 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)}.`);
}
Con este ejemplo, su manifest.json
debería listar los archivos en el siguiente orden:
{ ...
"content_scripts": [
{
"js": [
"modules-start.js",
"my-general-utilities.js",
"content.js"
]
}
], ...
}