nuxt-community / feed-module

Everyone deserves RSS, ATOM and JSON feeds!
MIT License
226 stars 36 forks source link

feat: nuxt 3 support #114

Open NozomuIkuta opened 1 year ago

NozomuIkuta commented 1 year ago

Replace nuxt/framework#108 with minimal spec for fast upgrade. Sorry, I had to recreate PR because I changed my personal email settings.


This draft PR aims to take over nuxt/framework#103 and resolves nuxt/framework#106.

At first, for the next major release, I triaged all the open issues as below (except Renovate Dependency Dashboard (#99)).

My implementation may include some breaking changes in API, as done in nuxt/framework#103, in a way that I believe is good and beneficial enough for users. I would like to discuss with authors and community while developing this PR.

This PR doesn't aim to add Docus-powered documentation, which is handled in nuxt/framework#103, so that we can keep this PR's "done of definition" manageable.

This PR message will be modified as needed.

TODOs

Out of Scope

References

NozomuIkuta commented 1 year ago

As of v3.3.1, Nuxt supports nitro:build:public-assets hook, which is said to be the successor to generate:done hook.

I believe now it's time to complete this PR.

@danielroe

Is it simply interchangeable, or is there difference from generate:done hook on usage?

danielroe commented 1 year ago

It should be interchangeable for the purpose of this module.

NozomuIkuta commented 1 year ago

Hmm, if I'm correct, this module has to know all routes inside server route(s) to return feed file(s) as response, and I can't find the way...

Current code in my local looks like this. I checked app instance passed via app:templates, but there doesn't seem to be information about routes 🤔

Or, am I totally taking wrong approach?

    nuxt.hook('pages:extend', (pages) => {
      sources.forEach((source, index) => {
        const { dst } = addTemplate({
          filename: `feed-${source.type}-${index}.mjs`,
          getContents: () => `
import { Feed } from 'feed'
import { defineEventHandler } from 'h3'

export default defineEventHandler(async (event) => {
  const feed = new Feed()

  feed.options = {
    generator: 'https://github.com/nuxt-community/feed-module',
  }

  ${pages.forEach((page) => `
  feed.addItem({
    title: ${page.meta?.title ?? ''},
    id: ${page.path},
    link: ${page.path},
    description: ${page.meta?.description ?? ''},
    date: new Date()
  })`.trim())}

  return feed.${source.type}()
})`.trimStart(),
          write: true // debug
        })

        addServerHandler({
          route: source.path,
          handler: dst
        })
      })
NozomuIkuta commented 1 year ago

Another point about which I want to clarify is that, since Nuxt 3 modules are all what is called build modules in Nuxt 2, runtime code that they create can't refer to variables passed to module function itself. Then, there is no safe way to support this modules' create option which is a function, is it? Using toString method on the function may result in unexpected behavior.

danielroe commented 1 year ago

You can get each generated route via the prerender:generate Nitro hook. You could use that to add them to an array/Set which you then use in nitro server route. (Don't add this route with addTemplate but use the nitro.virtual vfs as the final Nitro build will happen 'after' the prerendering step.)

You're right that we advise against including runtime code in nuxt.config. Instead, I would recommend users configure this within their app.config file. You can add the typings in the module for an object with feed key so they get type support.