Deploying

Gonna keep this one relatively short. I'll highlight what was wrong with my first attempt and then dive into how I resolved the issue.

First Attempt

Setting up Vercel was as easy as "New Project" and it recognizing my repo as a Remix.run project. Below is the very first thing I saw when I visited my Vercel site!

Error: ENOENT: no such file or directory, scandir '/var/task/output/server/pages/blog'

So I dug around the Remix docs & Discord server. Long story short, Vercel only uses the build output. My blog folder is not a part of that build output.

Adding GitHub

To get around the limitation of not having access to my content files, I'll use the GitHub API to read my content. I added app/util/github.server.ts to manage calls to GitHub.

import { Octokit } from "@octokit/rest";
import invariant from "tiny-invariant";

const octokit = new Octokit({
  auth: process.env.GITHUB_TOKEN
});

export const getBlogPostDirFiles = async () => {
  const { data } = await octokit.repos.getContent({
    owner: "vivalldi",
    repo: "vivalldi.dev",
    path: "blog"
  });

  invariant(Array.isArray(data), "Expected data to be an array");

  return await Promise.all(
    data.map(async fileData => {
      invariant(fileData.download_url, "Download URL is missing");
      let resp = await fetch(fileData.download_url);
      let content = await resp.text();

      return {
        ...fileData,
        content
      };
    })
  );
};

export const getBlogPostFile = async (slug: string) => {
  const { data } = await octokit.repos.getContent({
    owner: "vivalldi",
    repo: "vivalldi.dev",
    path: `blog/${slug}.md`
  });

  invariant(!Array.isArray(data), "Response malformed");
  invariant("content" in data, "Response not a file");

  return Buffer.from(data.content, "base64").toString("utf8");
};

I also moved app/blog.util.ts to app/util/blog.ts. This just helps tidy things up.

The notable changes to blog.ts are that I call getBlogPostFile to get the post data rather than fs. The same goes for listing blog posts.