Nikolaj Have

Simple Markdown-based Laravel blog

Fun little summer holiday project I did while spending a peaceful week in the wonderful Odsherred.

While staring up in the blue (okay, mostly gray) sky, I was wondering: How would you make a simple Laravel website based on Markdown content?

Of course, this has been done a billion times before – and a million times in Laravel.

But zero times by me. So here goes:

Initial thoughts 🤔

No GUI interface, no CMS crud interface for creating content
None of that, please!

Therefore: No rich text editor - just plain Markdown support
However, rich text preview is reluctantly allowed 😁

No database, just static index and content files
Yeah, I might regret this later.

Some kind of folder / menu / category for posts
In order to have different sections, like "blog", "projects", "random-thoughts", etc.

Enable comments on selected pages
Using a third-party service, something like Disqus.

Why a static website?

By "static website" I don't mean flat HTML-files, but merely a website without a database. You have your content in files and your files in your VCS.

Having content in your VCS is actually nice for a number of reasons (and probably bad for more, you tell me).

But it really comes down to that I wanted a website that's easy to update - and easy for me means not leaving my IDE environment.

What VIM really does to you

I was a VI-king (a term I read lately, meaning a passionate VIM user 😬) for a decade and a half - and only left this brilliant editor for JetBrains / PHPStorm, when I was happy with the IdeaVim plugin. What VIM really does to you - and I think you have to be a VIM user to fully understand this - is break your patience when typing in a non-VIM editor. It's a pain! And any web form in therefore a pain when typing anything longer than a search term.

Anyways, on top of this you get a lot of niceness from a static website:

Also - no database = no database content to backup. 👌

Workflow by Wishful Thinking

This is how I want my workflow to be, when creating a new post:

1. Use an Artisan command to create a new page entity

Do something like php artisan blog:new

2. Enter page attributes directly from the CLI

Enter title, let the system create a slug based on this, approve or edit it.

Also - enter page section (blog, projects, ...).

3. Start typing

The Artisan command stores the page meta data and creates a new file for the blog post. Yes, one file for each page. Open this file and you're on your way.

4. Deploy your new page

And that's it.

Index + Blog post meta data

I was actually considering - for a brief moment - to put the meta data in the top of the markdown file - in Yaml format. It would be nice to have it all in one file.

However, how to make a section index page - like a list of blog post? Read all files from disc and parse the content? Or process the files and create another index file. Hmmm, nah.

On top of this, I soon realized that the Markdown format actually do not have an official way to comment things out (you can do something like [comment]: <> (this is commented out)) - so if I did put the meta data in the blog post file, I would have to read the content and process the Yaml data inside the comments?

Another way would be put a Yaml section in the top - end it with ---\n. This would be easier to parse, but is not hidden from the Markdown and would therefore have to be removed.

I knew that I had to do this some other way.

I decided to store the page meta data in a separate Yaml file.

Meta data attributes:

In Yaml format - using the slug as key.

hello-world:
    title: 'Hello World!'
    section: blog
    created_at: '2021-07-04'

Performance

How well will this perform without a database? Reading and parsing Yaml and Markdown files on the fly? Even when the view files are cached? Probably not great. Probably not that bad either.

Mental note for future bored me: Test static index with 1000 file entries

File folder structure

I wanted to organize the posts into section folders:

posts/
    projects/
        laravel-markdown-blog.md
        ...
    blog/
        my-first-post.md
        ...
    about/
        _index.md

Looking at this, I decided the create an index view file for each folder, to have a place to add additional content for the pages.

posts/
    projects/
        _index.md
        laravel-markdown-blog.md
        ...
    blog/
        _index.md
        my-first-post.md
        ...
    about
        _index.md

Then I would be able to support slugs like /projects/laravel-markdown-blog, /blog/my-first-post and /about.

However, I wanted to blog post slugs to be more simple, so decided to construct my routes to support /my-first-post even when this post in is the blog folder.

File naming

I knew from the start that I wanted to name the files with the slug and only the slug. It's quite common from similar projects to name a content file something like YYYY-MM-DD-slug-goes-here.md. But why, when the timestamp is already in the index?

Templating

Where to put the blog post files?

Right here:

resources/views/posts

But blog posts are not Blade views?

Nope, but now they are! 😉

Converting Markdown to HTML

Was considering thephpleague/commonmark and erusev/parsedown, but ended up with graham-campbell/markdown.

This enables you to parse Markdown:

The Markdown parsing is then automatically executed when running the view helper function:

return view('posts.blog.hello-world', [
    // View data
]);

Implementation

Use Laravel

Of course, what else?

Use Tailwind CSS

Yes. I do have a crush on this CSS framework <3

A Page repository

For handling and retrieving data from the index file.

A Page model and controller

I will have to overwrite the basic model methods like find(), make() and all().

Challenges

No CSS class support in Markdown

Ah, CSS class attributes are - of course - not supported by Markdown (and nope, not going down this Hackey Alley) . Inline HTML in Markdown in possible, but really not what I want.

But Tailwind is a utility-first framework, so what to do?

I ended up adding @apply styles for the blog post HTML elements, which made it less Tailwind-ish, but still nicer than plain CSS.

Final notes

So let's call this version 0.1 beta. In future updates I plan to:

And there is more on the wishlist.

Other posts

2021-10-02   Configure auto-deploy with Github webhooks
Laravel Markdown
Show comments
Published 26th of Jul, 2021
Content updated 10 months ago