Adding Static Markdown Pages to our NextJS Hive Front-End

avatar

NextJS Hive Front-End

So far in our custom Hive front-end, all the content for the website has come from the posts we have published on the Hive blockchain.

A website is more than just fresh blog articles, though. We need to orient the visitor to who we are and why they should care about our content, and that means having a static "About Us" page that rarely, if ever, changes. In addition, if we have products or services, or perhaps a resources/downloads page, then that content would also be relatively static.

While technically we could post those on the Hive blockchain, perhaps setting to not have a payout, that wouldn't endear us to our fellow Hive family because it is not interesting content when it appears in our follower's feeds.

Therefore I wrote about creating markdown content and posting that content to the IPFS in Python. This essentially becomes a web-accessible text file that we can then call back and use on our website.

One of the great things about using NextJS as our Hive front end means it doesn't matter if pulling this content out of the IPFS takes a while, NextJS is all about constructing fast-loading pages based on whatever API or backend process you throw at it. As our static pages won't change very often, this will be extremely optimized by the time viewers click on them.

The Process

There are a few steps that we need to take care of and be aware of:

  1. We need to pull the content from IPFS. Fortunately for us, while we can use an IPFS node running on our server and craft a command-line command, the IPFS people have made nice and convenient web front-end gateways to IPFS data that we can simply do an HTTPS "GET" to retrieve if we know the hash key for the file we want.
  2. Next we need to convert that markdown markup to HTML markup. The Markdown syntax is pretty simple, especially as implemented on Hive, so we could do a regular expression/string manipulation dance and it mostly works, but other developers have already done the heavy lifting for us, saving us the bother (and the bugs!)
  3. This content now needs to be passed to our NextJS application. Unlike, say, Python or PHP, we can't just print() the HTML to the output stream as NextJS is built upon React.
  4. Finally we need to apply at least minimal CSS styling and meta so the freshly generated page consistently fits into our website and works naturally as the visitor navigates around.

Grabbing the Page Content

Rather than hard-code the hash key of our content in the interplanetary file system, I decided I would set an environment variable. This means you can have different content in your development/staging/production environments, and also it means if anyone wants to take this code and run their own Hive front end it is easy for them to customize to their own needs.

var about_content = process.env.ABOUT_CONTENT;

After getting the correct file key, we concatenate that to our IPFS gateway URL:

var about_url = "https://ipfs.io/ipfs/"+about_content;

This means if we find out that a specific URL is unreliable we can easily find it and change it in our code.

Now we pull the text content into a variable (using await because the HTTP get is asynchronous).

 var res = await fetch(about_url);
 const contents = await res.text();

We have the text but it is in Markdown format, so we use Remarkable to convert that markdown syntax into HTML markup:

var md = new Remarkable();
const article = md.render(contents);

All that is left is to deliver our HTML to the ServerSide Props, giving our React components access to our new "Article":

export const getServerSideProps = async (context) => {
  return {
   props: {
   article,
  },
 }

}

Rendering the Page

We can't just pump out our HTML - in fact, the framework really does NOT want us to do that.

It seems the only option available to us is the scary-sounding dangerouslySetInnerHTML.

As mentioned earlier, that is not enough - we need our page to work in the context of our website, and that means having consistent styling and meta.

For styles we can bring those in at the top of our code:

import layoutStyles from '../styles/Layout.module.css'
import articleStyles from '../styles/Article.module.css'

But Meta is a little different. If we want to set the HTML Title, where do we do that? Well, in my solution, I have a Meta component so we can set the title easily like so:

const about = ({ article }) => {

  return (
    <div>
      <Meta title='About' />
      <div dangerouslySetInnerHTML={{ __html: article }}></div>
    </div>
  )
}

Our Meta component looks like this:

import Head from 'next/head'

const Meta = ({ title, keywords, description }) => {
  return (
    <Head>
      <meta name='viewport' content='width=device-width, initial-scale=1' />
      <meta name='keywords' content={keywords} />
      <meta name='description' content={description} />
      <meta charSet='utf-8' />
      <link rel='icon' href='/favicon.ico' />
      <title>{title}</title>
    </Head>
  )
}

Meta.defaultProps = {
  title: 'Hive Blog',
  keywords: 'linux, programming',
  description: 'My Hive-Based Blog',
}

export default Meta

And that is it!

Is it easier than hard-coding our static pages? It might not seem so, until your site is deployed and you are told about a typo, or you just need to keep the bio information up to date. Using this system means you don't need to touch the code at all, no need to deploy the site again to staging and then production, just create your markdown and set the environment variable!

Also, as mentioned earlier, I want as many people as possible to be able to reuse this front-end code without having to do any programming if they don't want to.

Full Code

import Meta from '../components/Meta'
import Link from 'next/link'
import { Remarkable } from 'remarkable';
import layoutStyles from '../styles/Layout.module.css'
import articleStyles from '../styles/Article.module.css'

export const getServerSideProps = async (context) => {
  var md = new Remarkable();
  var about_content = process.env.ABOUT_CONTENT;
  console.log(process.env.ABOUT_CONTENT);
  var about_url = "https://ipfs.io/ipfs/"+about_content;
  console.log(about_url);
  var res = await fetch(about_url);
  const contents = await res.text();
  const article = md.render(contents);

  return {
    props: {
      article,
    },
  }

}


const about = ({ article }) => {

  return (
    <div>
      <Meta title='About' />
      <div dangerouslySetInnerHTML={{ __html: article }}></div>
    </div>
  )
}

export default about

Posted with STEMGeeks



0
0
0.000
3 comments
avatar

Using IPFS is an interesting way to keep things decentralized.

0
0
0.000
avatar

Using IPFS is an interesting way to keep things decentralized.

and it can be used for images and downloads too so hopefully regular folks who want to use my front-end as a foundation for their site won't need to need to learn the underlying code or figure out Git/version control ...

0
0
0.000
avatar

Users don't want to code. I think, as geeks, it is our job to make things very simple for users. It's the job of any good business or producer of any sort, imo.

0
0
0.000