This is Part 3 in a series where I describe how this site is built and hosted. If you haven't read Parts 1 or 2 yet, I encourage you to check them out here:
Part 1 - How I Built This Site
This will likely be the final part of this series. There were a couple things that I didn't write about in the first 2 parts that I thought were interesting and wanted to cover. Those being:
Analytics
Livewire SPA Mode
Filament
For site analytics, I use Umami. It's a great option for self-hosted analytics. It's open source and receives frequent updates. And, while it's definitely not as full-fledged as Google Analytics, it offers all of the most useful analytics features along with flexibility for customization. The other great thing - it's easy to get an instance up and running in a containerized environment. Below is the (mostly stock) docker-compose.yml
file I'm using for my instance:
services:
umami:
image: ghcr.io/umami-software/umami:mysql-latest
ports:
- 3100:3000
environment:
DATABASE_URL: ${DATABASE_URL}
DATABASE_TYPE: mysql
APP_SECRET: nOtMyAcTuAlSeCrEtVaLuE
restart: always
healthcheck:
test:
- CMD-SHELL
- curl http://localhost:3000/api/heartbeat
interval: 5s
timeout: 5s
retries: 5
networks: {}
Umami makes it incredibly simple to setup analytics for multiple sites. I'm able to use a single Umami instance to track analytics for all of my sites. For each site, Umami generates a unique script tag for you - just drop it into the <head>
of your DOM and you're good to go.
This site is running the latest versions of Laravel (v11), Livewire (v3), AlpineJS (v3), and Tailwind (v3). With Livewire v3, the wire:navigate
feature was introduced, which gives Livewire-based sites a single-page-application (SPA) feeling. It does this by preventing full-page loads when navigating between pages on a site. Instead, Livewire intercepts the request, handles it in the background, and instead of reloading an entire page, Livewire loads only the elements that differ between the 2 pages. This results in a much pfaster navigation, and reduces visual jitter.
Finally, to manage the basic content for the site, I'm using Filament (v3). Filament's original goal was to serve as an easy-to-use admin panel for Laravel, built in the TALL stack. It offered some great advantages in customization over the other Laravel admin panels with great sensible defaults out-of-the-box. However, with version 3, the package expanded from being an all-inclusive admin panel to also being suitable for the frontend of your web apps. It stands as one of the many highlights among community-maintained packages in the Laravel ecosystem. I may write a separate post (or several posts, even) about Filament. But, I'd like to at least mention one of the Filament packages that I'm using on this site: filament-tiptap-editor by Adam Weston. This package implements the TipTap Editor into a Filament form field, allowing you to write very extensible rich-text articles in Filament. It handles code blocks (with syntax highlighting), rich text formatting, media, etc. all with very little configuration needed. I'm using it to write all of the blog posts on this site, and it's been fantastic.
One other tidbit I'll mention here - the background image on the site. You'll notice as you navigate around the site, the background image stays the same. However, if you refresh a page on the site, you'll notice the background image changes. That is because the background image is uniquely generated for each full-page visit to the site. It's currently setup to generate an svg image with 100 vertical and 100 horizontal lines of various opacity and shade, depending on whether the visitor is using light mode or dark mode. It's a pretty cool feature that I added at the last minute, and thought I'd share it here in case you haven't noticed it.
Anywho, that concludes this 3-part series on the basics of the site. If you have any questions, or would like contact me, you can find my contact information or submit a contact form submission on my Contact Page. Thanks for reading!