Skip to content

When requiring jquery from within react-native, you get an error 'document.createElement' is not defined #2349

@oveddan

Description

@oveddan

Problem

My use case is to use jquery to page scrape from within react-native code. I'm using jsdom-jscore to build a document from downloaded html, then trying to pass that document to jquery to be able to parse it.

My code looks like:

var jquery = require('jquery');
     jsdom = require('jsdom-jscore');

var someHtmlIDownloaded = '<html><body><h1>Hello world</h1></body></html>';

jsdom.env(
    someHtmlIDownloaded,
    function (errors, window) {
      var $ = jquery(window);
      // do something with $ to parse/scrape html body.
    }
  );

The require('jquery') throws an error:
'document.createElement' is not defined

This occurs within sizzle, in the assert(fn) method.

Why it happens

react-native creates its own global document, but createElement is not supported on this document object. When jquery is loaded in this environment, because there is a global.document, it assumes document.createElement exists, and tries to attach itself to that document. The check that passes can be found here and looks like:

module.exports = global.document ?
            factory( global, true ) :
            function( w ) {
                if ( !w.document ) {
                    throw new Error( "jQuery requires a window with a document" );
                }
                return factory( w );
            };

Temp fix

I was able to fix this locally by:
Building jquery from source using command:
grunt custom: -ajax,-ajax/jsonp,-ajax/load,-ajax/parseJSON,-ajax/parseXML,-ajax/script,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-event/ajax,-css,-css/addGetHookIf,-css/curCSS,-css/defaultDisplay,-css/hiddenVisibleSelectors,-css/support,-css/swap,-css/var/cssExpand,-css/var/getStyles,-css/var/isHidden,-css/var/rmargin,-css/var/rnumnonpx,-effects,-effects/Tween,-effects/animatedSelector,-dimensions,-offset,-deprecated,-event,-event/alias,-event/support,-wrap,-deferred,-core/ready

Altering the built jquery code to never assume there is a global document:

module.exports = function( w ) {
                if ( !w.document ) {
                    throw new Error( "jQuery requires a window with a document" );
                }
                return factory( w );
            };

And I require that custom build js in my code:

var jquery = require('dist/jquery.js');

And it works!

Actual Solution?

What is the proper way to fix this? Should we check if the createElement method exists on the document before deciding to pass it to the factory?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions