feat: update Post 2024-03-02-version-3 #3

Merged
wonderfulfrog merged 4 commits from cms/post/2024-03-02-version-3 into main 2024-03-13 16:13:10 -07:00

View file

@ -35,6 +35,12 @@ I tried to migrate to the new [app router structure](https://nextjs.org/docs/app
As an alternative, I was thinking of using [Astro](https://astro.build/), but its still React under the hood. Im happy to use React for work but I dont want to have to deal with its newest idiosyncrasies in my own stuff.
<aside>
**Update 03/13/2024**: It has been pointed out to me[^5] that Astro is - in fact - _not_ React under the hood. It uses the JSX-like syntax, but isn't React. I'll be reconsidering it in the future when I need something above 11ty.
</aside>
Simply put modern React confuses the hell out of me. Im not all in for [“server vs client components”](https://nextjs.org/learn/react-foundations/server-and-client-components). Im certainly not the only one[^4]. I don't want this post to digress into my thoughts on modern React so I'm going to sidestep that for now. I am forced to learn its newest architecture for work, but for my personal site I'd rather things be <mark>easy</mark>. I'm tired of having to deal with breaking changes all the time. I longed for the days of PHP where stuff just worked forever. It was time to embrace an old foe: boring technology.
Boring technology - to me, anyway - is something thats been around for a while, probably a few years. Its stable. Its been around long enough that someone has asked the basic questions on how to do XYZ on StackOverflow. And something important to me is that its also *averse to breaking changes*. It tries its best to avoid them, and if they must then there is a clear migration path and plenty of warning.
@ -51,23 +57,23 @@ So I decided to do what every web dev with a blog does: rebuild their blog from
Eleventy is a static site generator. It does what probably other popular options like Next.js or Astro do. I chose it because:
- Its stable
- Its reliable
- Its fast
- It outputs pure HTML and CSS with no JS
- But you can add client-side JS if you want
- It uses Markdown files for content
- Has great documentation
- Minimal tooling required - its all plain JS
- The developer seems like a cool person
* Its stable
* Its reliable
* Its fast
* It outputs pure HTML and CSS with no JS
* But you can add client-side JS if you want
* It uses Markdown files for content
* Has great documentation
* Minimal tooling required - its all plain JS
* The developer seems like a cool person
Those are my biggest reasons for choosing it. But it also does some cool stuff like:
- Grouping content into collections for easy parsing
- Converts JavaScript data stores into collections
- Has plugins for optimizing images
- Is fine with organizing things however you want
- Did I mention its fast?
* Grouping content into collections for easy parsing
* Converts JavaScript data stores into collections
* Has plugins for optimizing images
* Is fine with organizing things however you want
* Did I mention its fast?
A whole site build from scratch takes 30 seconds, and most of the time is fetching images (for optimization, more on that later).
@ -83,10 +89,10 @@ I wanted to focus on vanilla CSS as much as possible, and use a little post-proc
A methodology that resonated with me was [CUBE CSS](https://cube.fyi/). CUBE standing for <mark>Composition, Utility, Block, and Exception</mark>. The site has a great explanation of how that breaks down, but for my own purposes, I interpreted it as:
- Composition: utility classes that do one thing and one thing well, e.g. a wrapper class for centering a layout and giving it a `max-width`.
- Utility: Design tokens and extremely simple utility classes. Very similar to the utility classes that [Tailwind](https://tailwindcss.com/) provides, albeit fewer.
- Blocks: Like components in React. It's a wild west here, anything goes. What I found those was that my composition and utility classes did 90% of the work for me.
- Exception: Your odd one-offs (like arbitrary values in Tailwind). Uses `data` attributes as the selector because exceptions are represented by state changes (or React props, perhaps?).
* Composition: utility classes that do one thing and one thing well, e.g. a wrapper class for centering a layout and giving it a `max-width`.
* Utility: Design tokens and extremely simple utility classes. Very similar to the utility classes that [Tailwind](https://tailwindcss.com/) provides, albeit fewer.
* Blocks: Like components in React. It's a wild west here, anything goes. What I found those was that my composition and utility classes did 90% of the work for me.
* Exception: Your odd one-offs (like arbitrary values in Tailwind). Uses `data` attributes as the selector because exceptions are represented by state changes (or React props, perhaps?).
I organized everything following this methodolgy, and added a `global.css` file that ties everything together with `@import`and `@import-glob` statements. I used PostCSS to process the CSS into a single file.
@ -96,10 +102,10 @@ I used a JavaScript [Template Data File](https://www.11ty.dev/docs/data-template
What PostCSS plugins am I using? The following:
- [`postcss-import`](https://github.com/postcss/postcss-import) - Any `@import` statements are replaced with the file being imported.
- [`postcss-import-ext-glob`](https://github.com/dimitrinicolas/postcss-import-ext-glob) - Like using `@import` but with glob file paths. More of a developer convenience.
- [`autoprefixer`](https://github.com/postcss/autoprefixer) - Not as essential these days, but there are still some vendor-prefixed CSS rules.
- [`cssnano`](https://github.com/cssnano/cssnano) - Minifies my CSS, and fast.
* [`postcss-import`](https://github.com/postcss/postcss-import) - Any `@import` statements are replaced with the file being imported.
* [`postcss-import-ext-glob`](https://github.com/dimitrinicolas/postcss-import-ext-glob) - Like using `@import` but with glob file paths. More of a developer convenience.
* [`autoprefixer`](https://github.com/postcss/autoprefixer) - Not as essential these days, but there are still some vendor-prefixed CSS rules.
* [`cssnano`](https://github.com/cssnano/cssnano) - Minifies my CSS, and fast.
Combining two CSS strings is perhaps not the most efficient way of doing things, but it makes sense to me and seems fast enough.
@ -169,6 +175,7 @@ const helperClasses = [
I run this array through a `helperClassesToCss` function I wrote, which takes the helper class prefix, appends the colour name (e.g. `primary`) to the prefix, and sets the array of CSS properties to the desired value.
### A walkthrough
I wanted to run through an example process from JSON to CSS and how it works - hopefully I can refer to this in the future if I ever forget how the process works.
To start, `cssPropertiesToCss` takes an array of CSS rules and sets them to the same `value`. For example:
@ -275,7 +282,7 @@ For example, my catalogue content is inside `/catalogue`. Inside that folder are
Just one property but it achieves a lot. It applies the `catalogue` tag to every file inside this directory.
Because I'm using the `tags` feature, 11ty will automatically group everything inside this directory into a new collection called `catalogue`, which I can access from the global collections using `collections.catalogue`. With just a few lines of code I have _my entire catalogue_ in an array! No fetching or setup required. Done and done!
Because I'm using the `tags` feature, 11ty will automatically group everything inside this directory into a new collection called `catalogue`, which I can access from the global collections using `collections.catalogue`. With just a few lines of code I have *my entire catalogue* in an array! No fetching or setup required. Done and done!
But wait... I can keep going... take for example my `/catalogue/books` folder. This one also has a template data file in here called `books.11tydata.js` which lets me use JS in here:
@ -293,11 +300,12 @@ module.exports = {
```
Lets go through this one:
- Every file inside uses the `layouts/catalogue-item` layout
- Applies the `book` tag (and therefore generates a new collection, automatically)
- Creates a permalink using the `fileSlug` variable per page
- Changes the `linkTitle` frontmatter
- Uses `eleventyComputed` (which is a special field) to inject frontmatter into the template's frontmatter
* Every file inside uses the `layouts/catalogue-item` layout
* Applies the `book` tag (and therefore generates a new collection, automatically)
* Creates a permalink using the `fileSlug` variable per page
* Changes the `linkTitle` frontmatter
* Uses `eleventyComputed` (which is a special field) to inject frontmatter into the template's frontmatter
Highly suggest reading the docs on [Computed Data](https://www.11ty.dev/docs/data-computed/).
@ -344,8 +352,8 @@ module.exports = async function () {
This allows for my Last.fm data to be accessible via the global `data` field! The only catch is that this data is generated at build time and not live. This can be solved different ways, such as:
- Rebuild the site periodically
- Make a web component that fetches the data live
* Rebuild the site periodically
* Make a web component that fetches the data live
For now I'm content to trigger a build every so often in order for the data to be "live-ish". In the future it would be fun to build a web component (or perhaps someone out there has done that already)! 11ty is very compatible with web components.
@ -353,7 +361,7 @@ For now I'm content to trigger a build every so often in order for the data to b
Media storage was still a thorny issue. I couldn't decide on how I wanted to manage it for a while. All I knew for certain was that I was tired of keeping it in my repo - it needed to be elsewhere.
As I dug into 11ty, I discovered a truly magical plugin called [`eleventy-img`](https://www.11ty.dev/docs/plugins/image/). It takes an image (either locally or remote), optimizes it, and stores it in the _output_ directory. The image can therefore be put anywhere you like, and with a small bit of shortcode it works like magic. For example:
As I dug into 11ty, I discovered a truly magical plugin called [`eleventy-img`](https://www.11ty.dev/docs/plugins/image/). It takes an image (either locally or remote), optimizes it, and stores it in the *output* directory. The image can therefore be put anywhere you like, and with a small bit of shortcode it works like magic. For example:
```
{% raw %}{% image "https://path.to.image.jpg" %}{% endraw %}
@ -369,13 +377,13 @@ I decided to do the painstaking process of manually updating all of my content b
The [Eleventy Excellent](https://eleventy-excellent.netlify.app/) starter was a huge inspiration for this site. I used its organization structure a lot. My `config` folder holds a lot of stuff:
- Custom collections, `config/collections`
- My design tokens, `config/design-tokens`
- Filters, `config/filters`
- Plugins, `config/plugins`
- Shortcodes, `config/shortcodes`
- Transforms, `config/transforms`
- Constants, `config/constants.js`
* Custom collections, `config/collections`
* My design tokens, `config/design-tokens`
* Filters, `config/filters`
* Plugins, `config/plugins`
* Shortcodes, `config/shortcodes`
* Transforms, `config/transforms`
* Constants, `config/constants.js`
### Custom collections
@ -393,10 +401,10 @@ As mentioned, a bunch of `.json` files that have my design tokens in here. That'
11ty has a lot of [built-in plugins](https://www.11ty.dev/docs/plugins/), but also makes it easy to define your own. In my case I've defined a customized Markdown processor using [`markdown-it`](https://github.com/markdown-it/markdown-it). I added some neat features:
- [Footnotes](https://github.com/markdown-it/markdown-it-footnote)
- [Abbreviations](https://github.com/markdown-it/markdown-it-abbr)
- [Heading anchors](https://github.com/valeriangalliat/markdown-it-anchor)
- [Code highlighting using Prism](https://github.com/jGleitz/markdown-it-prism)
* [Footnotes](https://github.com/markdown-it/markdown-it-footnote)
* [Abbreviations](https://github.com/markdown-it/markdown-it-abbr)
* [Heading anchors](https://github.com/valeriangalliat/markdown-it-anchor)
* [Code highlighting using Prism](https://github.com/jGleitz/markdown-it-prism)
I'm also using the [`@11ty/eleventy-plugin-rss`](https://www.11ty.dev/docs/plugins/rss/) plugin to generate my RSS feed. I'm glad to see that 11ty supports RSS feeds out-of-the-box. I always hated that setting up an RSS feed in Next.js felt rather hacky.
@ -422,12 +430,12 @@ A couple of properties that are passed to my `.eleventy.config.js` file.
To create and manage my content I use [Decap CMS](https://decapcms.org/) (formerly Netlify CMS). As far as I can tell it's the only game in town that does what I want:
- Git-backed file system that works with flat file structures
- Works on desktop and mobile
- Has preview deploys using pull requests
- Configurable schema for content
* Git-backed file system that works with flat file structures
* Works on desktop and mobile
* Has preview deploys using pull requests
* Configurable schema for content
It's honestly not my favourite, but it works well enough that I want to continue using it. I've toyed with making my own solution for years, but I think that's something best left to someone who has time to not only build it but _maintain_ it.
It's honestly not my favourite, but it works well enough that I want to continue using it. I've toyed with making my own solution for years, but I think that's something best left to someone who has time to not only build it but *maintain* it.
The only thing I can't seem to figure out is a custom media library. As previously mentioned I use Bunny.net for all my media storage, and they don't offer a plugin for it. From what I can tell it's not possible to roll your own either.
@ -489,17 +497,17 @@ The colour scheme was tricky to figure out. I knew that I wanted a teal colour a
I stumbled upon [Themescura](https://www.xypnox.com/blag/posts/themescura/introducing-themescura/) and found the philosophy resonated with me. The basis for a colour scheme has 5 elements:
- Primary - Also known as the "brand colour"
- Secondary - A... second colour.
- Background - The colour of the site's background
- Surface - A colour that is sort of a mix between Primary and Background
- Text - The colour of the site's overall text
* Primary - Also known as the "brand colour"
* Secondary - A... second colour.
* Background - The colour of the site's background
* Surface - A colour that is sort of a mix between Primary and Background
* Text - The colour of the site's overall text
I also extrapolated a few extra colours that are based on these five:
- Border - The colour of borders! Like a darkened version of the Primary colour. Works well when paired with Surface.
- Shadow - A very dark version of the Primary colour.
- Fade Text - A mix of the Text colour and Background colour.
* Border - The colour of borders! Like a darkened version of the Primary colour. Works well when paired with Surface.
* Shadow - A very dark version of the Primary colour.
* Fade Text - A mix of the Text colour and Background colour.
The [source code for Themescura](https://github.com/xypnox/xypnox.github.io/blob/v2/src/theme.ts) provides a "developer way" to create the colours from the base five. I used this way as a starting point, then tweaked the values using HSL until I was happy.
@ -559,29 +567,34 @@ If you have any questions, please [reach out to me on Mastodon]({{ meta.social.m
Here are some resources I used (likely heavily) while building the site.
### Inspiration
- [Eleventy Excellent](https://eleventy-excellent.netlify.app/) ([view source](https://github.com/madrilene/eleventy-excellent))
- [Aleksandr Hovhannisyan](https://www.aleksandrhovhannisyan.com/) ([view source](https://github.com/AleksandrHovhannisyan/aleksandrhovhannisyan.com))
- [Andy Bell](https://andy-bell.co.uk/ ) ([view source](https://github.com/Andy-set-studio/personal-site-eleventy))
- [Cory Dransfeldt](https://coryd.dev/) ([view source](https://github.com/cdransf/coryd.dev))
- [Lea Verou](https://lea.verou.me/) ([view source](https://github.com/LeaVerou/lea.verou.me))
* [Eleventy Excellent](https://eleventy-excellent.netlify.app/) ([view source](https://github.com/madrilene/eleventy-excellent))
* [Aleksandr Hovhannisyan](https://www.aleksandrhovhannisyan.com/) ([view source](https://github.com/AleksandrHovhannisyan/aleksandrhovhannisyan.com))
* [Andy Bell](https://andy-bell.co.uk/) ([view source](https://github.com/Andy-set-studio/personal-site-eleventy))
* [Cory Dransfeldt](https://coryd.dev/) ([view source](https://github.com/cdransf/coryd.dev))
* [Lea Verou](https://lea.verou.me/) ([view source](https://github.com/LeaVerou/lea.verou.me))
### Data Cascade
- [The Data Cascade](https://www.11ty.dev/docs/data-cascade/)
- [I Finally Understand Eleventy's Data Cascade.](https://benmyers.dev/blog/eleventy-data-cascade/)
* [The Data Cascade](https://www.11ty.dev/docs/data-cascade/)
* [I Finally Understand Eleventy's Data Cascade.](https://benmyers.dev/blog/eleventy-data-cascade/)
### 11ty setup and configuration
- [Build a Blogroll with Eleventy](https://benmyers.dev/blog/eleventy-blogroll/)
- [From Wordpress To Eleventy With Ease](https://heydonworks.com/article/wordpress-to-eleventy/)
- [Optimizing Images with the 11ty Image Plugin](https://www.aleksandrhovhannisyan.com/blog/eleventy-image-plugin/)
* [Build a Blogroll with Eleventy](https://benmyers.dev/blog/eleventy-blogroll/)
* [From Wordpress To Eleventy With Ease](https://heydonworks.com/article/wordpress-to-eleventy/)
* [Optimizing Images with the 11ty Image Plugin](https://www.aleksandrhovhannisyan.com/blog/eleventy-image-plugin/)
### 11ty and design
- [What Are Design Tokens?](https://css-tricks.com/what-are-design-tokens/)
- [Configuring Web Fonts in 11ty with Global Data](https://www.aleksandrhovhannisyan.com/blog/configuring-web-fonts-in-11ty-with-global-data/)
- [Easily Use Design Tokens In Eleventy](https://heydonworks.com/article/design-tokens-in-eleventy/)
* [What Are Design Tokens?](https://css-tricks.com/what-are-design-tokens/)
* [Configuring Web Fonts in 11ty with Global Data](https://www.aleksandrhovhannisyan.com/blog/configuring-web-fonts-in-11ty-with-global-data/)
* [Easily Use Design Tokens In Eleventy](https://heydonworks.com/article/design-tokens-in-eleventy/)
[^1]: Search for "nextjs react hydration error" to see what I mean.
[^2]: Here is [a post on 11ty.dev](https://www.11ty.dev/blog/stability/) with additional information, if you're curious.
[^3]: Every Layout is a fantastic resource and worth every penny. Check out the free options if you're not sure, and really try them out.
[^4]: People smarter than me have created posts outlining their problems with modern React. Here is a small sample: [Annoyed at React](https://blog.cassidoo.co/post/annoyed-at-react/) [React, where are you going?](https://dev.to/matfrana/react-where-are-you-going-5284) [Switching Costs](https://adactio.com/journal/20837) [Removing React is just weakness leaving your codebase](https://begin.com/blog/posts/2024-01-26-removing-react-is-just-weakness-leaving-your-codebase)
[^5]: Thank you to xypnox for the insight! [View Mastodon post](https://fosstodon.org/@xypnox/112082656802343799)
*[HSL]: Hue, Saturation, and Lightness