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