kit
kit copied to clipboard
Trouble converting svelte skeleton site to static, using adapter-static
Describe the bug
Hi, and thank you for working on a dev tool I love!
I’m attempting to make a static site with Svelte. My ultimate goal is to convert a two-page site I’ve already built into something I can host on GH Pages instead of its current hosting on Netlify. However, I’ve run into a problem while using adapter-static, so I am now try to convert just the basic starter "skeleton" into a static site, and ... I’m running into the same problem.
In summary, adapter-static keeps telling me:
@sveltejs/adapter-static: all routes must be fully prerenderable, but found the following routes that are dynamic:
- src/routes/
I’ve tried to follow the advice that follows, but adding export const prerender = true; to my src/routes/+layout.svelte file doesn’t seem to make a difference.
Reproduction
To keep things simple, I’ll just say how to reproduce this with the skeleton site.
- Start a new project with
npm create svelte@latest my-app(following the Creating a Project guide) - Follow the prompts to set up the project. I’m using JS, ESLint, and Prettier, but not Playwright
- Test that the basic
npm run devworks (it did for me) - Follow the adapter-static docs to convert the project to a static one.
// svelte.config.js
import adapter from '@sveltejs/adapter-static';
const dev = process.env.NODE_ENV === 'development';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
adapter: adapter({
// default options are shown. On some platforms
// these options are set automatically — see below
pages: 'docs',
assets: 'docs',
fallback: null,
precompress: false,
strict: true
}),
paths: {
base: dev ? '' : '/svelte-static-test-from_skeleton',
},
}
};
export default config;
I tried to follow a suggestion, adding a file at src/routes/+layout.svelte. that simply includes the following:
<script>
export const prerender = true;
</script>
...but this didn’t change the error.
I can’t get the build to work, so I don’t have browser logs, but the following is the full result from my terminal when I run the command npm run build.
Logs
~/code/svelte-static-test-from_skeleton master ✗ 21m ⚑ ◒ ⍉
▶ npm run build
> [email protected] build
> vite build
polyfillModulePreload is deprecated. Use modulePreload.polyfill instead.
vite v3.2.0 building for production...
✓ 36 modules transformed.
polyfillModulePreload is deprecated. Use modulePreload.polyfill instead.
vite v3.2.0 building SSR bundle for production...
✓ 44 modules transformed.
Generated an empty chunk: "hooks"
.svelte-kit/output/server/vite-manifest.json 1.03 KiB
.svelte-kit/output/server/index.js 71.03 KiB
.svelte-kit/output/server/entries/pages/_layout.svelte.js 0.24 KiB
.svelte-kit/output/server/entries/fallbacks/error.svelte.js 1.50 KiB
.svelte-kit/output/server/entries/pages/_page.svelte.js 0.31 KiB
.svelte-kit/output/server/chunks/index.js 3.15 KiB
.svelte-kit/output/server/chunks/hooks.js 0.00 KiB
Run npm run preview to preview your production build locally.
.svelte-kit/output/client/vite-manifest.json 2.11 KiB
.svelte-kit/output/client/_app/immutable/components/error.svelte-6882d5bf.js 2.07 KiB / gzip: 0.95 KiB
.svelte-kit/output/client/_app/immutable/components/pages/_layout.svelte-95eb34a5.js 0.43 KiB / gzip: 0.30 KiB
.svelte-kit/output/client/_app/immutable/chunks/0-39c7f10b.js 0.09 KiB / gzip: 0.10 KiB
.svelte-kit/output/client/_app/immutable/components/pages/_page.svelte-7a1cdd0a.js 0.81 KiB / gzip: 0.47 KiB
.svelte-kit/output/client/_app/immutable/chunks/singletons-1b0e5fcb.js 1.81 KiB / gzip: 0.99 KiB
.svelte-kit/output/client/_app/immutable/chunks/index-a22ecbec.js 6.08 KiB / gzip: 2.51 KiB
.svelte-kit/output/client/_app/immutable/chunks/2-eb11e36a.js 0.09 KiB / gzip: 0.10 KiB
.svelte-kit/output/client/_app/immutable/chunks/1-e1814a8c.js 0.09 KiB / gzip: 0.09 KiB
.svelte-kit/output/client/_app/immutable/start-77a5842c.js 24.87 KiB / gzip: 9.73 KiB
> Using @sveltejs/adapter-static
@sveltejs/adapter-static: all routes must be fully prerenderable, but found the following routes that are dynamic:
- src/routes/
You have the following options:
- set the `fallback` option — see https://github.com/sveltejs/kit/tree/master/packages/adapter-static#spa-mode for more info.
- add `export const prerender = true` to your root `+layout.js/.ts` or `+layout.server.js/.ts` file. This will try to prerender all pages.
- add `export const prerender = true` to any `+server.js/ts` files that are not fetched by page `load` functions.
- pass `strict: false` to `adapter-static` to ignore this error. Only do this if you are sure you don't need the routes in question in your final app, as they will be unavailable. See https://github.com/sveltejs/kit/tree/master/packages/adapter-static#strict for more info.
If this doesn't help, you may need to use a different adapter. @sveltejs/adapter-static can only be used for sites that don't need a server for dynamic rendering, and can run on just a static file server.
See https://kit.svelte.dev/docs/page-options#prerender for more details
error during build:
Error: Encountered dynamic routes
at adapt (file:///Users/stephennixon/code/svelte-static-test-from_skeleton/node_modules/@sveltejs/adapter-static/index.js:53:12)
at adapt (file:///Users/stephennixon/code/svelte-static-test-from_skeleton/node_modules/@sveltejs/kit/src/core/adapt/index.js:28:8)
at Object.handler (file:///Users/stephennixon/code/svelte-static-test-from_skeleton/node_modules/@sveltejs/kit/src/exports/vite/index.js:493:12)
at async PluginDriver.hookParallel (file:///Users/stephennixon/code/svelte-static-test-from_skeleton/node_modules/rollup/dist/es/shared/rollup.js:22670:17)
at async Object.close (file:///Users/stephennixon/code/svelte-static-test-from_skeleton/node_modules/rollup/dist/es/shared/rollup.js:23750:13)
at async Promise.all (index 0)
at async build (file:///Users/stephennixon/code/svelte-static-test-from_skeleton/node_modules/vite/dist/node/chunks/dep-61d2428a.js:48150:13)
at async CAC.<anonymous> (file:///Users/stephennixon/code/svelte-static-test-from_skeleton/node_modules/vite/dist/node/cli.js:758:9)
System Info
System:
OS: macOS 12.5
CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
Memory: 2.00 GB / 32.00 GB
Shell: 5.8.1 - /bin/zsh
Binaries:
Node: 18.12.0 - ~/.nvm/versions/node/v18.12.0/bin/node
Yarn: 1.22.19 - /usr/local/bin/yarn
npm: 8.19.2 - ~/.nvm/versions/node/v18.12.0/bin/npm
Browsers:
Chrome: 106.0.5249.119
Chrome Canary: 109.0.5384.0
Firefox: 105.0.1
Safari: 15.6
Safari Technology Preview: 16.0
npmPackages:
@sveltejs/adapter-auto: next => 1.0.0-next.84
@sveltejs/adapter-static: ^1.0.0-next.46 => 1.0.0-next.46
@sveltejs/kit: next => 1.0.0-next.525
svelte: ^3.44.0 => 3.52.0
vite: ^3.1.0 => 3.2.0
Severity
blocking all usage of SvelteKit
(at least, all usage of SvelteKit to make a static site, which is my current main goal)
Additional Information
My understanding of the concept of what exactly "dynamic rendering" means is pretty surface level. So, I might be missing some part of what I need to do to convert a site to static.
A specific question I have: can I run a Svelte store file if a site is converted to static, or would that make it dynamic? I’m using a Svelte store on a website to have a play/pause button in the navigation menu, which can play/pause CSS animations on either the home page or the about page (the site is just two pages, and won’t need frequent updates, so making it static seems ideal).
At the end of the day, my main goal is making a simple font specimen website that I can put up on GH Pages, and which I can trust to continue working for the foreseeable future. Svelte is awesome for this, because it makes it fun to see up interactive things like a "type tester" with variable axis sliders, and makes overall site composition really nice. I have a dynamic version that currently works well on Netlify, but I worry that maybe it may stop working (or be subject to hosting pricing changes) sooner than a static site would. If I am wrong to worry here, I’m also happy to hear if those concerns are unfounded.
Thank you so much for any insights or help!
As mentioned in the issue template, please provide a clonable repo, not a list of instructions to follow.
Explaining how to reproduce is generally not enough. It pushes the burden of creating a reproduction project onto a small set of volunteer maintainers and isn't scalable.
export const prerender = true; should be added to +layout.js (note the file ending), not +layout.svelte. Do that and it should work.
Keeping this open as it has come up a bunch of times now - is there any way we can make this more obvious? People seem to glance over the file ending and adding it to their +layout.svelte, probably also biased by the fact they often do not have a +layout.js present at that time.
Perhaps in development we could check to see if any route components (+layout.svelte, +page.svelte, +error.svelte) have unexpected properties (i.e. anything at all in +error.svelte, anything except data in +layout.svelte, anything except data or form in +page.svelte) and warn in that case (with special handling for things like prerender). Not sure how to determine that without svelte.compile though, which would add a bunch of complexity.
I like that idea, and I think a regex would probably get us there. We could do something like this:
- read content of
+layout/page.svelte - extract script content with a regexp (Svelte's preprocessors all do that already, so it's proven it works 99,99% of the time)
- run it through typescript, if available, or do a simple regex for
export const prerender/ssr/csr = - if found something, warn
Ohhh wow, that was simpler than expected – thanks for the quick answer, @dummdidumm!
Keeping this open as it has come up a bunch of times now - is there any way we can make this more obvious?
Sorry, I did try to search for the issue multiple times, using the error messaging and keywords, but couldn’t find it. The error happens very early on in the experience, so it felt somewhat overwhelming, and like a possible indication that maybe it was just too early to be working in the static side of Svelte. This feeling might affect others with the issue, as well.
As for making it more obvious... here’s my two cents:
Part of what confused me is that the suggested solution acted as if the file were already there, which it wasn’t. I had to add layout.js to src/routes/+layout.js with the prerender setting.
- add
export const prerender = trueto your root+layout.js/.tsor+layout.server.js/.tsfile. This will try to prerender all pages.
Because there wasn’t yet a file there – but the suggestion acted as if it were, and the filename was so similar to a file that did exist – I thought it must be referring to the existing file, +layout.svelte.
Potentially, the build could check whether +layout.js exists yet, and suggest adding it if it doesn’t. Short of that, the docs for adapter-static could perhaps suggest this.
Further, I was initially confused by the specific way the error refers to +layout.js/.ts in the context of the full error traceback. I think my brain interpreted this as possibly meaning that the file might also have a .svelte extension, though in hindsight, that seems silly.
As mentioned in the issue template, please provide a clonable repo, not a list of instructions to follow.
Sorry! I meant to do this, but had a meeting coming up, but I had to file this issue to figure this out today... and my mind went a bit fuzzy. I will be sure to do this next time around.
To make this more obvious, the headline for that section could perhaps be "Reproduction Repo." But, yes, that was my bad.
Anyway, thanks for the help, everyone! I love Svelte, and I really appreciate the thoughtful design of its developer experience.
Update: YESSSSS I got the actual project working on GH Pages! Stoked about this. Thanks again!
The global state managed with src/stores.js also seems to work perfectly across the two pages, which is awesome.
Notes for others who might come across this:
- My global.css initially wasn’t working, but I just had to fix paths in the
<head>insrc/app.html. They need to have a leading., like<link rel='stylesheet' href='./global.css'>. Before, it just had a slash, and that didn’t work. - My JS doesn’t work locally if I open
index.htmlin thedocs(build) folder, but it does work on GitHub Pages. And, it does work withnpm run dev, so life is good!
Confusion over adding export const prerender = true to the root +layout.js vs +layout.svelte just bit me too. Following a migration from like next.398 or so, that file wasn't there.
Maybe the error message could specify if the root +layout.js doesn't exist already? Or say to create the root +layout.js if it doesn't exist?
Maybe the error message could specify if the root +layout.js doesn't exist already? Or say to create the root +layout.js if it doesn't exist?
I would add to this that is should be clearer in the docs that +layout.svelte is a completely different file. I thought they'd be interchangeable and that +layout.svelte would be compiled/transpiled to +layout.js until I found this issue and the solution above
I would add, in addition to @TommasoAmici 's comment, that building to a static site was the main recurring issue (source of unanswerable errors) I had a new SvelteKit user primarily because I missed the detail described above. Even after several tutorials and days with the documentation, I still have not come across anything describing the difference between the *.svelte and its corresponding *.js file until I found this post and went looking for more information. https://stackoverflow.com/a/77753750/441878
The docs have a list of the different file types and this section describes what you can do in a .js file. What about this documentation was unclear to you / what is it lacking to make it click for you?
@dummdidumm Thanks for asking. I feel overall that the docs are generally geared towards using dynamic content from a server, so often will not be explicit with requirements for a static site which needs multiple routes. I also feel that pages like Routing could use images and diagrams to explain the process for visual learners.
Another close read of that page on Routing, for example doesn't discuss the differences between JS in<script> or <script type="module"> in a +page.svelte file and JS in a corresponding +page.js. It mentions that the onLoad "runs on the server during server-side rendering and in the browser during client-side navigation", but that you need to "rename +page.js to +page.server.js" if "your load function can only run on the server" which makes it further confusing.
After looking across the web for better discussions I found this documentation on script and script module which was helpful, but again does not mention the .js files.
In my case, I found this issue because I had placed export const prerender = true; inside +layout.svelte and the warning export const prerender will be ignored — move it to +layout(.server).js/ts instead. was confusing. Why would I use a server side script if I was building for SSG? If the +layout.js is not a server side script, and code I put inside the .svelte file isn't the right place, then what exactly is this file? I recall visiting this Project structure page several times trying to find an answer to this question. The warning could be more clear if it was explicit that I had options like: move it to +layout.js/ts or +layout.server.js/ts instead, and the Project structure page could include a section that discussed (perhaps visually?) what the specific locations for JS/TS mean and yield. I am comparing Astro to SvelteKit at the moment, which has an entire page dedicated to the structure and effects of Components