Describe the bug
goto(...) causes ReferenceError: document is not defined.
Logs
(node:30909) UnhandledPromiseRejectionWarning: ReferenceError: document is not defined
[...]
(node:30909) UnhandledPromiseRejectionWarning: Unhandled promise rejection. [...]
To Reproduce
sapper-template repo with degit.src/routes/about.svelte:diff --git a/src/routes/about.svelte b/src/routes/about.svelte
index e1734b3..f6c4afa 100644
--- a/src/routes/about.svelte
+++ b/src/routes/about.svelte
@@ -1,3 +1,11 @@
+<script>
+import { goto } from '@sapper/app';
+const navigate = async () => {
+ await goto('/');
+}
+navigate();
+</script>
+
<svelte:head>
<title>About</title>
</svelte:head>
npm run dev.Expected behavior
The browser should navigate to http://localhost:3000/ without causing that error.
Stacktraces
Stack trace
UnhandledPromiseRejectionWarning: ReferenceError: document is not defined
at goto (/private/tmp/my-app/__sapper__/dev/server/server.js:495:45)
at navigate (/private/tmp/my-app/__sapper__/dev/server/server.js:886:9)
at /private/tmp/my-app/__sapper__/dev/server/server.js:889:2
at Object.$$render (/private/tmp/my-app/__sapper__/dev/server/server.js:230:22)
at Object.default (/private/tmp/my-app/__sapper__/dev/server/server.js:426:86)
at /private/tmp/my-app/__sapper__/dev/server/server.js:372:70
at Object.$$render (/private/tmp/my-app/__sapper__/dev/server/server.js:230:22)
at /private/tmp/my-app/__sapper__/dev/server/server.js:423:40
at $$render (/private/tmp/my-app/__sapper__/dev/server/server.js:230:22)
at Object.render (/private/tmp/my-app/__sapper__/dev/server/server.js:238:26)
Information about your Sapper Installation:
"sapper": "^0.27.0"Svelte version: "svelte": "^3.0.0"
Whether your application uses Webpack or Rollup: "rollup": "^2.3.4"
Additional context
The exception is thrown by line
const target = select_target(new URL(href, document.baseURI));
in the generated goto function.
This works as long as that code is executed in the browser. This happens whenever you go to http://localhost:3000/ and navigate to the about page from there -- or from any other page different than the about page.
As far as I understand, as soon as you open http://localhost:3000/about directly, that code is run on the server. There, document is not available.
This is as designed, and goto() is listed in the docs under the 'Client API' section. Either guard against your code running on the server with onMount() or if (process.browser), or use this.fetch in preload for a unified way to perform a redirection either on the server or on the client.
This is as designed, and
goto()is listed in the docs under the 'Client API' section. Either guard against your code running on the server withonMount()orif (process.browser), or usethis.fetchinpreloadfor a unified way to perform a redirection either on the server or on the client.
Thanks for your prompt help. Makes sense -- I misunderstood the 'client' aspect. I thought this meant that code will be executed by the browser (= client) in all cases.
Using onMount works like a charm.
Either guard against your code running on the server with onMount() or if (process.browser), or use this.fetch in preload for a unified way to perform a redirection either on the server or on the client.
A few examples of each would be very helpful to understand the use cases. I'm struggling with a login route (it calls a REST API for authentication): once the user is logged (the POST request receives a status 200), I set a user object in the session store and then I want to redirect to some other page. I can't figure what goes in module/preload and what goes in the component script (in particular regarding the redirection...).
This seems to be a common cause of misunderstandings; how about catching any errors about missing window and document in development and producing a more explanatory error message? I know Gatsby does this for example.
I agree @ehrencrona
I would suggest:
window/document usage (when undefined, in case somebody is doing something quite odd) on the server which points to the FAQRaised this here: https://github.com/sveltejs/sapper/issues/1554
Most helpful comment
This is as designed, and
goto()is listed in the docs under the 'Client API' section. Either guard against your code running on the server withonMount()orif (process.browser), or usethis.fetchinpreloadfor a unified way to perform a redirection either on the server or on the client.