Jsdom: Como você carrega scripts externos?

Criado em 7 jul. 2017  ·  3Comentários  ·  Fonte: jsdom/jsdom

jsdom pode executar scripts que estão embutidos dentro da tag <head> do documento, mas como você faz com que ele execute scripts vinculados no cabeçalho do documento via <script src=""> ?

Para opções que estou usando:

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

Informação básica:

  • Versão do Node.js: 8.1.2
  • versão jsdom: 11.1.0

Caso de reprodução 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>

Exemplo de trabalho mínimo completo: https://github.com/cg433n/jsdom-test

Comentários muito úteis

O problema aqui é que DOMContentLoaded é um evento assíncrono. Você está registrando antes que isso tenha a chance de acontecer. Você precisa esperar que ele dispare; só assim seu document.write() vai acontecer.

Algo assim provavelmente deve 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 comentários

O problema aqui é que DOMContentLoaded é um evento assíncrono. Você está registrando antes que isso tenha a chance de acontecer. Você precisa esperar que ele dispare; só assim seu document.write() vai acontecer.

Algo assim provavelmente deve 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>`
  });
});

Eu vejo! Vocês são fantásticos - continuem o bom trabalho!

Aviso: 2 recursos da demonstração acima são arriscados.

hack de FS

Como alternativa, recomendo usar fs para ler e carregar os códigos js de arquivos, consulte Stackoverflow baseado na abordagem FS.read() de @EricRicketts em #3023 e addEventListener() de @Domenic em #1914. A demonstração de trabalho que proponho inclui:

  • use fs.readFileSync para carregar js externos em html como strings
  • loop para lidar com vários arquivos js externos
  • caso de uso de disparar funções js externas
  • caso de uso de passar variáveis ​​de terminal para o nó e, em seguida, para funções js externas

Isso provavelmente impedirá que você faça chamadas xhr/API e, portanto, resolva apenas parcialmente o problema.

URL

Eu não conseguia descobrir a maneira de obter o trabalho de URL.
Idealmente, um JSDOM mínimo atualizado carregando arquivos external.js via URL de demonstração de trabalho seria bem-vindo. :coração:

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

philipwalton picture philipwalton  ·  4Comentários

jacekpl picture jacekpl  ·  4Comentários

Progyan1997 picture Progyan1997  ·  3Comentários

machineghost picture machineghost  ·  4Comentários

tolmasky picture tolmasky  ·  4Comentários