New hook `onRenderContent()`: generate non-HTML files with arbitrary content
Description
I hope vike can generate files that is not HTML and without injected tags.
The requirements are
- The generation script need to work inside vite context (need access to vite API like
import.meta.glob) - Work in development mode (can see the file on development server)
- Work in production build (the file is generated correctly with a chosen filename without .html)
Related: #1522 #1524
Use Cases
- Generate Atom feed from blog posts
- Generate Sitemap #49
- Web Application Manifest
Workarounds
- Use your server instead of Vike. For example, create a new Express.js route that serves your non-HTML URL.
- Generate a custom HTTP response after calling
renderPage().
Use Cases
- Generate Atom feed from blog posts
- Generate Sitemap Sitemap Generation #49
So far the recommendation for these two use cases are to use a post-build script (without using Vite).
I agree that being able to use Vite for transpiling the post-build script would be nice. In the meantime, can you fallback to use other utilities such as ts-node (and fast-glob instead of import.meta.glob())?
Why not adding a new CLI command $ vike run path-to/some-script.ts instead of your proposal?
Or maybe a new Vike hook onAfterBuild(), but that would work only for build. Actually, how about a new generic hook onRenderContent() that can generate content that isn't HTML.
Spontaneously I like $ vike run and onRenderContent() most. But I'm happy to discuss this.
Also, what do other frameworks do to support these two use cases? Can someone dig into that?
onRenderContent is best, I think. Still need to offer an option to set the output path, though. It would be nice if the API allows access to pageContext from other files like page title, which will make sitemap generation easier.
Also, what do other frameworks do to support these two use cases? Can someone dig into that?
lume allows generating arbitrary file content. lume has a sitemap plugin.
To set the page URL in lume, you simply do
export const url = "/feed.json";
or
---
url: /blog/example.md
---
# Page Content Here
Eleventy allows generating arbitrary content too. It has a RSS plugin which only provides data and needs the user to provide a template for it. You can use the RSS plugin to generate a site map with the correct template.
Still need to offer an option to set the output path, though.
Or how about using Filesytem Routing as usual?
It would be nice if the API allows access to
pageContextfrom other files
You shouldn't do that in dev, see https://vike.dev/markdown#metadata. Upon pre-rendering you can already access that, although it's currently hidden behind an internal API: pageContext._prerenderContext.pageContexts.
It makes sense that SSGs like Lume and Eleventy supports that use case. I was more wondering about SSR frameworks such as Next.js or Nuxt.
Or how about using Filesytem Routing as usual?
How do I generate dist/client/feed.json but not dist/client/feed.json/index.html?
Also, I can't name a folder feed.json because vite complains about trying to load the folder as JSON. (you can create feed.json/+Page.tsx to test it out)
It makes sense that SSGs like Lume and Eleventy supports that use case. I was more wondering about SSR frameworks such as Next.js or Nuxt.
In those frameworks, the Atom feed is usually an API route, and vike made the decision to not support API routes (I read that in the docs).
How do I generate
dist/client/feed.jsonbut notdist/client/feed.json/index.html?
Vike wouldn't create an .html file when the content is generated with onRenderContent().
Also, I can't name a folder
feed.jsonbecause vite complains about trying to load the folder as JSON. (you can createfeed.json/+Page.tsxto test it out)
You could use a Route String.
In those frameworks, the Atom feed is usually an API route, and vike made the decision to not support API routes (I read that in the docs).
You can use an Express.js/Fastify/Hono/... route instead. Note that we're currently working on https://github.com/vikejs/vike/issues/562. I stand to be corrected, but I believe that once #562 is implemented then API routes would be an inferior design in all regards.
Vike wouldn't create an
.htmlfile when the content is generated withonRenderContent().
I need a static page! onRenderContent won't generate a JSON file, or can it?
You could use a Route String.
A route string of /feed.json generates /feed.json/index.html
In #562, you linked to vite-node. I'll try writing a script with that. Thanks for the idea!
@iacore It will create a file, it just won't be a .html one. If you set the Route String to end with .json so will the generated file.
Since there is a workaround and there are only two use cases for it, I'm labeling this as low-prio 🐌.
That said, the priority can be increased by:
- Reacting to the original post of this issue with "👍".
- Further elaborating use cases. (The more we can see how much added value it adds, the higher we'll increase its priority.)
- Creating a PR. (For example, if your PR showcases that it's easy to implement, then we'll merge it. That said, keep in mind that we may reject your PR if reviewing it would take too much time.)
- Does any React/Vue/Solid SSR framework out there support your use case? If yes that also increases the priority.
- Sponsoring Vike
The vite-node method worked! Do we document the vite-node usage somewhere?
I haven't tried onRenderClient. Is it strange that onRenderClient renders to a file on the server?
I haven't tried
onRenderClient. Is it strange thatonRenderClientrenders to a file on the server?
Apologies I meant onRenderContent() not onRenderClient(). I've edited my comment (and yours).
The
vite-nodemethod worked! Do we document thevite-nodeusage somewhere?
It isn't. I think it's fine for now as there are currently a lot of higher priorities regarding the docs.
Apologies I meant
onRenderContent()notonRenderClient(). I've edited my comment (and yours).
I assume you meant onRenderHtml. I can't find a onRenderContent hook.
@iacore It will create a file, it just won't be a
.htmlone. If you set the Route String to end with.jsonso will the generated file.
as of vike 0.4.165, it generates xxx.json/index.html rather than xxx.json, with the route string below:
// +route.ts
export default '/test.json'
Interesting approach by SvelteKit: https://kit.svelte.dev/docs/seo#manual-setup-sitemaps