Jsdom: Comment charger des scripts externes ?

Créé le 7 juil. 2017  ·  3Commentaires  ·  Source: jsdom/jsdom

jsdom peut exécuter des scripts qui sont en ligne à l'intérieur de la balise <head> du document, mais comment lui faire exécuter des scripts qui sont liés à l'en-tête du document via <script src=""> ?

Pour les options que j'utilise:

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

Informations de base:

  • Version Node.js : 8.1.2
  • version jsdom : 11.1.0

Cas de reproduction minimal :

// 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>

Exemple de travail minimum complet : https://github.com/cg433n/jsdom-test

Commentaire le plus utile

Le problème ici est que DOMContentLoaded est un événement asynchrone. Vous vous connectez avant que cela ait une chance de se produire. Vous devez attendre qu'il se déclenche ; ce n'est qu'alors que votre document.write() arrivera.

Quelque chose comme ça devrait probablement fonctionner :

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>`
  });
});

Tous les 3 commentaires

Le problème ici est que DOMContentLoaded est un événement asynchrone. Vous vous connectez avant que cela ait une chance de se produire. Vous devez attendre qu'il se déclenche ; ce n'est qu'alors que votre document.write() arrivera.

Quelque chose comme ça devrait probablement fonctionner :

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>`
  });
});

Je vois! Vous êtes fantastiques - continuez votre bon travail !

Remarque : 2 fonctionnalités de la démo ci-dessus sont risquées.

pirater FS

Alternativement, je recommande d'utiliser fs pour lire et charger les codes js à partir de fichiers, voir Stackoverflow basé sur l' approche FS.read() de @EricRicketts dans #3023 et addEventListener() de @Domenic dans #1914. La démo de travail que je propose comprend :

  • utilisez fs.readFileSync pour charger des js externes dans html sous forme de chaînes
  • boucle pour gérer plusieurs fichiers js externes
  • cas d'utilisation du déclenchement de fonctions js externes
  • cas d'utilisation du passage de variables terminales au nœud, puis à une fonction js externe

Cela vous empêchera probablement de faire des appels xhr/API et ne résoudra donc que partiellement le problème.

URL

Je n'arrivais pas à trouver le moyen d'obtenir un travail d'url.
Idéalement, un JSDOM minimal mis à jour chargeant des fichiers external.js via une démo de travail d'url serait le bienvenu. :cœur:

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

lehni picture lehni  ·  4Commentaires

jhegedus42 picture jhegedus42  ·  4Commentaires

Progyan1997 picture Progyan1997  ·  3Commentaires

tolmasky picture tolmasky  ·  4Commentaires

drewish picture drewish  ·  4Commentaires