loteoo / hyperstatic-starter

Starter project for the hyperapp site generator
https://hyperstatic-starter.netlify.app/
MIT License
18 stars 3 forks source link

Example of external data using StaticFetch #8

Closed mdings closed 4 years ago

mdings commented 4 years ago

Would you mind adding an example in the repo of a site with multiple pages that fetches external data for each page using StaticFetch?

What I'm actually trying to achieve is to load in a couple of external markdown files and have them being rendered by the same template. So I can still have multiple pages without having to create an entry in the routes.js file for every single page. Would that even be possible at all?

Also, I have a bit of a hard time wrapping my head around the workings of that. I mean, whenever I fetch data and add that to the window.staticData object, the data is cached when running a production build. That's cool, but what surprises me is that the call to the actual API is then not being made anymore. So behind the scenes there must be something going on with popping the subscriptions array or something. Could you elaborate a bit on this as well, since that might affect the way I have to build my website with multiple other subscriptions?

mdings commented 4 years ago

I think I've got this figured out myself.

So whenever a page loads I'm fetching content from an external markdown file with an effect like this:

const effect = a => b => [a, b]

const FetchContent = effect(async (dispatch, url = window.location.pathname) => {
    if (url == '/' || url.length < 1) return
    url = url.replace(/\/+$/, "") // remove trailing slashes
    const pageContent = await fetch(`${url}.md`).then(response => response.text())
    if (pageContent) {
        if (window.navigator.userAgent === 'puppeteer') {
            window.staticData = {
                ...window.staticData,
                [url]: pageContent
            }
        }
        dispatch(SetContent, pageContent)
    }
})

const SetContent = (state, content) => {
    state.pageContent = content
    return {...state}
}

While in development I can see the requests being made to the markdown files. In production mode (or after a build), the data is being loaded through an external JSON-file. This allows me to build multiple pages with external static content while keeping the same template.

Then, in that template I can render the html using a markdown renderer. I am using https://github.com/developit/snarkdown in this particular case:

<!-- Note: we will probably have to add a XSS-protection layer!  -->
<div innerHTML={snarkdown(state.pageContent)}></div>

The only gotcha here is that Parcel doesn't process markdown files by default, so they won't be accessible from the development server. Therefore I installed a plugin which copies and watches the markdown files (https://www.npmjs.com/package/parcel-plugin-static-files-copy), with the following configuration in package.json. Basically I'm keeping all of my static content inside markdown files in the content-folder, which then gets processed by the plugin.

"staticFiles": {
    "staticPath": "./src/content",
    "watcherGlob": "**/*.md"
  }

What do you think about this approach @loteoo?