next.jsvercel

Embed current build time into humans.txt file with nextjs


Placing a humans.txt file into nextjs' /public folder works fine for a static file.

However I'd like to annotate the file with the date of the latest page build (when next build is called). So I created pages/humans.txt.tsx which renders a string that also contains the build time static date:

export default function Test({ buildTime }) {
  return `Hello ${buildTime}`
}

export async function getStaticProps() {
  return {
    props: {
      buildTime: new Date().toISOString()
    }
  }
}

I tried to customize pages/_document.js but even with everything stripped down (for testing) it still renders the doctype and one div with my text in it.

class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext) {
    ctx.renderPage = (props) => {
      return {
        html: "text",
        head: null,
      }
    }
    // Run the parent `getInitialProps`, it now includes the custom `renderPage`
    const initialProps = await Document.getInitialProps(ctx)

    return initialProps
  }
  render() {
    return <Main/>
  }
}

Output:

<!DOCTYPE html><div id="__next">text</div>

Returning just string from my documents render instead of <Main/> still renders the doctype and also causes a warning, since render should return an Element.

So I am out of ideas and might resort to using a prebuild script in package.json prebuild: sed ./pages/humans.txt... to replace a marker in the file with the system date and pipe it to public/humans.txt.


Solution

  • Here is an interesting runtime alternative:

    Rewriting /humans.txt to /api/humans

    You can use the following rule:

    // next.config.js
    module.exports = {
      async rewrites() {
        return [
          {
            source: '/humans.txt',
            destination: '/api/humans',
          },
        ]
      },
    }
    

    Check the Rewrites docs here

    Writing /api/humans

    Now you can use any response in your API. However, make sure you are caching it:

    // /pages/api/humans.js
    export default function handler(req, res) {
      res.setHeader('Cache-control', 's-maxage=6000, stale-while-revalidate=30')
      res.setHeader('Content-type', 'text/plain')
      res.status(200).end('example')
    }
    

    Check the API routes docs here