最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

node.js - JSDOM is not loading JavaScript included with <script> tag - Stack Overflow

programmeradmin0浏览0评论

Note: This question is not a duplicate of other existing questions because this question does not use jsdom.env() function call which older version of JSDOM use.

File bar.js:

console.log('bar says: hello')

File foo.js:

var jsdom = require('jsdom')
var html = '<!DOCTYPE html><head><script src="bar.js"></script></head><body><div>Foo</div></body>'
var window = new jsdom.JSDOM(html).window
window.onload = function () {
  console.log('window loaded')
}

When I run foo.js, I get this output.

$ node foo.js
window loaded

Why did bar says: hello output did not come? It looks like bar.js was not loaded. How can I make jsdom load the file in the script tag?

[EDIT/SOLUTION]: Problem solved after following a suggestion in the answer by Quentin. This code works:

var jsdom = require('jsdom')
var html = '<!DOCTYPE html><head><script src="bar.js"></script></head><body><div>Foo</div></body>'
var window = new jsdom.JSDOM(html, { runScripts: "dangerously", resources: "usable" }).window
window.onload = function () {
  console.log('window loaded')
}

Note: This question is not a duplicate of other existing questions because this question does not use jsdom.env() function call which older version of JSDOM use.

File bar.js:

console.log('bar says: hello')

File foo.js:

var jsdom = require('jsdom')
var html = '<!DOCTYPE html><head><script src="bar.js"></script></head><body><div>Foo</div></body>'
var window = new jsdom.JSDOM(html).window
window.onload = function () {
  console.log('window loaded')
}

When I run foo.js, I get this output.

$ node foo.js
window loaded

Why did bar says: hello output did not come? It looks like bar.js was not loaded. How can I make jsdom load the file in the script tag?

[EDIT/SOLUTION]: Problem solved after following a suggestion in the answer by Quentin. This code works:

var jsdom = require('jsdom')
var html = '<!DOCTYPE html><head><script src="bar.js"></script></head><body><div>Foo</div></body>'
var window = new jsdom.JSDOM(html, { runScripts: "dangerously", resources: "usable" }).window
window.onload = function () {
  console.log('window loaded')
}
Share Improve this question edited Sep 1, 2020 at 20:35 Hugolpz 18.3k28 gold badges105 silver badges191 bronze badges asked Oct 30, 2018 at 17:08 Lone LearnerLone Learner 20.6k25 gold badges114 silver badges218 bronze badges 4
  • 1 @rlemon I don't see how this is a duplicate of that question. That question uses jsdom.env(). This one does not. How is that answer applicable here? – Lone Learner Commented Oct 30, 2018 at 17:14
  • @Lone_learner : I installed jdsom [email protected], copied your code into relevant bar.js and foo.js but I'am unable to reproduce your scenario. It only returns window loaded but not bar says: hello. Is the code above missing some settings or code ? – Hugolpz Commented Sep 1, 2020 at 17:53
  • I found another thread which point toward server loading of the .js files. github.com/jsdom/jsdom/issues/1914 . I'am still curious to know if Lone_Learner & @Quentin found simpler way. – Hugolpz Commented Sep 1, 2020 at 18:40
  • 1 "EDIT/SOLUTION" should be posted as an answer, not an edit to the question. – ggorlen Commented Jul 10, 2022 at 0:41
Add a comment  | 

3 Answers 3

Reset to default 12

Go to the JSDOM homepage.

Skim the headings until you find one marked Executing scripts

To enable executing scripts inside the page, you can use the runScripts: "dangerously" option:

const dom = new JSDOM(`<body>
  <script>document.body.appendChild(document.createElement("hr"));</script>
</body>`, { runScripts: "dangerously" });

// The script will be executed and modify the DOM:
dom.window.document.body.children.length === 2;

Again we emphasize to only use this when feeding jsdom code you know is safe. If you use it on arbitrary user-supplied code, or code from the Internet, you are effectively running untrusted Node.js code, and your machine could be compromised.

If you want to execute external scripts, included via <script src="">, you'll also need to ensure that they load them. To do this, add the option resources: "usable" as described below.

Given I was unable to reproduce the url-based solution from the code above...

Brutal bundle alternative : inline it all !

Read the various .js files, inject them as string into the html page. Then wait the page to load as in a normal navigator. These libraries are loaded into _window = new JSDOM(html, { options }).window; and therefor available to your node script.

This is likely to prevent you from doing xhr calls and therefore only partially solve the issue.

say-hello.js

// fired when loaded
console.log("say-hello.js says: hello!")
// defined and needing a call
var sayBye = function(name) { 
    var name = name ||'Hero!'; 
    console.log("say-hello.js says: Good bye! "+name)
}

main.js:

    const fs    = require("fs");
    const jsdom = require("jsdom");
    const { JSDOM } = jsdom;
    
    var NAME  = process.env.NAME; // variable from terminal

    var html = '<!DOCTYPE html><head></head><body><div>Foo</div></body>'
    var _window = new JSDOM(html, {
        runScripts: "dangerously",
        resources: "usable" }).window;
    /* ************************************************************************* */
    /* Add scripts to head ***************************************************** */
    var jsFiles = [
        'say-hello.js'
    ];
    var scriptsContent = ``;
    for(var i =0; i< jsFiles.length;i++){
        console.log(__dirname + '/'+ jsFiles[i])
      let scriptContent = fs.readFileSync( jsFiles[i], 'utf8');
      scriptsContent = scriptsContent + `
      /* ******************************************************************************************* */
      /* `+jsFiles[i]+` **************************************************************************** */
      `+scriptContent;
    };
    let scriptElement = _window.document.createElement('script');
    scriptElement.textContent = scriptsContent;
    _window.document.head.appendChild(scriptElement);


/* ************************************************************************* */
/* Run page **************************************************************** */
_window.document.addEventListener('DOMContentLoaded', () => {
    console.log('main says: 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.
    _window.sayBye(NAME); // prints "say-hello.js says: Good bye!"

  });

Run it:

NAME=John node main.js    # expects hello and good bye to john messages

Source:

  • https://github.com/jsdom/jsdom/issues/1914
  • https://github.com/jsdom/jsdom/issues/3023

Using JSDOM option url : file://${__dirname}/index.html could work, according to a source. If you test it, please report result here.

发布评论

评论列表(0)

  1. 暂无评论