javascript - greasemonkey scripts
¿Cómo puedo cargar un trabajador web compartido con un script de usuario? (3)
Condición previa
-
Como ha investigado y como se ha mencionado en los comentarios, la URL de
SharedWorker
está sujeta a la Política del mismo origen. -
Según
esta pregunta,
no hay soporte de CORS para la URL del
Worker
. -
De acuerdo con
este problema, el
soporte de
GM_worker
ahora es un WONT_FIX, y parece lo suficientemente cerca como imposible de implementar debido a los cambios en Firefox. También hay una nota de que WorkboxedWorker
(en oposición aunsafeWindow.Worker
) tampoco funciona.
Diseño
Lo que supongo que desea lograr es un script de usuario
@include *
que recopilará algunas estadísticas o creará una interfaz de usuario global que aparecerá en todas partes.
Y, por lo tanto, desea tener un trabajador para mantener algunos agregados estadísticos o de estado en tiempo de ejecución (que será de fácil acceso desde cada instancia de script de usuario), y / o desea hacer alguna rutina de cálculo pesado (porque de lo contrario lo hará sitios objetivos lentos).
En el camino de cualquier solución
La solución que quiero proponer es reemplazar el diseño de
SharedWorker
con una alternativa.
-
Si solo desea mantener un estado en el trabajador compartido, simplemente use el almacenamiento de Greasemonkey (
GM_setValue
y amigos). Se comparte entre todas las instancias de script de usuario (SQLite detrás de las escenas). -
Si desea hacer algo que
unsafeWindow.Worker
mucha tarea de cómputo,unsafeWindow.Worker
enunsafeWindow.Worker
yunsafeWindow.Worker
colocar el resultado en el almacenamiento de Greasemonkey. -
Si desea realizar algunos cálculos en segundo plano y debe ejecutarse solo por una sola instancia, hay varias bibliotecas de sincronización "entre ventanas" (en su mayoría usan
localStorage
pero Greasemomkey tiene la misma API, por lo que no debería ser difícil de escribir un adaptador para eso). Por lo tanto, puede adquirir un bloqueo en una instancia de usercript y ejecutar sus rutinas en él. Me gusta, IWC o ByTheWay ( probablemente usado aquí en Stack Exchange; publique sobre esto ).
Otra manera
No estoy seguro, pero puede haber una suplantación de respuesta ingeniosa, realizada desde
ServiceWorker
para hacer que
SharedWorker
funcione como a usted le gustaría.
El punto de partida está en
la edición de esta respuesta
.
Quiero cargar un trabajador compartido con un script de usuario. El problema es que el script de usuario es gratuito y no tiene un modelo de negocio para alojar un archivo, ni me gustaría usar un servidor, incluso uno gratuito, para alojar un archivo pequeño. De todos modos, lo probé y (por supuesto) obtengo el mismo error de política de origen:
Uncaught SecurityError: Failed to construct ''SharedWorker'': Script at ''https://cdn.rawgit.com/viziionary/Nacho-Bot/master/webworker.js'' cannot be accessed from origin ''http://stackoverflow.com''.
Hay otra forma de cargar un trabajador web convirtiendo la función de trabajador en una cadena y luego en un Blob y cargando eso como trabajador, pero también lo intenté:
var sharedWorkers = {};
var startSharedWorker = function(workerFunc){
var funcString = workerFunc.toString();
var index = funcString.indexOf(''{'');
var funcStringClean = funcString.substring(index + 1, funcString.length - 1);
var blob = new Blob([funcStringClean], { type: "text/javascript" });
sharedWorkers.google = new SharedWorker(window.URL.createObjectURL(blob));
sharedWorkers.google.port.start();
};
Y eso tampoco funciona.
¿Por qué?
Debido a que los trabajadores compartidos se
comparten en
función de la ubicación desde la que se carga su archivo de trabajador.
Dado que
createObjectURL
genera un nombre de archivo único para cada uso
, los trabajadores nunca tendrán la misma URL y, por lo tanto, nunca se compartirán.
¿Como puedó resolver esté problema?
Nota: Intenté preguntar sobre soluciones específicas, pero en este punto creo que lo mejor que puedo hacer es pedir de manera más amplia cualquier solución al problema, ya que todas mis soluciones intentadas parecen fundamentalmente imposibles debido a las mismas políticas de origen o forma en que funciona
URL.createObjectURL
(a partir de las especificaciones , parece imposible alterar la URL del archivo resultante).Dicho esto, si mi pregunta se puede mejorar o aclarar de alguna manera, por favor deje un comentario.
Estoy bastante seguro de que quieres una respuesta diferente, pero lamentablemente esto es a lo que se reduce.
Los navegadores implementan políticas del mismo origen para proteger a los usuarios de Internet, y aunque sus intenciones son claras, ningún navegador legítimo le permite cambiar el origen de un Trabajador compartido.
Todos los contextos de navegación en un
sharedWorker
deben compartir exactamente el mismo origen
- anfitrión
- protocolo
- Puerto
No puedes hackear este problema, estoy intentando usar iframes además de tus métodos, pero no funcionará.
Tal vez puedas ponerlo en tu archivo javascript en github y usar su
raw.
servicio para obtener el archivo, de esta manera puede ejecutarlo sin mucho esfuerzo.
Actualizar
Estaba leyendo actualizaciones de Chrome y recordé que preguntaste sobre esto. ¡Los trabajadores de servicio de origen cruzado llegaron a Chrome!
Para hacer esto, agregue lo siguiente al evento de instalación para el SW:
self.addEventListener(''install'', event => {
event.registerForeignFetch({
scopes: [self.registration.scope], // or some sub-scope
origins: [''*''] // or [''https://example.com'']
});
});
También se necesitan algunas otras consideraciones, échale un vistazo:
Puede usar
fetch()
,
response.blob()
para crear una
Blob URL
de
Blob URL
de tipo
application/javascript
desde
Blob
devuelto;
establecer el parámetro
SharedWorker()
en
Blob URL
creado por
URL.createObjectURL()
;
utilice
window.open()
,
load
evento de la
window
recién abierta para definir el mismo
SharedWorker
definido previamente en la
window
original, adjunte el evento del
message
al
SharedWorker
original en la
window
recién abierta s.
Se intentó
javascript
en la
console
en
Cómo borrar el contenido de un iFrame de otro iFrame
, donde la URL de la pregunta actual debe cargarse en una nueva
tab
con el
message
de la
window
apertura a través del controlador de eventos
worker.port.postMessage()
registrado en la
console
.
La
window
apertura también debe registrar el evento del
message
cuando se publica desde una
window
recién abierta usando
worker.postMessage(/* message */)
, de manera similar en la
window
apertura
window.worker = void 0, window.so = void 0;
fetch("https://cdn.rawgit.com/viziionary/Nacho-Bot/master/webworker.js")
.then(response => response.blob())
.then(script => {
console.log(script);
var url = URL.createObjectURL(script);
window.worker = new SharedWorker(url);
console.log(worker);
worker.port.addEventListener("message", (e) => console.log(e.data));
worker.port.start();
window.so = window.open("https://.com/questions/"
+ "38810002/"
+ "how-can-i-load-a-shared-web-worker-"
+ "with-a-user-script", "_blank");
so.addEventListener("load", () => {
so.worker = worker;
so.console.log(so.worker);
so.worker.port.addEventListener("message", (e) => so.console.log(e.data));
so.worker.port.start();
so.worker.port.postMessage("hi from " + so.location.href);
});
so.addEventListener("load", () => {
worker.port.postMessage("hello from " + location.href)
})
});
En la
console
en cualquiera de las
tab
, puede usar, por ejemplo;
en
Cómo borrar el contenido de un iFrame de otro iFrame
worker.postMessage("hello, again")
en una nueva
window
de la URL actual
¿Cómo puedo cargar un trabajador web compartido con un script de usuario?
,
worker.port.postMessage("hi, again");
donde los eventos de
message
se adjuntan en cada
window
, la comunicación entre las dos
window
se puede lograr utilizando
SharedWorker
original creado en la URL inicial.