plentico / plenti

Static Site Generator with Go backend and Svelte frontend
https://plenti.co
Apache License 2.0
1.02k stars 49 forks source link

RSS/Atom feed support #172

Open preslavrachev opened 2 years ago

preslavrachev commented 2 years ago

Hello,

First of all, I want to thank you for the amazing tool. As a long-time practitioner of both Go, Hugo, and Svelte, I cannot help but marvel at the possibility to combine the superpowers of all three together.

I am not sure I noticed any support for exporting an RSS/Atom feed. This is important to me (and frankly, for the future of the open Web).

What would be required for making this work and is this something I could maybe contribute to?

jimafisk commented 2 years ago

Hi @preslavrachev,

Thanks for the kind words! This is a great idea, I don't use RSS feeds a ton so I'm using https://www.nasa.gov/rss/dyn/breaking_news.rss as a model. Looks like they simply put it in a string inside <pre> tags, is that normal?

I originally thought about accomplishing this using jsonfeed-to-rss and passing Plenti's allContent magic prop to it, but it doesn't have esm support and would require nodejs + some modifications to our build process to get it to work. What are your thoughts on manually creating the xml and simply inserting the content yourself? I created a test repo to demonstrate what I mean by that: https://github.com/jimafisk/plenti-rss

Here's the demo site: https://jimafisk.github.io/plenti-rss Here's the actual RSS feed: https://jimafisk.github.io/plenti-rss/rss

Here are the steps I took:

<script>
    export let allContent;
    let allPosts = allContent.filter(content => content.type == "blog");

    let rssFeed = '<?xml version="1.0" encoding="UTF-8" ?><rss version="2.0"><channel><title>My Site Blog</title><link>https://www.mysite.com/blog</link><description>Awesome blog posts for my site</description>';
    allPosts.forEach(post => {
        rssFeed += '<item><title>' + post.fields.title + '</title>';
        rssFeed += '<link>' + post.path + '</link>';
        rssFeed += '<description>' + post.fields.body[0] + '</description>';
        rssFeed += '</item>';
    });
    rssFeed += '</channel></rss>';

</script>

<pre style="word-wrap: break-word; white-space: pre-wrap;">
    {rssFeed}
</pre>

(I also added a conditional in layouts/global/html.svelte to remove the header and footer from the RSS feed)

So with that, every time you add a blog post to your site, it should automatically get added to your RSS feed without additional coding. It's not the nicest looking solution, mainly because you can't currently use template literals (there's a bug when adding backticks in Plenti: https://github.com/plentico/plenti/issues/121), but would something like this work for you?

preslavrachev commented 2 years ago

@jimafisk thank you for the thorough answer. Yeah, I am OK with creating a custom template for RSS. In fact, I usually do something similar for my backend projects.

However, what you've presented here won't really work, because the RSS feed needs to be only the raw XML and nothing more. In your case, the RSS feed seems to be a full-fledged web page with a head, body, etc.

To be honest, I don't think this is a problem that can be solved from Svelte. I think that the Go builder is the better place to do it. It has to enumerate all the content during building anyway, plus it has the compiled Svelte content, so it might as well output one or more RSS files, based on some predefined rules.

jimafisk commented 2 years ago

Ahh yes that makes sense.

Nasa feed is xml ![nasa](https://user-images.githubusercontent.com/5913244/146982190-7042f1e1-027a-4b59-a6b4-fdfc2119a4e4.png)
Example Plenti feed is html ![bad_rss](https://user-images.githubusercontent.com/5913244/146982237-a6044d64-c73c-4809-93bb-dd508483a1c1.png)

So you could go outside of the wrapper in layouts/global/html.svelte entirely like so:

<script>
  import RSS from '../content/rss.svelte';
  export let allContent;
</script>
{#if content.path == "rss"}
  <RSS {allContent} />
{:else}
<html lang="en">
   {...}
</html>
{/if}

Then in layouts/content/rss.svelte change the Content-Type:

<head>
  <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="rss" />
</head>

Unfortunately it still doesn't solve the issue of rendering xml in a Svelte component. The @html filter won't work for this, and there isn't a @raw filter. So I think you're right that we'll have to create the xml using Go during the build. I was hoping to be able to do it in the svelte templates so you'd have ultimate control over the output. This is probably something we'd have folks define in the sitewide plenti.json configuration file, just need to figure out a way to make it flexible while not being overwhelming.

preslavrachev commented 2 years ago

I can't promise anything, but I will try to use the quiet time around the holidays to look at the code and sketch something out.

axodys commented 11 months ago

Has there been any further thought on this issue recently? Looks like it's been over a year since anything related has been discussed. Discovered Plenti yesterday and it looks amazing, but the lack of xml/rss templating support is a deal breaker for my purposes.

jimafisk commented 11 months ago

Hi @axodys, thanks for your interest in the project! Are you looking for a simple way to auto-generate a sitemap.xml or were you hoping for more control over the XML output to build custom RSS feeds?

For me, in an ideal world you could build this out yourself in the layouts folder using the JSON content just like any other template. Unfortunately I don't think Svelte can SSR an XML file, so I'd have to think of a creative way to do this. Putting the process in Go during the build would take control away from the user and/or would require config to make adjustments. If anyone has thoughts on how we could do this with the Svelte compiler let me know!