javascriptjquerydomjsdom

Why does JQuery require a global "window" object?


I'm using jsdom together with jquery to scrape static web content in a Node.js application.

jsdom converts an HTML string to a DOM tree, including a window property. I found that I had to assign the DOM's window property to global.window, otherwise JQuery errors (saying that a global window object is required). Why is this required?

// Create DOM from HTML
const JSDOM = require('jsdom').JSDOM;
const jsDom = new JSDOM('<html>...</html>')

// Set up JQuery
const { window } = jsDom;
const { document } = window;
global.window = window;
const $ = global.jQuery = require('jquery');

// Scrape content
const tbl = $(document)
  .find('#table-id')
  .find('tr').each(function() {
    // Do something with $(this).html()
  })

Also, I have often seen this: const $ = global.jQuery = require('jquery'); Why is global.jQuery required?


Solution

  • jQuery expects to be running in a browser. In a browser window is present in the global space, and jQuery makes use of it for some of its features. In Node.js, your code is running in a scope created for the file that contains it. Even if you don't think of it as a module, Node.js does not make the distinction all of your const (and let) declarations at the top level of your file declare variables that are scoped to your file. So const { window } = jsDom; is not putting window in the global space, and it is not accessible to jQuery.

    You have two choices when you run jQuery in Node:

    1. Do what you are doing: first expose window into the global space, then load jQuery. This works fine.

    2. You can instead do this:

      const JSDOM = require('jsdom').JSDOM;
      const jsDom = new JSDOM('<html>...</html>');
      
      const { window } = jsDom;
      const { document } = window;
      const $ = global.jQuery = require("jquery")(window);
      

    You are asking also about const $ = global.jQuery = require('jquery');. In my experience, most libraries that depend on jQuery (like jQuery plugins for instance) refer to it as jQuery. They run in an IIFE like this:

    (function ($) { // Inside the IIFE, jQuery is bound to $.
    
    
    }(jQuery)); // jQuery is grabbed from the global space as jQuery.
    

    So you want jQuery in the global space to support libraries that depend on it.