Jsdom: Как вы загружаете внешние скрипты?

Созданный на 7 июл. 2017  ·  3Комментарии  ·  Источник: jsdom/jsdom

jsdom может запускать скрипты, встроенные в тег документа <head> , но как заставить его запускать скрипты, связанные с заголовком документа через <script src=""> ?

Для вариантов, которые я использую:

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

Базовая информация:

  • Версия Node.js: 8.1.2
  • версия jsdom: 11.1.0

Минимальный репродукционный случай:

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

Полный минимальный рабочий пример: https://github.com/cg433n/jsdom-test

Самый полезный комментарий

Проблема здесь в том, что DOMContentLoaded является асинхронным событием. Вы регистрируетесь до того, как это произойдет. Вам нужно дождаться его срабатывания; только тогда произойдет ваш document.write() .

Что-то вроде этого, вероятно, должно работать:

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

Все 3 Комментарий

Проблема здесь в том, что DOMContentLoaded является асинхронным событием. Вы регистрируетесь до того, как это произойдет. Вам нужно дождаться его срабатывания; только тогда произойдет ваш document.write() .

Что-то вроде этого, вероятно, должно работать:

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

Я понимаю! Вы молодцы - продолжайте в том же духе!

Примечание: 2 функции демо выше являются рискованными.

FS взломать

В качестве альтернативы я рекомендую использовать fs для чтения и загрузки кодов js из файлов, см. Stackoverflow на основе подхода @EricRicketts ' FS.read() в #3023 и addEventListener() @Domenic в № 1914. Предлагаемая рабочая демонстрация включает в себя:

  • используйте fs.readFileSync для загрузки внешних js в html в виде строк
  • цикл для обработки нескольких внешних файлов js
  • вариант использования запуска внешних js-функций
  • использовать случай передачи переменных терминала в узел, а затем во внешние функции js

Это, вероятно, помешает вам выполнять вызовы xhr/API и, следовательно, лишь частично решит проблему.

URL-адреса

Я не мог понять, как заставить URL работать.
В идеале будет приветствоваться обновленный минимальный JSDOM, загружающий файлы external.js через рабочую демонстрацию URL . :сердце:

Была ли эта страница полезной?
0 / 5 - 0 рейтинги