Hello.

I am Paul Kinlan.

A Developer Advocate for Chrome and the Open Web at Google.

I love the web. The web should allow anyone to access any experience that they need without the need for native install or content walled garden.

20 years blogging

Paul Kinlan

Wow! Just realized I've been blogging for over 20 years, starting way back in August 2004 on kinlan.co.uk with Blogger. The journey has taken me through Posterous and landed me here on paul.kinlan.me with Hugo (and maybe Jekyll at some point). Sure, there's some cringe-worthy stuff in the archives, but it's my history. And honestly, I wouldn't be where I am today without this little corner of the internet. Huge thanks to Tim Berners-Lee and everyone who's made the web what it is!

Read More

tldr.rocks

Paul Kinlan

tldr.rocks is a simple site that summarizes the sentiment of Hacker News posts.

Read More

Paul Kinlan

I added ActivityPub support to my static Hugo blog hosted on Vercel. It now automatically announces new posts to followers on the Fediverse. Key challenges included implementing the ActivityPub protocol for a static site, handling WebFinger discovery, managing Follow/Unfollow requests, and sending signed HTTP requests. I used Vercel Serverless Functions for dynamic request handling and Firebase Firestore for storing follower data. Check out the code and follow me @paul@paul.kinlan.me to see it in action!

Read More

Simulating Apache mod_include for Vercel

Paul Kinlan

For my Hugo static site hosted on Vercel, I wanted a simple way to include server-side logic, like a copyright notice, without setting up a full backend. I created a function that mimics Apache's mod_include to inject dynamic content. It rewrites HTML requests through a handler that parses files for <!--#include ... --> directives. The file command injects file content, while the virtual command fetches content from the /api directory (like a modern /cgi-bin/). Caching is crucial for performance. Check out the demo and code. A more robust solution like Cloudflare Workers' HTMLRewriter would be ideal, but this works for simple use cases.

Read More

A simple video insertion tool for EditorJS

Paul Kinlan

I've created a simple video plugin for EditorJS, called simple-video, to easily embed videos. It's based on the simple-image plugin and allows for autoplay, mute, and control options. Check out the npm package and GitHub repo for more details!

Read More

Using Web Mentions in a static site (Hugo)

Paul Kinlan

This blog post discusses how to integrate Webmentions into a statically generated website built with Hugo, hosted on Zeit. Static sites lack dynamic features like comments, often relying on third-party solutions. This post explores using Webmentions as a decentralized alternative to services like Disqus. It leverages webmention.io as a hub to handle incoming mentions and pingbacks, validating the source and parsing page content. The integration process involves adding link tags to HTML, incorporating the webmention.io API into the build process, and efficiently mapping mention data to individual files for Hugo templates. Finally, a cron job triggers regular site rebuilds via Zeit's deployment API, ensuring timely updates with new mentions.

Read More

Webmention.app

Paul Kinlan

I've added Webmention support to my blog! I'm excited about Webmentions because they allow decentralized commenting and reactions, unlike Disqus which I'm looking to remove. Sending webmentions involves two parts: the sender and the receiver. I used Remy Sharp's webmention.app tool to simplify the sending process. Integrating it into my Zeit/Hugo blog was super easy - I just installed the package and added a call to the CLI in my build script. Now, whenever I publish a post, it automatically pings any URLs I've linked to.

Read More

Creating a commit with multiple files to Github with JS on the web

Paul Kinlan

I've created a simple UI for my static site and podcast creator that allows me to quickly post new content. It uses Firebase Auth, EditorJS, Octokat.js, and Zeit's Github integration. This post focuses on committing multiple files to Github using Octokat.js. The process involves getting a reference to the repo and the tip of the master branch, creating blobs for each file, creating a new tree with these blobs, and creating a commit that points to the new tree. The code handles authentication, creates blobs for images, audio (if applicable), and markdown content, and then creates the tree and commit. This setup allows me to have a serverless static CMS.

Read More

Editor.js

Paul Kinlan

I've migrated my Hugo blog's editor to Editor.js. It's a block-based editor, unlike classic editors, offering more flexibility and a Medium-like experience. Although I faced some challenges adapting the ES5 code from the NPM distribution (compared to the ES Modules examples), building the UI was relatively straightforward. Check out Editor.js for more details.

Read More

Translating a blog using Google Cloud Translate and Hugo

Paul Kinlan

Inspired by a recent trip to India and the emphasis on local language content, I developed a script to translate my Hugo-based blog using Google Cloud Translate. This script processes markdown files, handles code blocks and pull quotes, and outputs translated versions, expanding the potential reach of my content to non-English speakers. While machine translation isn't perfect, the goal is to improve content discoverability and accessibility for a wider audience. I'll share results as data becomes available.

Read More

Configuring hugo server to serve 'mjs' ES modules

Paul Kinlan

Hugo, by default, doesn't serve .mjs files with the correct MIME type, which is necessary for using ES modules. However, starting with v0.43, you can configure Hugo to serve .mjs files correctly by adding the 'mjs' suffix to the 'text/javascript' media type in your config file. This allows for proper local testing of ES modules, although hosting considerations might differ.

Read More

My blog's Service Worker and Caching Strategy

Paul Kinlan

This blog post discusses the implementation of a Service Worker for my blog, with a focus on the caching strategy. I've chosen a "Stale While Revalidate" approach, which prioritizes speed and resilience. The Service Worker intercepts network requests and serves cached content if available, while simultaneously fetching updated content in the background. This ensures the latest version is available after one refresh. The post also details the requirements considered when choosing this strategy, including development simplicity and compatibility with the existing hosting setup (Hugo and NGINX). The provided JavaScript code snippet demonstrates the Service Worker implementation.

Read More

Goodbye Jekyll, Hello Hugo

Paul Kinlan

Ruby frustrations and performance have frustrated me for a long time. Experimented with Hugo and ported blog in about 3 hours

Read More

paul.kinlan.me

Paul Kinlan

This blog

Read More