Skip to content

Automating Social Media Posts for Your Blog Deployed on Vercel

by David Yates

If there’s one thing that I feel I have to eliminate from my writing, its the friction involved in publishing work. The longer I “sit on” an idea, the more likely I am to put it back in the drawer with all my other ideas. With this i n mind I dedicate quite a bit of time to removing as much friction as Ican from any processes that need to me to share my work. I’ve already written about autmating post creation usni some scripting, and recently I’ve been using a simple bash script to help me post random musings to Mastodon without leaving the command line. I figured I would take this a step further and see if I could automate letting people know when I’ve written about something. So here we go.

I did originally intend to use serverless functions for this before quickly realsing it was massively overkill. All thats required is to write a simple script, store your access token in the right place and have it form part of your build step.

Here’s the basic steps:

  1. Go create your access token for whichever social media platform you’re wanting to use, I’m using Mastodon.
  2. Store that ACCESS_TOKEN as an environment variable in Vercel.
  3. Create a little script and put it at your proejct root, here’s mine:
const fs = require("fs").promises;
const path = require("path");
const yaml = require("js-yaml");
async function getLatestBlogPost() {
  const blogDir = "src/content/blog";
  const files = await fs.readdir(blogDir);
  const sortedFiles = files.sort((a, b) => b.localeCompare(a));
  const latestFile = sortedFiles[0];
  return path.join(blogDir, latestFile);
}

function removeDateFromBlogTitle(title) {
  const datePattern = /^\d{4}-\d{2}-\d{2}-/;

  const newTitle = title.replace(datePattern, "");

  return newTitle;
}

async function readYamlMetadata(blogPath) {
  const content = await fs.readFile(blogPath, "utf-8");
  const yamlSection = content.split("---")[1];
  const metadata = yaml.load(yamlSection);
  return metadata;
}

async function main() {
  const shouldPost = true;

  if (shouldPost) {
    const latestBlogPath = await getLatestBlogPost();
    const metadata = await readYamlMetadata(latestBlogPath);

    const blogPostPath = latestBlogPath.split("/").slice(3).join("/");
    const newTitle = removeDateFromBlogTitle(blogPostPath);
    const uriPath = newTitle.replace(".md", "");

    const message = `${metadata.description} Read more at https://oneforthecode.com/posts/${uriPath}`;

    const ACCESS_TOKEN = process.env.ACCESS_TOKEN;
    const INSTANCE_URL = "https://mastodon.social";
    const API_ENDPOINT = `${INSTANCE_URL}/api/v1/statuses`;

    try {
      const response = await fetch(API_ENDPOINT, {
        method: "POST",
        headers: {
          Authorization: `Bearer ${ACCESS_TOKEN}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ status: message }),
      });

      if (response.status === 200) {
        console.log("Post successful.");
      } else {
        console.log(`Post failed. HTTP Status Code: ${response.status}`);
      }
    } catch (error) {
      console.error("An error occurred:", error);
    }
  } else {
    console.log("Not posting to Mastodon.");
  }
}

main();
  1. Add the script to the build bit of your package.json like this:
"build": "astro build && jampack ./dist && node ./postToMastodon.js",

And that’s all there is to it. Test it locally if you like before publishing. I’ve added a manual bit of code in there for switching wether to POST or not, I might look into something fancier another day.

All Posts