Uncaught ReferenceError: document is not defined

Hi there (@will and @vaios),

I’m adding you guys to this question/request thinking that it’s something which bothered people not the first time, but before I will write a ‘feature request’, I want to check if it’s the best thing to do.

The problem is that very often clicking ‘Parse’-button gives an error:
Uncaught ReferenceError: document is not defined
from ‘assets-script-parse-worker.js’

I already realized that there is a possibility to add something like this at the beginning of the script:

if (typeof (document) !== "undefined") {
   //script
}

The thing is, it’s not always possible to manually add it, while you are using additional libraries from NPM imported to the project, also minified and parsed by babel, thanks to templates like this one:
https://github.com/whydoidoit/babel-playcanvas-template

and automatically sent to the project. In live mode (local hosting) it works like a charm. But every time when you have to use the online (fully playcanvas.com hosted) version, with ‘ready to go’-built library, there’s the parser on your way. I’m assuming that it works as a node.js server or something like this and it doesn’t know what a global ‘document’ variable is.

To be more specific - I’m realizing, that there is no need to communicate with the ‘document’ or DOM at all in most cases. But more advanced projects nowadays are also using React, Angular, Vue, and many more. Any variables-store solution checks also from time to time some elements through ‘document’ variable. Standard GUI elements added to PC are often just not enough for our clients and thus we are forced to extend PC with one of those frameworks.

Checking big minified .js file and rewriting them is clearly not a solution. But maybe I missed something. Is there any possibility to add some global definition of ‘document’? If not, I think it is about time to add it to parser (feature request), because more and more complicated projects are made in less time every year, and slowly such things as automation and accepting big chunks of external code (which can base on standard browser definitions) are becoming a necessity.

1 Like

Thanks for posing this question. Hmm. Definitely more of a @vaios thing though so I’ll hand over to him to respond. :smiley:

Hi there @vaios,

would you be able to bring some new light on this topic?
Is it possible at all to hook it somehow? Is my proposal at least is worth of considering?

I would be glad to hear something from you about this case

Hi,

Yeah we can look into it but I’m not entirely sure what you mean by adding document to the parser. Do you mean just define a fake document variable in the worker that parses script attributes?

Also are you trying to parse external libraries? If you are getting an error from the parser for an external library that is not meant to be parsed then that’s OK the error doesn’t cause an issue in your project.

1 Like

I believe they have a giant transcompiled Javascript file based given they are using the babel template that they need to parse which also includes references to document in global space and their own ScriptTypes.

That’s exactly my case. The ‘document’ definition in global space as @yaustar called it is not available in parser and I’m not able to add it in such a big chunk of code.

the error doesn’t cause an issue in your project

@vaios Theoretically it’s not a problem, as long as I don’t have to compile it with some PC scripts, because parser error means it the same time that my PC scripts are not parsed correctly or updated (logic, attributes, etc.). In this case it means that I have a to chose between PC scripts and external frameworks. So a fake ‘document’ definition/variable could be a good way :ok_hand:

I can prepare some test-project for you if you need it or just test your solution (in some RC branch or so) in my spare time.

I’m just wondering if we add a fake global document variable isn’t that going to fail parsing later on when the code that relies on it tries to use something from the document?

I guess that’s easy to test in your code if you just add a snippet like that in your code:

if (!window.document) {window.document = {};}

I already tried it (and also and if (typeof (document) !== "undefined") {}). But after mini- and uglyfying my code has 74 usages of document some of them are not able to just replace with some automated replacer while packing with babel. Whats more, I don’t have much control upon external libraries. Copying them, checking manually and rewriting seems to be an only option, but this solution would check out only until we don’t need a new version from NPM or next library so it’s basically extremely inefficient.

You are right. I’ve got also Uncaught TypeError: document.createElement is not a function for example, but I’m not sure how the Parser would react on fake document definition. As I mentioned, your solution or rather this one if (typeof (document) !== "undefined") {} works for me, but only for small self-written files.
It is possible that you would have to add fake document class and also standard methods definitions (createElement, querySelector, body, exitFullscreen and so on). But right now it seems that just adding some standard hook or fake definition could be enough. I would give it a try.

If you want to have something to test, I can send you my compiled code via private message.

I think Vaios was saying to add it as your first line of code in that large file. That would create a fake document object to see if it’s enough for the parser.

I’ve checked it yesterday again with this whole chunk of code but it did’t worked.

If it didn’t work then we can’t just proxy the document object in the parser unfortunately as there are some other properties in the document object that is used by the code in the project in the global scope.

Is there a way to split the files in the build system? So one for PlayCanvas ScriptTypes and the other for web libraries?

Hmm, it could be a possibility, but definitely not the easiest one. How could I bind them later in PC while running, assuming that they are both loaded. Would I need to add some extra handler which would be triggered only in build mode? Maybe simple require would be enough.

I’m still wondering why it’s not working. I’ve used almost the same technique for smaller chunks of code and didn’t get an error about undefined document, but maybe there’s something more in it and the error is just not precise.

It’s possible that where the document reference is used matters? ie, if it’s after the PlayCanvas ScriptTypes, it be might okay? A manual repro project would be of great help here :slight_smile:

No problem :slight_smile:
At Thursday I’ll have a bit more time so it should be possible to create a copy with access for you.
Send me your work email address pls. If you want to add someone, than also this person email address.

Sorry for that inconvenience (mails and waiting), but I have to prepare ‘clean project and repo’ without our clients stuff.

Did anybody find a solution for this issue? I’m facing the same problem.

The recommendation is still currently to have the PlayCanvas scripts separate from any JS code that adds/extends the document object.