【问题标题】:JSDOM is not loading JavaScript included with <script> tagJSDOM 未加载 <script> 标记中包含的 JavaScript
【发布时间】:2021-07-28 22:31:06
【问题描述】:

注意:此问题与其他现有问题不重复,因为此问题不使用旧版本 JSDOM 使用的 jsdom.env() 函数调用。

文件bar.js

console.log('bar says: hello')

文件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')
}

当我运行foo.js 时,我得到了这个输出。

$ node foo.js
window loaded

为什么bar says: hello 没有输出?看起来bar.js 没有加载。如何让jsdom 加载script 标签中的文件?

[编辑/解决方案]:按照昆汀回答中的建议解决了问题。此代码有效:

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')
}

【问题讨论】:

  • @rlemon 我看不出这是那个问题的重复。该问题使用jsdom.env()。这个没有。这个答案在这里如何适用?
  • @Lone_learner :我安装了 jdsom jsdom@16.4.0,将您的代码复制到相关的 bar.jsfoo.js 但我无法重现您的场景。它只返回window loaded 而不是bar says: hello。上面的代码是否缺少一些设置或代码?
  • 我发现另一个线程指向服务器加载 .js 文件。 github.com/jsdom/jsdom/issues/1914 。我仍然很想知道 Lone_Learner 和 @Quentin 是否找到了更简单的方法。

标签: javascript node.js jsdom


【解决方案1】:

转到the JSDOM homepage

浏览标题,直到找到标记为Executing scripts的标题

要在页面内执行脚本,您可以使用 runScripts: "dangerously" 选项:

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;

我们再次强调只在输入你知道的 jsdom 代码时使用它 是安全的。如果您在任意用户提供的代码或来自 互联网,您正在有效地运行不受信任的 Node.js 代码,并且 你的机器可能会被入侵。

如果您想执行通过<script src=""> 包含的外部脚本,您还需要确保它们加载它们。去做这个, 将选项resources: "usable" 添加为described below

【讨论】:

    【解决方案2】:

    鉴于我无法从上面的代码中重现基于 url 的解决方案...

    残酷的捆绑替代方案:全部内联!

    读取各种.js文件,将它们作为字符串注入到html页面中。然后等待页面像在普通导航器中一样加载。 这些库被加载到_window = new JSDOM(html, { options }).window;,因此可用于您的节点脚本。

    这可能会阻止您进行 xhr 调用,因此只能部分解决问题。

    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!"
    
      });
    

    运行它:

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

    来源:

    【讨论】:

      【解决方案3】:

      根据source,使用 JSDOM 选项 url : file://${__dirname}/index.html 可以工作。如果你测试它,请在这里报告结果。

      【讨论】:

        猜你喜欢
        • 2015-04-22
        • 2014-05-02
        • 1970-01-01
        • 2011-06-14
        • 1970-01-01
        • 1970-01-01
        • 2011-04-09
        • 2020-05-25
        • 1970-01-01
        相关资源
        最近更新 更多