Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build: document is not defined #254

Closed
Simon-He95 opened this issue May 31, 2022 · 26 comments · Fixed by #242
Closed

build: document is not defined #254

Simon-He95 opened this issue May 31, 2022 · 26 comments · Fixed by #242

Comments

@Simon-He95
Copy link

image
Under such scenario,I introduced an npm package component that relies on document

This error occurs that vite-ssg build

@blwtxc
Copy link

blwtxc commented May 31, 2022

Stumbled upon that problem several times now. Before I was able to wrap it and create a mock window/document to make it build. Now I added an npm package that wants document (quill.js in my case) and I don't know what to do now. Project runs smooth in dev but wont build. Is there perhaps an option I overlooked that injects a mock document to make modules build?
Cheers for any help from the community :)

@Simon-He95
Copy link
Author

image
I want to create style element append head, In this case will build wrong.
I can only use it by using onBeforeMount to wrap it in a component, it will be ok, but It wasn't what I expected.The component will be used many times,so i need to add additional conditions to control unexpected execution.

@blwtxc
Copy link

blwtxc commented May 31, 2022

@Simon-He95 concerning your document problem: did you try tor wrap the problematic code portion(s) into try .. catch to handle the missing document issue?

@blwtxc
Copy link

blwtxc commented May 31, 2022

@antfu any idea? did I miss an option?

@Simon-He95
Copy link
Author

I try to wrap the problematic code portion(s) into try .. catch to handle, the issue was resolved.
Thank you for your help, but I'm more looking forward to being able to create a mock window/document to make it build.

@blwtxc
Copy link

blwtxc commented Jun 1, 2022

Well ... As I have no idea about your code I have to freeride here ...
Assuming we are NOT talking about a 3rd party module where we have (basically) no control over its internals, I would:

  • "test" if there is a "window" object by using it inside a try..catch (something like accessing document -> "window.document)
  • If that fires, you are -- quite likely -- in a context that does not know "window", i.e.: webworker or node
  • Now you can either not execute the rest of your code or mock the "window" object and all the objects, classes, methods and attributes your code expects to "work" ... as we are in build-phase, the code does not have to work per-se, but to build.
  • When we are back in the browser, we again have the contexts the code expects to run properly and everything should work as expected

@blwtxc
Copy link

blwtxc commented Jun 1, 2022

... I just had another look at the issues-page and this problem is prevalent when using vite-ssg, but it seems to be also solved (?) ... I have to take a look at their suggestions and see if they are feasable for my situation ... did you have a look there and tried some of their suggestions?

@blwtxc
Copy link

blwtxc commented Jun 1, 2022

... and ... yes, it would of course be awesome, if that would be something taken care of on vite-ssg's side ;)

@userquin
Copy link
Member

userquin commented Jun 1, 2022

@blwtxc I sent a PR a few days ago to allow use jsdom, the problem is that the mock: true option enables it usage but jsdom is registered after building the SSR main and may fail

@Simon-He95
Copy link
Author

Yeah,most of the problems are in build process, when build we might be able to wrap window/document into try...catch or mock window/document, If there are errors, let the errors be thrown at runtime

@userquin
Copy link
Member

userquin commented Jun 1, 2022

@Simon-He95 the problem here is the executon of main.[cm]js not its generation: if you're using some lib referencing window/document it will fail while importing that library when we run it, just check the vite-ssg-temp folder and the main entry generated.

This line https://github.com/antfu/vite-ssg/blob/main/src/node/build.ts#L107 will load previous generated module, but the jsdom registration is done a few lines below it, we need to register jsdom (when using mock: true) at least before line 107, my PR registers the jsdom before its generation

@userquin
Copy link
Member

userquin commented Jun 1, 2022

you can also excluded these libraries using optimizedDeps.exclude and try build: for example, while testing vite 3 with vitesse template I need to exclude workbox-window

imagen

@blwtxc
Copy link

blwtxc commented Jun 1, 2022

@userquin thanks a lot for chiming in and your reply!! :D

@blwtxc
Copy link

blwtxc commented Jun 1, 2022

@userquin I see what you mean...
I tried it with mock: true and it still failed (as you suspected)
Because I searched for window mock... before I read your answer I also found happy-dom and already installed it .. so I thought I give that a try ... if you ask why (because there is jsdom already available): just for shits and giggles
I found the build.cjs in my node_modules, required it, and did the GlobalRegistrator.register() ... well, that failed fast!
So I looked for the line you described and did the GlobalRegistrator.register() just before that.
That allowed the app at least to run a bit further, but then I got an error that jsdomGlobal wasn't found (still had my mock: true). I guess GlobalRegistrator.register() overloads the functions that are needed to load jsdom..?
Well ... long story short ... It ran, it built :)
Is there a strong reason to use jsdom? happy-dom seems to do the job just fine and be easier to use...
Just

const GReg = require('@happy-dom/global-registrator');

at the start of the script, and then

GReg.GlobalRegistrator.register();

just before

const { createApp, includedRoutes: serverEntryIncludedRoutes } = format === "esm" ? await import(serverEntry) : _require(serverEntry);

... but I'm quite sure that I overlooked something ;D

@userquin
Copy link
Member

userquin commented Jun 1, 2022

@blwtxc you can just try modifying the build.[cm]js modules from vite-ssg dist folder with the changes on my PR (just move the jsdom registration before the SSR vite build or at least before the ssr entry import/require), you should be able to build your project

@blwtxc
Copy link

blwtxc commented Jun 1, 2022

@userquin Thanks! Already achieved it with happy-dom in the build.[cm]js module. I guess I will try it with your changes the next time I have to touch the modules or I realize that something's not working after all :))

@userquin
Copy link
Member

userquin commented Jun 1, 2022

@blwtxc about happy-dom, IIRC this guy didn't exist when Anthony started this repository... we use jsdom to do the SSG part, so be careful not to break it using the happy-dom patch

@blwtxc
Copy link

blwtxc commented Jun 1, 2022

@userquin Ok, thanks. If you want, I can let u know if I run into problems with happy-dom ... kinda case study ;)

@userquin
Copy link
Member

userquin commented Jun 1, 2022

@blwtxc what do you mean, adding also happy-dom to use it on SSG instead jsdom? If so, maybe you can change mock to be mock?: 'happy-dom' | 'jsdom' | boolean , when configuring mock: true fallback to 'jsdom' and so no breaking change, but you must include some common interface to do all current ssg work using happy-dom

I'll move this issue to a discussion, my PR should fix this

@blwtxc
Copy link

blwtxc commented Jun 1, 2022

@userquin I think that is a brilliant idea!
What do you mean by include some common interface?
(Sorry, maybe that's a stupid question...)

@blwtxc
Copy link

blwtxc commented Jun 1, 2022

@userquin Ok ... had another look at the module code and I guess I understand what you mean.
Well ... I know neither jsdom nor happy-dom ... well ... not more than what I read on their readme pages.
From what I understand concerning happy-dom, its extension GlobalRegistrator exports everything into global scope, so there seems to be no need for what I can see in the module concerning jsdom.
So if I'm not mistaken, everything that'd be necessary is to GlobalRegistrator.register() and then GlobalRegistrator.unregister() at the appropriate times in the build process.

@userquin
Copy link
Member

userquin commented Jun 1, 2022

@blwtxc we should use/replace from this line https://github.com/antfu/vite-ssg/blob/main/src/node/build.ts#L167 to this another https://github.com/antfu/vite-ssg/blob/main/src/node/build.ts#L175 (both included, I'm assuming happy-dom can serialize the dom to html)

EDIT: so we need to expose a common interface and move previous logic for example to the jsdom module, and then add the corresponding for happy-dom, once we have this use the mock value to load and use one of them

The common interface abstracting the internals should be in its own module, then use that factory on the SSG loop for each page:

export const SSGBuildContext {
  document: Document
  serialize: () => Awaitable<string>
}

For src/node/jsdom.mjs, it would be something like this:

import { JSDOM } from 'jsdom'

export function jsdom(renderedHTML)  {
  const jsdom= new JSDOM.JSDOM(renderedHTML)
  return {
    get document() { return jsdom.window.document },
    serialize() { return jsdom.serialize() },
  }
}

For happy-dom we'll have something similar in its own module and also the corresponding src/node/happydomGlobal.mjs (here should go the global register and unregister).

Then use the SSGBuildContext on the SSG build (remember use jsdom as fallback, and use dynamic import to load both modules).

@blwtxc
Copy link

blwtxc commented Jun 1, 2022

@userquin I really shouldn't open my mouth if I don't know what I'm talking about :/
Well ... I'll have a look ;)

@blwtxc
Copy link

blwtxc commented Jun 1, 2022

@userquin I see now where I made a mistake.
Using GlobalRegistrator.register() was only an easy fix that allowed modules in my app to run without throwing errors about missing DOM elements and functions. Based on that I assumed that happy-dom replaced jsdom, but it did not. The heavy lifting is still done by jsdom as it seems.
I can't find a serialize method, that does the same as the one provided by jsdom. I guess happy-dom could be used as a replacement, but I don't see a solution that wouldn't include rewriting the whole build module... and I don't think that is something worth spending timee on...

@blwtxc
Copy link

blwtxc commented Jun 1, 2022

@userquin I'm very sorry to have wasted your time!

@userquin
Copy link
Member

userquin commented Jun 1, 2022

@blwtxc continues here #256

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants