diff options
| author | Brandon C. Irizarry <brandon.irizarry@gmail.com> | 2026-03-08 19:16:04 -0400 |
|---|---|---|
| committer | Brandon C. Irizarry <brandon.irizarry@gmail.com> | 2026-03-08 19:16:04 -0400 |
| commit | cdecb8191a791b8db66effe61de16cb3e3904238 (patch) | |
| tree | 815c42e49e87ab89b103cf876437cc985f078675 /posts | |
| parent | c4af1098ffebffa02d3a055d7570193acd77985d (diff) | |
Reorder posts according to new publishing algorithm
Diffstat (limited to 'posts')
| -rw-r--r-- | posts/adding-cgit-subdomain-to-personal-site.md | 195 | ||||
| -rw-r--r-- | posts/apple-time.md | 21 | ||||
| -rw-r--r-- | posts/making-cgit-go-gettable.md | 101 | ||||
| -rw-r--r-- | posts/smoothing-over-more-markdown-pain-points.md | 73 | ||||
| -rw-r--r-- | posts/understanding-pratt-parsing.md | 155 | ||||
| -rw-r--r-- | posts/writing-my-blog-with-eleventy.md | 90 |
6 files changed, 635 insertions, 0 deletions
diff --git a/posts/adding-cgit-subdomain-to-personal-site.md b/posts/adding-cgit-subdomain-to-personal-site.md new file mode 100644 index 0000000..c62fde8 --- /dev/null +++ b/posts/adding-cgit-subdomain-to-personal-site.md @@ -0,0 +1,195 @@ ++++ +title = "Adding a CGit Subdomain To My Site" +tags = ["linux", "nginx", "certbot", "cgit"] +summary = "Setting up CGit on my VPS." +date = 2026-03-06 ++++ + +# Motivation + +To update the content of my blog, I have to do something of a +dance. My blog's content started out life as a subdirectory of my SSG +project, but now lives in its own separate Git repo. This is super +convenient since I now can host my blog wherever I want on my VPS's +filesystem, for example in a folder called `brandons_blog`. So right +now what I'm doing is this: + +1. Commit all changes. +2. Push the changes to GitHub, where it's currently hosted in a + somewhat centralized manner. +3. Log in via SSH into my VPS. +4. Perform a `cd` into the `brandons_blog` directory, and run `git + pull`. + +However, I thought, "wouldn't it be nice if I could push **directly** +to the VPS repo?" And so I started working on that idea in the obvious +manner: add the VPS repo as a remote, such that I would be pushing to +`vps/main` alongside of `origin/main` (where `origin` points to +GitHub). + +It turns out that this alone is a shade more complicated that it would +seem: I had to first add a new `git` user (see [this tutorial](https://landchad.net/git/)), +and then adjust my SSH configuration appropriately to allow for this +pseudo-user to log in via SSH (since I would be pushing into a +directory now owned by it.) + +I quickly learned, to my dismay, that I couldn't push to the VPS +remote if it's not a bare repo. A bare repo is one initialized with +`git init --bare`, so that it doesn't have a working directory +populated with files. However, the buildablog server expects to see a +working directory with blog files (not just blobs, for example), so +this doesn't solve my problem. + +# Cgit + +What I ended up doing in the end didn't solve this problem, but it +ended up becoming an interesting rabbit hole in its own right. + +I ended up adding the Cgit web interface to my site, available via +<https://git.brandonirizarry.xyz>. I checked out a [tutorial](https://landchad.net/cgit/) on +how to do it, but their suggested Nginx setup was off in some +parts. + +After a ton of false starts, I ended up doing slightly different. Note +that this assumes that you've already followed the aforementioned +tutorial on setting up your `git` user and its home directory. As a +quick addon to that, I suggest adjusting the permissions for the +`/var/git` directory to 775 (I had initially found they were set to +770.) This allows the Cgit web interface to actually read and display +your hosted repos, which is after all the point. + +Here's what I did. I'm phrasing these in the imperative mood since it +reads better than beginning everything with "I" + past-tense, and the +steps themselves are also suitable as a potential HOWTO for my future +self: + +1. Add two new *external records* for `git.brandonirizarry.xyz` to my + site's DNS configuration over on Epik: the A (IPv4) and AAAA (IPv6) + records, per usual if you're already somewhat familiar with this + thing. + +2. Start out by adding the Nginx configuration of the `http` version + of the site. Not only does this make adding the TLS certificate + later on painless, you can immediately verify that your new + subdomain is, in fact, being hosted. Add the following server block + to your published Nginx configuration, and then reload Nginx + (e.g. `sudo systemctl restart nginx.service`): + +```nginx +server { + listen 80; + listen [::]:80; + + # Replace this with your actual site. + server_name git.example.org; + + root /usr/share/cgit ; + try_files $uri @cgit ; + + location ~ /.+/(info/refs|git-upload-pack) { + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend; + fastcgi_param PATH_INFO $uri; + fastcgi_param GIT_HTTP_EXPORT_ALL 1; + + # This part assumes your git user's home directory is /var/git. + fastcgi_param GIT_PROJECT_ROOT /var/git; + fastcgi_param HOME /var/git; + fastcgi_pass unix:/run/fcgiwrap.socket; + } + + location @cgit { + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi; + fastcgi_param PATH_INFO $uri; + fastcgi_param QUERY_STRING $args; + fastcgi_param HTTP_HOST $server_name; + fastcgi_pass unix:/run/fcgiwrap.socket; + } +} +``` + +3. Add a TLS certificate for your subdomain. I admit that I took a + somewhat nonlinear path in achieving my setup, but this should be + as simple as running `sudo certbot --nginx`, and then selecting + your subdomain from the menu options. Here I'm assuming you've + already gotten a certificate for your main site, hence you need a + certificate only for your new subdomain. + +From there you shouldn't even have to restart Nginx: you should see +that your subdomain is available over `https`. + +# Five Strikes and You're Out + +I learned, through banging my head against various misconfigurations +(both from the DNS and Nginx sides), that Let's Encrypt (what Certbot +uses to issue the certificate) [imposes a rate limit](https://letsencrypt.org/docs/rate-limits/#authorization-failures-per-identifier-per-account) on +certificate issues per identifier (five per hour), which doesn't +forgive botched attempts at certificate registration. The solution +here is to run Certbot with the `--test-cert` flag, which uses Let's +Encrypt's staging area, which has a much more forgiving rate limit. + +In digging a bit through the Let's Encrypt [forums](https://community.letsencrypt.org/), I learned +about two super helpful sites for debugging DNS and certificate +issues: + +1. <https://letsdebug.net> + + Super helpful for figuring out issues with bad certificates. + +2. <https://dnsviz.net> + + For debugging a site's DNS config, which I was messing up since I + wasn't sure in the beginning how to properly add a subdomain to my + DNS records (somewhat confusingly, Epik places the word + "subdomain" alongside the CNAME section, making me think CNAME had + something to do with it, which it doesn't.) + +# A Ghost in the Machine? + +I finally managed to [host](https://git.brandonirizarry.xyz) my Cgit dashboard on my site, which +currently contains only my blog repo. I even managed to share the link +with a friend of mine, who was successfully able to view it from their +end. + +However, when going through some exercises in *The Go Programming +Language* (a story for another time), I happened to cavalierly make a +GET request to that subdomain, which then reported a TLS error. In my +mind this seemed somewhat bonkers, since, after all, everything was +already up and running, no? So late that evening I had to jump back +onto the VPS and do some bespoke troubleshooting. + +It looked like there were some redundant server blocks in my Nginx +config file that were added while I was throwing everything and the +kitchen sink at getting a valid TLS certificate. So what I did in the +end was remove everything Certbot had added concerning my `git` +subdomain, essentially reverting back to just the server block shown +just above, and repeating those exact steps — including first +verifying service over `http`. This part of the process for me was the +most satisfying, since it proves that the mere act of publishing a +website on the Web is, at its core, not all that difficult. One thing +different this time though was that, per the options Cerbot presents +you, it sufficed to reinstall the existing certificate, as opposed to +applying for a new one.) + +After that, everything was in order! I even checked the site the next +morning just to make sure it had stayed that way. To date, everything +looks good. + +# In the End... + +In the end, I didn't actually solve my initial problem, but still went +down an interesting rabbit hole, and now have a convenient tool at my +disposal — my own poor-man's GitHub — for personal use. For now, I may +well only use it for throwaway Go packages, in case I don't feel like +using workspaces. + + + + + + + + + + diff --git a/posts/apple-time.md b/posts/apple-time.md new file mode 100644 index 0000000..e012fc5 --- /dev/null +++ b/posts/apple-time.md @@ -0,0 +1,21 @@ ++++ +title = "My first post" +summary = "Stub post for buildablog" ++++ + +# Roses are red + +Violets are blue, etc. +<br> +```go +package main + +import "fmt" + +func main() { + fmt.Println("Hello world!") +} +``` +<br> + +[This is a link](https://example.com) diff --git a/posts/making-cgit-go-gettable.md b/posts/making-cgit-go-gettable.md new file mode 100644 index 0000000..0c197ca --- /dev/null +++ b/posts/making-cgit-go-gettable.md @@ -0,0 +1,101 @@ ++++ +title = "Making Cgit Repos Installable as Go Packages " +summary = "Steps I took to configure my private Cgit repo hub to host Go packages." +tags = ["nginx", "cgit", "go"] +date = 2026-03-07 ++++ + +# Putting my private Git server to good use + +In my quest to learn the real ins and outs of Go by going through *The +Go Programming Language*, I decided to use my newly minted private +repo [hub](https://git.brandonirizarry.xyz) to store exercises from the book as packages I can reuse +for later exercises. For example, I decided to make the lissajous +example from Chapter 1 into a separate installable [package](https://git.brandonirizarry.xyz/lissajous). The +lissajous package is used to create a GIF of a [Lissajous curve](https://en.wikipedia.org/wiki/Lissajous_curve), +which was a staple visual effect in old sci-fi movies. + +However, simply "go-getting" from the repo's URL, as you would in the +case of GitHub, isn't that simple. There were multiple hiccups along +the way which I had to overcome. What follows is my best attempt to +piece together what I did to finally enable Go package installation +from my private Git server. Hopefully this account will serve two +purposes: + +1. Set people straight who are looking for answers to this same + question. + +2. Serve as a reference for my future self in case I have to do this + again. + +# Steps + +## Inject the appropriate HTML `meta` tag from Nginx + +This [excellent](https://anirudh.fi/go-get-cgit ) blog post by Anirudh +Oppiliappan set me on the right path for fixing an error I encountered +early on involving a missing `go-import` something-or-other: + + +I ended up putting the `sub_filter` stuff inside the `location @cgit` +block: + +```nginx + location @cgit { + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi; + fastcgi_param PATH_INFO $uri; + fastcgi_param QUERY_STRING $args; + fastcgi_param HTTP_HOST $server_name; + fastcgi_pass unix:/run/fcgiwrap.socket; + + # Make our repos go-gettable. + sub_filter '</head>' + '<meta name="go-import" content="$host$uri git https://$host$uri"></head>'; + + sub_filter_once on ; + } +``` + +Remembering the semicolons here is important. You can always use `sudo +nginx -t` to test whether your current config is valid. + + +## Configure Git to use SSH for the Git server + +Add this block to your home directory's `.gitconfig` file, making the +appropriate substitution for "example.com": + +```ini +[url "git@example.com:"] + insteadOf = https://git.example.com/ +``` + +Alternatively, you can issue the equivalent command line invocation: + +``` +git config --global url."git@example.com".insteadOf "https://git.example.com/" +``` + +Now, whenever you invoke `go get`, you'll be prompted for your SSH +password. + +Note that, in this case, the `git` in `git@example.com` refers to the +Linux *user* on your remote server that owns the directory containing +all your Git repos. This syntax mirrors the one used when logging into +the same server via SSH, viz. `ssh git@example.com`. + +## Set GOPRIVATE (optional?) + +I'm not sure I need to set this in my case, since AFAICT this has more +to do with close-sourcing code, which isn't my intention here. But I +threw it in just in case. + +Since I want **all** my repos to be potentially installable as Go +packages for now, so I use a glob to indicate that: + +`go env -w GOPRIVATE=git.brandonirizarry.xyz/*` + +Initially, I had set `GOPRIVATE` to point to the `lissajous` repo +only, though this glob technique should work also (and be way easier +to maintain.) diff --git a/posts/smoothing-over-more-markdown-pain-points.md b/posts/smoothing-over-more-markdown-pain-points.md new file mode 100644 index 0000000..d9432ac --- /dev/null +++ b/posts/smoothing-over-more-markdown-pain-points.md @@ -0,0 +1,73 @@ ++++ +title = "Smoothing Over More Markdown Pain Points" +tags = ["blogging", "emacs"] +date = 2025-12-05 + +summary = """ + +A post from my old blog about a small Elisp helper library I wrote for \ +generating a table of contents for a Markdown file. + +""" + ++++ + +# I Couldn't Keep It Together + +As I go about editing these blogs as Markdown buffers inside Emacs, +I've been running into a snag of sorts. Previously, I had been +exporting Org to Markdown one way or another. I observed how the +Markdown output inserts an anchor tag above a given section as a way +to link to it from the table of contents. I decided to continue this +practice in my now hand-wrought Markdown. However, manually keeping +the table of contents in sync with changes in the outlining of the +content itself—adding and removing sections, renaming sections, and so +on—is a pain. And so I came up with a way to sync the two, using +Emacs Lisp. Emacs Lisp, or Elisp for short, is the Emacs editor's +extension language: the language you use to write Emacs plugins. + +# Elisp For The Win +[Having written](2025-12-03) about my zany Elisp-based Java build system made +me recall those times: I could once again rise to the challenge, and +solve this new problem with Elisp. That's exactly what I did. I wrote +two functions, `bcimd-generate-toc` and `bcimd-remove-toc`. The first +one regenerates the table of contents based on the current set of +level-1 headings. The second one erases the existing table of +contents, along with the connected anchor tags. It's used by the first +function to start out with a clean slate before defining the new table +of contents. + +I decided to collect these functions into an installable package. It's +currently available through Emacs' version-control installation +mechanisms (for example, `package-vc-install`.) See the [project +README](https://github.com/BrandonIrizarry/bcimd) for more details. + +I find Emacs' VC-based package installation facilities extremely +convenient for writing my own bespoke stuff which I otherwise have to +manage locally. I store it remotely, and install it as an *official* +package, much like how Go packages work. In this way, I can even share +my work with the community. + +# Yet Another Yasnippet Testimonial + +I also decided to go the extra mile and use a [Yasnippet](Yasnippet) snippet +that generates some stock front matter. In particular, the title of a +given blog post is ripped directly from the name of the file itself, +which first undergoes some on-the-fly formatting. I got this idea from +[another blog](https://weblog.masukomi.org/2024/07/19/using-org-mode-with-hugo/) where the author runs with the whole Yasnippet idea +to set up her `ox-hugo` front matter. In fact, this is what turned me +on to the idea of Yasnippet as a useful tool in general; that is, it +isn't just a lazy man's way of inserting a for-loop into source code. + +# Now I Can Keep It Together! + +I now use table-of-contents regeneration frequently: writing the +package was a worthwhile investment of time.The only minor hiccup is +that I have to remember to leave two spaces in between headers, so +that the anchor tag doesn't eliminate all whitespace between sections, +an effect which looks aesthetically jarring. I may address this in the +future, but I first need to see how this package interacts with, for +example, level-2 headers. Other ideas include running +table-of-contents generation as an `after-save-hook`, and eventually +writing a full-blown minor-mode. But for now, I'm taking it easy on +this project: I still have to work on other things. diff --git a/posts/understanding-pratt-parsing.md b/posts/understanding-pratt-parsing.md new file mode 100644 index 0000000..d88ba88 --- /dev/null +++ b/posts/understanding-pratt-parsing.md @@ -0,0 +1,155 @@ ++++ +title = "Understanding Pratt Parsing" +tags = ["programming languages"] +date = 2025-12-02 + +summary = """ + +A post I had written about Pratt parsing, in the context of a \ +programming language I was designing at the time. + +""" + ++++ + +# Introduction + +I've forgotten how I came across Pratt parsing specifically. I had +been working on an interpreter for a programming language based on the +one loosely described in Greg Michaelson's *An Introduction to +Functional Programming Through Lambda Calculus*. I had managed to +implement simple arithmetic, and even extended the basic lambda +calculus spec with assignment expressions (a feat which I was very +proud of.) + +However, some parts of my implementation felt a bit hacky (for +example, how I had implemented `letrec`), and my implementation of +lazy evaluation, while mostly complete, ultimately turned out to be +buggy. + +At first, I decided to rewrite the project from scratch. One major +guiding factor was to narrow the scope of the project, borrowing some +advice from [Zed Shaw](https://learncodethehardway.com/blog/32-very-deep-not-boring-beginner-projects/). I got around to writing a new tokenizer, +and then I was on to writing the parser. My initial parser used the +recursive descent technique, taking advantage of the simplified lambda +calculus grammar used in Michaelson's text (for example, parentheses +are always used for application terms there.) + +This time though, I wanted to try something different. And so, +rummaging through the internets, I stumbled across Pratt parsing. + +# "It's like a burrito" + +Understanding Pratt parsing ended up being much harder than I +expected. I ended up searching through a bunch of examples online: + +1. [Alex Kladov's](https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html) Rust-based tutorial. +2. [Eli Bendersky's](https://eli.thegreenplace.net/2010/01/02/top-down-operator-precedence-parsing) Python-based tutorial. +3. Bob Nystrom's [intro](https://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/) to the subject, as well as the relevant + chapter in his [Crafting Interpreters](https://craftinginterpreters.com/compiling-expressions.html). +4. Vaughan Pratt's [original paper](https://tdop.github.io/). Shout-out to the legend who + put this up as a GitHub Pages site! +5. Douglas Crockford's celebrated [article](https://crockford.com/javascript/tdop/tdop.html) on the subject deserves + honorable mention, though my JavaScript is currently rusty and so I + didn't look into it in any depth. + +Alex Kladov in his post calls Pratt parsing the "monad tutorial of +syntactic analysis". As I had recently become familiar with the +concept of "monad" in a [philosophical](https://en.wikipedia.org/wiki/Monad_(philosophy)) sense, I aksed ChatGPT +where the reference comes from: it turns out that it's an inside joke +involving *Haskell* monads. I'm not an expert, but my readings have +given me enough of an inkling to see the connection: Pratt parsing +isn't a discrete "thing" with exactly one shape: it's more of a +technique, if you will—a design pattern—which can assume various +manifestations. + +A good example of this is iteration, because we all recognize it when +we see it, even when we don't know the language—but no one syntactic +construction sufficiently defines it. For-loops, while-loops, Python +generator functions, and [optimized tail-recursive functions](https://mitp-content-server.mit.edu/books/content/sectbyfn/books_pres_0/6515/sicp.zip/full-text/book/book-Z-H-11.html#%_sec_1.2.1 ) all +count as iteration. + +After struggling for some time, I finally managed to distill the +essence of the algorithm, which I present here as pseudocode: + +``` +parse(level): + t ← next(stream) + acc ← nud_dispatch(t) + + while level < precedence(peek(stream)): + t ← next(stream) + acc ← led_dispatch(t, acc) + + return acc +``` + +Unwrapping what this does exactly is a surprisingly nuanced task, +precisely because the algorithm is more about technique than +structure. Because of this, I won't pretend to be up to the task +here. Nevertheless, a brief synopsis is warranted. + +There is a global `stream` of tokens, such that `next(stream)` +consumes and returns the next token, and `peek(stream)` returns the +next token without consuming it. The function `nud_dispatch` +interprets `t` as a *null denotation*, or "nud" for short, and +initializes `acc`. The function `led_dispatch` interprets `t` as a +*left denotation*, or "led" for short. It accumulates a value into +`acc` using the existing value of `acc` (hence the choice of name.) +Both dispatch functions call `parse` recursively in all but the most +trivial cases. + +When `peek`ing the stream reveals a token with higher precedence than +the current `level`, the while loop exits and `acc` is returned. + +The algorithm is initialized by calling `parse(0)`. + +# Down To Brass Tacks + +My approach was to take Eli Bendersky's full source code at the bottom +of his post, and start chiseling away at it. What I ended up with was +the same simple arithmetic calculator, only with a different +architecture: I moved away from Eli's object-oriented approach towards +something closer to the formulation given in the previous section. + +In the end, I was amazed at how simple and robust the actual +implementation turned out to be! I feel that what I came up with (at +this stage, anyway) is arguably simpler than even many of the examples +I initially came across: for example, it isn't necessary to add space +between precedence levels (10, 20, etc.), since you can use an enum to +take care of any ordering needed. Also, using even and odd precedence +levels (for handling right associativity) is unnecessary. For example, +say you have precedence levels `MULTIPLICATION = 2` and +`EXPONENTIATION = 3`. The algorithm cleverly avoids clashing +`EXPONENTIATION-1` with `MULTIPLICATION` when enforcing right +associativity for exponentiation. I found this to be one of the more +remarkable aspects of the algorithm. + +# Wanting More + +To be fair, my calculator app technically doesn't parse arithmetic +expressions: it evaluates them wholesale. This is OK: instead of +accumulating an AST, I'm accumulating an arithmetic result. + +Because of how compelling the calculator app turned out to be, I +decided to stop work on the lambda calculus project, and instead work +on expanding the calculator into a full-blown programming language, +albeit a simple one. I've already made progress in this direction: in +addition to arithmetic (including trig functions!), the application +currently supports variable assignment. + +Ideally, I'd like something with +<br></br> + ++ Booleans ++ Conditionals ++ Loops ++ Functions ++ Proper lexical scoping, even for conditional and loop blocks +<br></br> +I'll see how many of these I manage. + + + + + diff --git a/posts/writing-my-blog-with-eleventy.md b/posts/writing-my-blog-with-eleventy.md new file mode 100644 index 0000000..dc78e51 --- /dev/null +++ b/posts/writing-my-blog-with-eleventy.md @@ -0,0 +1,90 @@ ++++ +title = "Writing My Blog With Eleventy" +tags = ["blogging"] +date = 2025-12-03 + +summary = """ + +This is a reproduction of a post I had on my old blog, which I've \ +since migrated to a custom engine. + +""" + ++++ + +# Introduction + +This is *at least* my third time trying to start a blog. + +First, I experimented with using Org Mode's HTML exporting feature to +create posts; unfortunately, that didn't get me far, though there are +some [interesting attempts](https://one.tonyaldon.com/) by others to this end. I might've +published this material at some point, but at any rate it didn't stay +up long. An early topic from this time include a post about a [Java +build system](https://github.com/BrandonIrizarry/Hydraulic-Make) I once wrote that scanned a `.java` file for its +dependencies (defined by things like package imports and code syntax), +so that those would get passed into `javac` along with the target +file. + +# Hugo +I then started writing a blog using Hugo. Hugo was my first encounter +with an SSG. Because of this, I was a bit impatient with Hugo, and hit +a wall every time I came across any sort of complexity. I also got +frustrated with how themes never follow a consistent template; each +does something different, with different elements, and so each one +effectively has different rules. In the end, I published a blog post +or two on GitHub pages using this setup. It was passable, but in the +end configuring it still felt wonky and cargo-culted. + +Another reason for why I didn't have success with Hugo was my use of +`ox-hugo`. It's a fun package, and you can tell the author put a *lot* +of love into it. However, using Org Mode as a middleman between you +and Hugo obfuscates the nature of Hugo, something I'm realizing now as +I go deeper into using Eleventy. + + +# Eleventy: The Soup Actually Tastes Good + +I went ahead and did a little bit of "shopping" for SSGs. I ran into +[Eleventy](https://www.11ty.dev). I watched the author's [intro video](https://www.youtube.com/watch?v=kzf9A9tkkl4), and +immediately took a liking to it. After a few false starts, I cloned +their [official starter project](https://github.com/11ty/eleventy-base-blog), tweaked it here and there, and +the rest is what you're currently looking at. + +A huge shift in my thinking which made the leap from Hugo to Eleventy +possible occurred when I learned to stop worrying and love the +Markdown. + +I used to think of Markdown as an icky, second-rate version of Org +Mode. Then, I eventually got the hang of writing Markdown using Emacs' +`markdown-mode` package, which is a [masterpiece](https://jblevins.org/projects/markdown-mode/) of a plugin: it +makes the experience of writing Markdown rival that of using Org, and +smoothes out a lot of Markdown's pain points (significant whitespace, +noisy links, etc.) And so I slowly let go of the attachment of using +Org Mode in all the things, and embraced the idea of writing blog +posts directly in Markdown; this also alleviated the complexity of +sundry issues arising from exporting from Org to Markdown. + +At first, Eleventy looks like a deceptively complex pile of language +soup: JS, Markdown, templating languages, HTML, and CSS—at times all +occurring within the same file—all somehow live under one +roof. However, tweaking the starter project ended up being a +relatively easy, even pleasant experience. + +# Painless Deployment + +Even deployment is simple. This site's content is version-controlled +locally. I then build the site, then simply `scp` the `_site` +directory to the appropriate directory in my VPS, where this blog is +hosted. The previous remote `_site` directory is simply overwritten +with the new files. I don't need a GitHub workflow, as I did when +using Hugo with GitHub pages; I don't even need to push to a remote +repo. Copying the files suffices. + +# Conclusion + +On the one hand, I'm nowhere near able to make something like the +starter project from scratch. On the other hand, neither am I +daunted. Eleventy in a sense reminds me of Emacs, in that there's a +certain joy to be found in its eclectic complexity. I look forward to +continue using Eleventy as I grow this blog. |
