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

Can't avoid crash when trying to discriminate between build environment and client side. #230

Closed
YannDuv opened this issue Apr 15, 2022 · 13 comments · Fixed by #242
Closed

Comments

@YannDuv
Copy link

YannDuv commented Apr 15, 2022

    "vue": "3.2.25",
    "vite": "2.8.0",
    "vite-ssg": "0.19.2",

I have a dialog that has a dependency on @a11y/focus-trap which is a web component.
As it is a web component, it uses stuff like document.createElement('template').
So I need to prevent it from being imported during SSG.

I tried 2 solutions without success :

  1. Test window presence with dynamic import
if (window) {
  import('@a11y/focus-trap')
}

Leads to the following error:

[vite-ssg] An internal error occurred.
[vite-ssg] Please report an issue, if none already exists: https://github.com/antfu/vite-ssg/issues
file:///Users/doe/Projects/front/.vite-ssg-temp/main.mjs:63
if (window) {
^

ReferenceError: window is not defined
    at file:///Users/doe/Projects/front/.vite-ssg-temp/main.mjs:63:1
    at ModuleJob.run (node:internal/modules/esm/module_job:183:25)
    at async Loader.import (node:internal/modules/esm/loader:178:24)
    at async importModuleDynamicallyWrapper (node:internal/vm/module:437:15)
    at async Object.build (/Users/doe/Projects/front/node_modules/vite-ssg/dist/chunks/build.cjs:171:87)
    at async Object.handler (/Users/doe/Projects/front/node_modules/vite-ssg/dist/node/cli.cjs:25:3)
  1. Use ClientOnly

Which is the only way in the documentation to prevent running code in SSG. I used it around all usage of the dialog component that does the import.
Sadly it doesn't change anything.

[vite-ssg] An internal error occurred.
[vite-ssg] Please report an issue, if none already exists: https://github.com/antfu/vite-ssg/issues
file:///Users/doe/Projects/front/.vite-ssg-temp/main.mjs:466
const template = document.createElement("template");
                 ^

ReferenceError: document is not defined
    at file:///Users/doe/Projects/front/.vite-ssg-temp/main.mjs:466:18
    at ModuleJob.run (node:internal/modules/esm/module_job:183:25)
    at async Loader.import (node:internal/modules/esm/loader:178:24)
    at async importModuleDynamicallyWrapper (node:internal/vm/module:437:15)
    at async Object.build (/Users/doe/Projects/front/node_modules/vite-ssg/dist/chunks/build.cjs:171:87)
    at async Object.handler (/Users/doe/Projects/front/node_modules/vite-ssg/dist/node/cli.cjs:25:3)

It would be nice to have an identified solution in the documentation to prevent code from running during SSG.

@YannDuv YannDuv changed the title Can't avoid crash when trying to test if build environment or client side. Can't avoid crash when trying to discriminate between build environment and client side. Apr 19, 2022
@YannDuv
Copy link
Author

YannDuv commented Apr 26, 2022

I got the same issue when working with crypto (from window.crypto). It's also a problem because i use it to generate ID in rendered content. Moreover, crypto should also be available in a node context.

@userquin
Copy link
Member

check for window with if (typeof window !== 'undefined')

@earlAchromatic
Copy link

I am having this issue as well, even with tests for window. As far as I can tell, what is happening is that even if you conditionally/dynamically import a module, if that module has dependencies then those are getting bundled in somewhere (main.mjs for example) and when Vite runs the ssr if those dependencies make use of window it will throw an error.

It seems like this problem is what the mock option is for (simulating window, document, etc) but I have not had any luck with that either.

@userquin
Copy link
Member

userquin commented May 3, 2022

@YannDuv @earlAchromatic can you provide a minimal repro?

@earlAchromatic
Copy link

See repro here: https://github.com/earlAchromatic/vite-ssg-build-v-client

or use npx degit earlAchromatic/vite-ssg-build-v-client vite-ssg-repro

Details are in the README. Note that I did solve the issue on my end - it turned out to be library specific.

I left the repro in case you want to look anyways. I am still curious why mock doesn't work in the case where window is accessed on the server during build (though perhaps that is a separate issue).

@userquin
Copy link
Member

userquin commented May 5, 2022

@earlAchromatic I've found the problem with mock, it is being loaded after loading the app SSR entry and should be loaded before loading that entry (or building the SSR entry), and so the error is there: I've your repo working with ESM patching 3d-force-graph and three-forcegraph dependencies (we need to add "type": "module" to both packages since the extensions are not .mjs).

I'll check updating the vite-ssg::build.mjs manually loading jsdom before SSR entry...

3d-force-graph/package.json
  "type": "module",
  "sideEffects": false,
  "exports": {
    ".": {
      "require": "./dist/3d-force-graph.common.js",
      "import": "./dist/3d-force-graph.module.js",
      "types": "./dist/3d-force-graph.d.ts"
    }
  },
three-forcegraph/package.json
  "type": "module",
  "sideEffects": false,
  "exports": {
    ".": {
      "require": "./dist/three-forcegraph.common.js",
      "import": "./dist/three-forcegraph.module.js",
      "types": "./dist/three-forcegraph.d.ts"
    }
  },

@userquin
Copy link
Member

userquin commented May 5, 2022

it works (loading jsdom before SSR entry), but then I get some errors loading three dependency:

  • WARNING: Multiple instances of Three.js being imported.

we also need to patch this another package:

three-render-objects/package.json
  "type": "module",
  "sideEffects": false,
  "exports": {
    ".": {
      "require": "./dist/three-render-objects.common.js",
      "import": "./dist/three-render-objects.module.js",
      "types": "./dist/three-render-objects.d.ts"
    }
  },

and then we got another error from @vueuse/core:

[vite-ssg] An internal error occurred.
[vite-ssg] Please report an issue, if none already exists: https://github.com/antfu/vite-ssg/issues
file:///F:/work/projects/quini/GitHub/issue-repro/vite-ssg-issues/vite-ssg-build-v-client-master/node_modules/.pnpm/@vueuse+core@8.3.1_vue@3.2.33/node_modules/@vueuse/core/index.mjs:500
      mediaQuery = window.matchMedia(query);
                          ^

TypeError: window.matchMedia is not a function

@userquin
Copy link
Member

userquin commented May 5, 2022

@earlAchromatic with your repo and applying previous patches, I can now use this on the src/pages/index.vue sfc (using ESM), we just need to patch/await useMediaQuery to be fixed:

<script setup>
import ForceGraph3D from '3d-force-graph'
onMounted(async () => {
  // const ForceGraph3D = await import('3d-force-graph')
  const N = 300
  const gData = {
    nodes: [...Array(N).keys()].map(i => ({ id: i })),
    links: [...Array(N).keys()]
      .filter(id => id)
      .map(id => ({
        source: id,
        target: Math.round(Math.random() * (id - 1)),
      })),
  }

  ForceGraph3D()(document.getElementById('3d-graph')).graphData(gData)
})
</script>

<template>
  <div id="3d-graph" />
</template>

@userquin
Copy link
Member

userquin commented May 5, 2022

A small fix allowing use useDark on src/composables/dark.ts module would be:

export const isDark = typeof window !== 'undefined' && typeof window.matchMedia !== 'undefined' ? useDark() : ref(false)
export const toggleDark = useToggle(isDark)

build just works:

F:\work\projects\quini\GitHub\issue-repro\vite-ssg-issues\vite-ssg-build-v-client-master>pnpm run build

> @ build F:\work\projects\quini\GitHub\issue-repro\vite-ssg-issues\vite-ssg-build-v-client-master
> vite-ssg build


[vite-ssg] Build for client...
vite v2.9.7 building for production...
✓ 370 modules transformed.
dist/index.html               0.83 KiB
dist/ssr-manifest.json        13.02 KiB
dist/assets/app.3b68aa3a.js   793.00 KiB / gzip: 220.18 KiB

(!) Some chunks are larger than 500 KiB after minification. Consider:
- Using dynamic import() to code-split the application
- Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/guide/en/#outputmanualchunks
- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit.

[vite-ssg] Build for server...
vite v2.9.7 building SSR bundle for production...
✓ 8 modules transformed.
.vite-ssg-temp/main.mjs   3.36 KiB

[vite-ssg] Rendering Pages... (1)
dist/index.html       1.22 KiB

[vite-ssg] Build finished.

@userquin
Copy link
Member

userquin commented May 5, 2022

I'll make a PR to fix it (loading jsdom before building or before loading SSR entry, I'm checking it right now)...

We also need to patch build.mjs, adding this before the SSR build:

imagen

and removing this:

imagen

imagen

@userquin
Copy link
Member

userquin commented May 5, 2022

@earlAchromatic here the same repo patching the deps to use ESM: also using a local vite-ssg loading the jsdom before SSR build, use pnpm install && pnpm run build && pnpm run preview (check the postinstall script on scripts/patch.ts module):

https://github.com/userquin/vite-ssg-build-v-client-master

@earlAchromatic
Copy link

@userquin Nice work! Thank you taking a deep dive into it. Patch script is great 😄

@userquin
Copy link
Member

userquin commented May 5, 2022

@earlAchromatic if you want to also use apollo with vite-ssg I have also a patch for it, just check https://github.com/userquin/vitesse-stackter-clean-architect, from #241

@antfu antfu closed this as completed in #242 Jun 1, 2022
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