antfu / vite-ssg

Static site generation for Vue 3 on Vite

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

YannDuv opened this issue · comments

    "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.

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.

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

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.

@YannDuv @earlAchromatic can you provide a minimal repro?

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).

@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"
    }
  },

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

@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>

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.

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

@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

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

@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