-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
sitemap.xml #1142
Comments
You can create an endpoint with a But if you are meaning that you want SvelteKit to provide the pages it knows about, that may be something that could be provided, similar to how the |
Yes, that seems along the lines that I'm thinking. |
I was playing with SvelteKit in November and wanted to do just that: generate a sitemap based on the pages. import {create_manifest_data} from '@sveltejs/kit/dist/utils.js';
const manifest = create_manifest_data('src/routes'); Then you can use the But it would be great if this would be exposed in some way. I also used the Svelte compiler to parse the pages to extract a svelte:head title, and some metadata comments, in this way you can auto-populate navigation. |
I also wanted to ask for that feature. Would be a great addition for SvelteKit to provide even more automations. |
It sure would be super nice if the sitemap would be generated from the page routes. But that only starts making real sense, if there was a way to define |
Here's a video tutorial showing how you can create your own |
I also need to create a sitemap.xml and think SvelteKit would benefit from having it built-in (as it's such a fundamental task). At minimum it should be explained in the docs how to do it correctly in "the SvelteKit way". To be honest I didn't like the video as it left me more confused than before: where is the new (?) api endpoint coming from? How else can I get the current list of pages? What's the deal with these endpoint URLs? How can I pre-generate the sitemap? ...Maybe it's all answered when watching the whole series but I'm not planning to do that. Edit: Because we developers (at least I ;) ) tend to make things more complicated than they have to be. For now I ended up writing the sitemap.xml manually. (Took less than 10 mins.) |
The video assumes that you have an existing API endpoint (e.g. at your CMS) that knows the correct routing and urls of all pages within your frontend website. A svelte-style solution in the future could be, that during build-time, every page generated is also optionally added to the sitemap. Maybe this could be configured with an additional option returned by the |
I feel like we should provide a way to expose the routing table, but that's the extent to which we should provide any sort of sitemap support. Exposing the routing table is also useful for automatic documentation generators, for example. |
That's how I do it at the moment and then I build the sitemap with a generator script via a npm prebuild script. For static content that's way better than building it on-the-fly with an endpoint. |
I agree with @antony SvelteKit should provide a way to expose the routing table. But meanwhile... I needed sitemap for my static website (used with https://github.com/bartholomej/svelte-sitemap Basically just install it and use it as
{
"name": "my-project",
"scripts": {
"prebuild": "svelte-sitemap --domain https://mydomain.com"
}
} And yes, I reckon that my library will soon become obsolete when the SvelteKit supports it natively ;) 👍 |
The routing table alone wouldn't be enough because you also need to know all possible values of all parameters to generate a sitemap, the date each page was last updated, etc. These are things that SvelteKit fundamentally cannot provide in most cases. I'm curious how people suggest this would be handled or if there are other frameworks doing a good job at this |
@benmccann Yes, Like I said, it's just a quick workaround library and a temporary solution. But for my purpose, that's ok for now :) I'm also curious how people suggest this would be handled... 👍 |
Nice tool @bartholomej! Would it make more sense to have something run as a post build so it could capture all the statically generated paths (including dynamic routes that are crawled by sveltekit)? Or am I misunderstanding how it works? |
Definitely, this should run as a postbuild by scanning the The script from this article works great as a postbuild: import fs from "fs";
import fg from "fast-glob";
import { create } from "xmlbuilder2";
import pkg from "./package.json";
const getUrl = (url) => {
const trimmed = url.slice(6).replace("index.html", "");
return `${pkg.url}/${trimmed}`;
};
async function createSitemap() {
const sitemap = create({ version: "1.0" }).ele("urlset", {
xmlns: "http://www.sitemaps.org/schemas/sitemap/0.9"
});
const pages = await fg(["build/**/*.html"]);
pages.forEach((page) => {
const url = sitemap.ele("url");
url.ele("loc").txt(getUrl(page));
url.ele("changefreq").txt("weekly");
});
const xml = sitemap.end({ prettyPrint: true });
fs.writeFileSync("build/sitemap.xml", xml);
}
createSitemap(); |
Thank you @auderer @madeleineostoja So now (in v1.0.0) it already works as a https://github.com/bartholomej/svelte-sitemap npm install svelte-sitemap --save-dev Let me know how it works ;) |
Although |
There's also a somewhat similar use case with export async function get({ host }) {
return {
headers: {
'Content-Type': 'text/plain',
},
body: `User-agent: *
Allow: /
Sitemap: https://${host}/sitemap.xml`,
};
} It would be nice, if you could have the ability to prerender GET requests, this could solve both cases. |
This comment was marked as off-topic.
This comment was marked as off-topic.
That's how I create a sitemap currently. If this endpoint is not being used in a link somewhere in the application it wont be prerendered. Maybe there was an option for // sitemap.xml.ts
export async function get() {
const response = await fetch('example.com/api')
if (!response.ok) {
return {
status: response.status,
body: response.statusText,
}
}
const staticPages = Object.keys(import.meta.glob('/src/routes/**/!(_)*.svelte'))
.filter(page => {
const filters: Array<string> = ['slug]', '_', '/src/routes/index.svelte']
return !filters.find(filter => page.includes(filter))
})
.map(page => {
return page
.replace('/src/routes', 'https://example.com')
.replace('/index.svelte', '')
.replace('.svelte', '')
})
const body = render(staticPages)
const headers = {
'Cache-Control': `max-age=0, s-max-age=${600}`,
'Content-Type': 'application/xml',
}
return {
body,
headers,
}
}
const render = (staticPages: Array<string>) => `<?xml version="1.0" encoding="UTF-8" ?>
<urlset
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"
xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0"
xmlns:pagemap="http://www.google.com/schemas/sitemap-pagemap/1.0"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
>
${staticPages.map(
staticPage => `
<url>
<loc>${staticPage}</loc>
<lastmod>${`${process.env.VITE_BUILD_TIME}`}</lastmod>
<changefreq>monthly</changefreq>
</url>
`,
)}
</urlset>
` |
I think there are a lot of people participating in this thread that don't understand that a SvelteKit-generated sitemap is likely to provide almost no value. Please read this whole comment before responding to it and don't leave comments that are just saying "this feature is important" without detailing a unique use case or imparting some technical information. I'm happy to consider things I may have overlooked, but +1 comments just add noise, slow down development, and will be hidden. You can thumbs up the issue to indicate support The main thing that sitemaps do is help search engines figure out how to prioritize crawling very large sites. Search engines prioritize crawling based on a number of factors such as how important/popular a site is, how often the site is updated, etc. If you have a very large site where there are meaningful changes randomly distributed deep in the site's structure and it isn't popular enough that the whole thing will be frequently recrawled by Google you can hint to it that it should focus on the new and updated pages with a sitemap so that it can go directly there instead of crawling the first pages it encounters and then giving up to do the rest later. Sitemaps do not affect the ranking of your page relative to other pages other than ensuring search engines have the latest copy of a page. For a sitemap to have an impact, you have to help the search engine prioritize which pages to crawl. SvelteKit cannot know which pages were recently updated and thus would have no possible way of generating a sitemap of any real value. It can't even know the list of pages in your site in most cases - except if you use By definition, sitemaps must be generated in user-land and not by the framework to have any meaningful value. A framework like Wordpress can provide SEO plugins because it's responsible for the content database and has a well defined set of data it's storing. But a sitemap is way outside the realm of what a frontend framework can provide. You could possibly have things like a Strapi+SvelteKit plugin, etc. But for SvelteKit in a standalone context I haven't seen anything that's both possible and valuable for it to do |
@benmccann thank you for the thoughtful response and for your work on SvelteKit. I really appreciate what you've done and the time you put into it. Thank you. I read your post and understand the technical and logical limitations of the ability of SvelteKit to generate a sitemap.xml. A few quick responses: Paragraph 2:
In paragraph 2 it seems like you're saying that sitemaps are not as essential as some people in this thread are implying. I think you're correct and would share the official Google Developers site about sitemaps. I think your comment echos these two points from the guide: Contrary though,
Given the above, you and I agree that there are many cases where sitemaps may not be necessary (small sites, comprehensively linked sites), but you must concede that certainly there are cases (numbers 1,2,3 above, for example) that websites built with SvelteKit do need a sitemap.xml. Do you agree? Paragraph 4:
I see your technical points here, and trust that you're correct. Given that, and my assertion (above) that sitemap.xml files are needed for some sites,
Finally, from a "developer relations" perspective, note that instead of trying to convince developers that sitemaps are unnecessary, those other frameworks have faced the fact that sitemaps are necessary for certain projects, and I think that's how we at SvelteKit should handle it. Even if it's not truly "built in" to SvelteKit, at least we can have a documentation page that explains the best way to do it (be it with a plugin, manually via a script in user world, etc etc). Thanks again. I appreciate your time and all the work you do for SvelteKit. |
Thanks @gavinr for the thoughtful and constructive reply.
SvelteKit could certainly generate a
Yes, if there are pages that are not linked to either from your own website or another, then a sitemap will help Google discover those pages. Most sites built with SvelteKit will be fairly new, but typically the vast majority of pages on a site will be linked to from within the site. If a page has no links to it, it's not going to rank well, so there's very little value in having a search engine crawl it because it's highly unlikely to drive any amount of traffic.
I'm assuming this is referring to Google's video extension of the sitemap standard. I'm less familiar with this than sitemaps in general, but I believe the reason Google requests it is because video embeds are often in iframes, which are difficult to crawlers to deal with. It's hard for me to see what exactly SvelteKit could offer in this situation. If there's some specific request, I'm happy to consider it. I don't have experience with video SEO, so I'm willing to be educated. My first reaction though is that this seems like something that fundamentally has to be dealt with in user land
SvelteKit provides a number of other features that are useful for SEO. E.g. it has been optimized to get really great core vital scores out-of-the-box. It's also does SSR by default and is maybe the only framework I've seen that can do dynamic rendering in just a few lines of code. These types of things are far more impactful, so I do think it's fair that we say we offer SEO benefits. In terms of the specific wording, I think that having a sitemap.xml that isn't aware of last modified times would be a compromise and would contradict the claim and having the user code it is necessary for uncompromising SEO. But anyway, we have at least one draft for a totally new homepage design and will do a homepage refresh in the future that will update this content. That will be a bit down the road though as right now we've chosen to put that on hold to finish the core features.
NextJS appears to support it in exactly the same manner as SvelteKit currently does based on this link.
Yes, totally agree with this. I'll take a stab at putting some starter docs up and people can add to them from there |
Hey @gavinr I've created sitemaps for Gatsby, NextJS and SvelteKit projects. Gatsby does have a plugin for creating sitemaps you can check out the documentation over on the Gatsby repo. I haven't used this in a while now, from my understanding it will crawl the file structure once the site is built and generate a For NextJS and SvelteKit the approach is similar. Create a route/endpoint for the sitemap, here you can generate the xml needed this is useful if the data for the site is dynamically generated. I documented how to make a sitemap with SvelteKit with help from @davidwparker's YouTube video. For reference here's my notes on creating a sitemap in NextJS Apologies for adding to the noise here @benmccann. The documentation from me can help until the starter docs have been added. |
Regardless wether sitemaps are good or bad, there should be the possibility to have one – which is perfectly possible through the And sure, all the page info and metadata (date, priority) is received from the content structure (MD files, API, CMS). So as long as your content knows the URL under which it will be visible, the best strategy would be to from within your When that is not the case, and routing is only implied by SvelteKit, you could create a |
Not noise at all! Thanks for sharing @spences10! Here's a draft of the SEO docs for folks who are interested: #3946 Also, I saw Astro has a sitemap plugin, so we could look at what they do for inspiration: https://github.com/withastro/astro/tree/main/packages/integrations/sitemap |
Hey I'm just chiming in to see if there's been any progress on this since Feb. Thanks Ben for all your hard work and great discussions thus far. |
Docs on how to generate a sitemap.xml were added in #3946: https://kit.svelte.dev/docs/seo#manual-setup-sitemaps (thank you @benmccann!) In that PR, @Rich-Harris suggested we leave this issue open:
|
I have a tangentially related question regarding what would be safe to exclude from robots... Specifically around if If anyone thinks this should be a separate issue I can log it. I did ask on the Svelte Discord with no answers |
A sitemap is really for end-user navigable routes, ie. the URLs that you want indexed, the content pages. You wouldn't list |
This is a good tutorial on sitemaps with Svelte kit: https://scottspence.com/posts/make-a-sitemap-with-sveltekit You can make a js file that returns a sitemap at: http://localhost:3000/sitemap.xml Sitemap protocol: https://www.sitemaps.org/protocol.html Here's some code I came up with (following the article linked above) for my site: const website = 'https://example.com';
const pages = [
{
url: '',
priority: 0.8
},
{
url: 'mypage'
}
];
export async function get() {
return {
headers: {
'Cache-Control': 'max-age=0, s-maxage=3600',
'Content-Type': 'application/xml'
},
body: `<?xml version="1.0" encoding="UTF-8" ?>
<urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9">
${pages
.map(
(page) =>
`<url>
<loc>${website}/${page.url}</loc>
<changefreq>monthly</changefreq>
<priority>${page.priority ?? 0.5}</priority>
</url>`
)
.join('')}
</urlset>`
};
} Last thing while I'm throwing in all the stuff I found useful that might found others, encoding XML: const encodeXML = (str) =>
str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, '''); |
Here's my variation for the current routing of the above neat solution shared by @Myrmod
|
hey i needed a way to generate sitemaps on the fly (not staticly) for some Shopify storefronts. So I built this hooks/plugin to do just that. It's really helpful when dealing with dynamic routes, here is an example of the api. (As a plus it also helps you to generate robots.txt). => https://github.com/beynar/sveltekit-sitemap. sitemapHook(sitemap, {
//...
getRoutes: async (event) => {
const blogs = await event.locals.api.getBlogsForSitemap();
// ^-- make async api call to get fresh data
return {
"/about": {
path: "/",
priority: "0.8"
},
// ^-- Static routes are automatically added to the sitemap. But if you want to customize them, you can return a route definition object.
"blogs/[handle]": blogs,
"/products/[id]": [
{ path: "/products/test-1" },
{ path: "/products/test-2" },
{
path: "/products/test-3",
changeFreq: "Monthly",
priority: "0.8",
lastMod: "2023-01-01",
image: {
url: "https://picsum.photos/200/300",
title: "test-1",
altText: "image-product-test-1"
}
}
]
// ^-- For dynamic routes you have to return an array of route definitions
};
}
}); |
Manually you can generate your |
Exposing a routing table would solve 90% of the remaining pain points, imo: Currently:
A routing table would allow iterating over it to: 1.) automatically include non-parameterized routes, and 2.) throw a build warning when forgetting to add data for a parameterized route, ensuring no paths are forgotten. (Side note: Google ignores priority and changefreq.) |
This is what I use to get non-parameterized routes, with parameterized ones expected to be provided (e.g. they would come from a database) import type { RequestHandler } from '@sveltejs/kit'
import { getProductURLs } from './store'
export const GET: RequestHandler = async ({}) => {
const [pages, productURLs] = await Promise.all([
import.meta.glob('/src/routes/**/+page.svelte'),
getProductURLs(),
])
const routes = Object.keys(pages)
.map((x) => x.substring(11)) // remove /src/routes prefix
.map((x) => x.substring(0, x.length - 13)) // remove /+page.svelte suffix
.map((x) => x.replaceAll(/\/\(\w+\)/g, '')) // remove (groups)
.filter((x) => !x.includes('[')) // filter out parameterized routes
.sort() // satisfy OCD
const urls = routes.concat(productURLs)
const sitemap = `<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls.map((url) => ` <url><loc>https://example.com${url}</loc></url>`}).join('')}
</urlset>`
return new Response(sitemap, {
headers: {
'Content-Type': 'application/xml',
'Cache-Control': 'public, max-age=3600',
},
})
} |
I just published a package that I think creates a near ideal DX, for me at least. Thanks to @CaptainCodeman for the inspo. Super Sitemap (npm) - SvelteKit sitemap focused on ease of use and making it impossible to forget to add your paths.
Features
The Github README has JS & TS examples. Happy to get feedback, issues, etc! |
Is your feature request related to a problem? Please describe.
Most websites need to provide a
sitemap.xml
for SEO purposes.Describe the solution you'd like
SvelteKit should provide a way (automatically, or recommended way via documentation) on how to create a sitemap.xml.
Describe alternatives you've considered
I see sitemap.xml generation is mentioned in the sapper repo - is this the way to do it?
Also mentioned by @antony here.
How important is this feature to you?
I think this will affect a large number of SvelteKit users who are building websites.
Note
The SvelteKit homepage says:
Without supporting
sitemap.xml
, this claim is inaccurate/disingenuous.Thank you!
The text was updated successfully, but these errors were encountered: