Jsdom: ¿Cómo se cargan scripts externos?

Creado en 7 jul. 2017  ·  3Comentarios  ·  Fuente: jsdom/jsdom

jsdom puede ejecutar secuencias de comandos que están en línea dentro de la etiqueta <head> del documento, pero ¿cómo se ejecutan secuencias de comandos que están vinculadas en el encabezado del documento a través <script src=""> ?

Para las opciones que estoy usando:

{
    url: url,
    resources: 'usable',
    runScripts: 'dangerously',
}

Información básica:

  • Versión de Node.js: 8.1.2
  • versión jsdom: 11.1.0

Caso de reproducción mínima:

// index.js
const request = require('request')
const jsdom = require('jsdom')
const {JSDOM} = jsdom
const url = 'http://localhost:8000'

request(url, (error, response, body) => {
  const options = {
    url: url,
    resources: 'usable',
    runScripts: 'dangerously',
  }

  const dom = new JSDOM(body, options)

  console.log(dom.window.document.body.children.length) // Expecting to see `1`
  console.log(dom.window.document.body.innerHTML) // Expecting to see `<h1>Hello world</h1>`
})
// external.js
document.addEventListener('DOMContentLoaded', () => {
  document.write('<h1>Hello world!</h1>')
})
<!-- index.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>JSDOM test</title>
    <script src="external.js"></script>
  </head>
  <body>
  </body>
</html>

Ejemplo de trabajo mínimo completo: https://github.com/cg433n/jsdom-test

Comentario más útil

El problema aquí es que DOMContentLoaded es un evento asíncrono. Estás iniciando sesión antes de que tenga la oportunidad de suceder. Tienes que esperar a que se dispare; solo entonces sucederá su document.write() .

Algo como esto probablemente debería funcionar:

const dom = new JSDOM(body, options)

dom.window.document.addEventListener('DOMContentLoaded', () => {
  // We need to delay one extra turn because we are the first DOMContentLoaded listener,
  // but we want to execute this code only after the second DOMContentLoaded listener
  // (added by external.js) fires.
  setImmediate(() => {
    console.log(dom.window.document.body.children.length) // Expecting to see `1`
    console.log(dom.window.document.body.innerHTML) // Expecting to see `<h1>Hello world</h1>`
  });
});

Todos 3 comentarios

El problema aquí es que DOMContentLoaded es un evento asíncrono. Estás iniciando sesión antes de que tenga la oportunidad de suceder. Tienes que esperar a que se dispare; solo entonces sucederá su document.write() .

Algo como esto probablemente debería funcionar:

const dom = new JSDOM(body, options)

dom.window.document.addEventListener('DOMContentLoaded', () => {
  // We need to delay one extra turn because we are the first DOMContentLoaded listener,
  // but we want to execute this code only after the second DOMContentLoaded listener
  // (added by external.js) fires.
  setImmediate(() => {
    console.log(dom.window.document.body.children.length) // Expecting to see `1`
    console.log(dom.window.document.body.innerHTML) // Expecting to see `<h1>Hello world</h1>`
  });
});

¡Veo! Ustedes son fantásticos, ¡sigan con el buen trabajo!

Aviso: 2 características de la demostración anterior son riesgosas.

truco de FS

Alternativamente, recomiendo usar fs para leer y cargar los códigos js de los archivos, vea Stackoverflow basado en el enfoque de FS.read() de @EricRicketts en #3023 y addEventListener() de @Domenic en #1914. La demostración de trabajo que propongo incluye:

  • use fs.readFileSync para cargar js externos en html como cadenas
  • loop para manejar varios archivos js externos
  • caso de uso de disparar funciones js externas
  • caso de uso de pasar variables de terminal a nodo, luego a funciones js externas

Es probable que esto le impida realizar llamadas xhr / API y, por lo tanto, solo resuelva parcialmente el problema.

URL

No pude encontrar la manera de hacer funcionar la URL.
Idealmente, sería bienvenido un JSDOM mínimo actualizado que cargue archivos external.js a través de una demostración de trabajo de URL . :corazón:

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

kentmw picture kentmw  ·  3Comentarios

Progyan1997 picture Progyan1997  ·  3Comentarios

eszthoff picture eszthoff  ·  3Comentarios

jacekpl picture jacekpl  ·  4Comentarios

lehni picture lehni  ·  4Comentarios