diff --git a/src/posts/0018-makefile-as-static-site-builder-follow-up/index.org b/src/posts/0018-makefile-as-static-site-builder-follow-up/index.org index 736c86a..6eb7bf8 100644 --- a/src/posts/0018-makefile-as-static-site-builder-follow-up/index.org +++ b/src/posts/0018-makefile-as-static-site-builder-follow-up/index.org @@ -8,17 +8,17 @@ #+OPTIONS: auto-id:t #+STARTUP: showeverything -This article will dig a bit deeper about how I generate my static website. +This article will dig a bit deeper about my =Makefile= based static website generator. In a [[https://her.esy.fun/posts/0017-static-blog-builder/index.html][previous article]] I just gave the rationale and an overview to do it yourself. Mainly it is very fast and portable. -A few goal reached by my current build system are: +A few goals reached by my current build system are: -1. Be fast, try to make as few work as possible. +1. Be fast and make the minimal amount of work as possible. I don't want to rebuild all the html pages if I only change one file. 2. Source file format agnostic. You can use markdown, org-mode or even - directly writing html. + directly write html. 3. Support gemini 4. Optimize size: minify HTML, CSS, images 5. Generate an index page listing the posts @@ -38,7 +38,7 @@ To make those transformations I use very short a shell scripts. :CUSTOM_ID: -makefile--overview :END: -A Makefile is constitued of rules. +A Makefile is made out of rules. The first rule of your Makefile will be the default rule. The first rule of my Makefile is called =all=. @@ -50,15 +50,14 @@ target: file1 file2 --output target #+end_src -if =target= does not exists, then =make= will look at its -dependencies. -If any of its dependency need to be updated, it will run all the rules in -the correct order to rebuild them, and finally run the script to build +if =target= does not exists, then =make= will look at its dependencies. +If any of its dependencies need to be updated, it will run all the rules in +the correct order to rebuild them and finally run the script to build =target=. -A file need to be updated if one of its dependency need to be updated or is +A file needs to be updated if one of its dependency needs to be updated or is newer. -The ususal case of =make= is about building a single binary out of many +The usual use case of =make= is about building a single binary out of many source files. But for a static website, we need to generate a lot of files from a lot of files. @@ -105,7 +104,7 @@ I have a block for: The rules to copy assets will be a good first example. 1. find all assets in =src/= directory -2. generate all assets from these file in =_site/= directory +2. generate all assets from these files in =_site/= directory 3. make this rule a dependency on the =all= rule. @@ -123,44 +122,44 @@ ALL += assets OK, this looks terrible. But mainly: -- ~SRC_ASSETS~ will contains the result of the command ~find~. -- ~DST_ASSETS~ will contains the files of ~SRC_ASSETS~ but we replace the +- ~SRC_ASSETS~ will contain the result of the command ~find~. +- ~DST_ASSETS~ will contain the files of ~SRC_ASSETS~ but we replace the =src/= by =_site/=. - We create a generic rule; for all files matching the following pattern =_site/%=, look for the file =src/%= and if it is newer (in our case) - then execute the following commmands: + then execute the following commands: - create the directory to put =_site/%= in - copy the file About the line ~@mkdir -p "$(dir $@)"~: - the =@= at the start of the command simply means that we make this execution silent. - The =$@= is replaced by the target string. -- And =$(dir $@)= will generate the dirname of =$@=. +- And =$(dir $@)= will generate the folder name of =$@=. -For the line with ~cp~ you just need to know that =$<= will represent the +For the line with ~cp~, you just need to know that =~$<~= will represent the first dependency. -So my Makefile is composed of similar blocks, where I replace the first -find command to match specific files and where I use different building rule. -An important point, is that the rule must be the most specific possible -because make will use the most specific rule in case of ambiguity. -So for example, the matching rule =_site/%: src/%= will match all files in +My Makefile is composed of similar blocks, where I replace the first +find command to match specific files and where I use different building rules. +An important point is that the rules must be the most specific possible. +This is because =make= will use the most specific rule in case of ambiguity. +For example, the matching rule =_site/%: src/%= will match all files in the =src/= dir. -But if we want to treat css file with another rule we could write: +But if we want to treat =CSS= files with another rule we could write: #+begin_src makefile _site/%.css: src/%.css minify "$<" "$@" #+end_src -And if the selected file is a css file, this rule will be selected. +And if the selected file is a =CSS= file, this rule will be selected. ** Prelude :PROPERTIES: :CUSTOM_ID: prelude :END: -So to start I have a few predefined useful variables. +I start with variables declarations: #+begin_src makefile all: site @@ -183,7 +182,7 @@ NO_SRC_FILE := ! -name '*.org' :CUSTOM_ID: css :END: -So here we go, the same simple pattern for CSS files. +Here we go; the same simple pattern for CSS files. #+begin_src makefile # CSS @@ -280,16 +279,15 @@ or the file, it will generate the dependencies. :CUSTOM_ID: indexes :END: -One of the goal I have is to be as agnostic as possible regarding format. -I know that the main destination format will be html. -So as much as possible, I would like to use this format. -So for every generated html file I will generate a clean XML file (via -hxclean) so I will be able to get specific node of my HTML files. -These XML files will constitute my "index". -Of course this is not the most optimized index (I could have used sqlite -for example) but it will already be quite helpful as the same index files -will be used to build the homepage with the list of articles, and the RSS -file. +We often need indexes to build a website. +Typically to list the latest articles, build the RSS file. +So for sake of simplicity, I decided to build my index as a set of XML files. +Of course, this could be optimizide, by using SQLite for example. +But this will already be really fast. + +For every generated html file I will generate a clean XML file with +=hxclean=. +Once cleaned, it will be easy to access a specific node of in these XML files. #+begin_src makefile # INDEXES @@ -308,24 +306,23 @@ indexcache: $(DST_XML_FILES) ALL += indexcache #+end_src -So to resume this rule will generate for every file in =site/posts/*.html= -a corresponding =xml= file (=hxclean= takes an HTML an try its best to make -an XML out of it). +This rule will generate for every file in =site/posts/*.html= a corresponding +=xml= file (=hxclean= takes an HTML an try its best to make an XML out of it). ** HTML Index :PROPERTIES: :CUSTOM_ID: html-index :END: -So now we just want to generate the main =index.html= page at the root of +Now we just want to generate the main =index.html= page at the root of the site. This page should list all articles by date in reverse order. -So the first step is to take advantage of the cache index. +The first step is to take advantage of the cache index. For every XML file I generated before I should generate the small HTML block I want for every entry. For this I use a script =mk-index-entry.sh=. -He will use =hxclean= to retrieve the date and the title from the cached +He will use =hxselect= to retrieve the date and the title from the cached XML files. Then generate a small file just containing the date and the link. @@ -340,7 +337,7 @@ $(INDEX_CACHE_DIR)/%.index: $(INDEX_CACHE_DIR)/%.xml $(MK_INDEX_ENTRY) $(MK_INDEX_ENTRY) "$<" "$@" #+end_src -which reads, for every =.xml= file generate a =.index= file with +It means: for every =.xml= file generate a =.index= file with =mk-index-entry.sh=. #+begin_src sh @@ -378,7 +375,7 @@ printf ": %-55s" "$title ($keywords)" echo " [${fg[green]}OK${reset_color}]" #+end_src -Then I use these intermediate file to generate a single bigger index file. +Then I use these intermediate files to generate a single bigger index file. #+begin_src makefile HTML_INDEX := $(DST_DIR)/index.html @@ -393,13 +390,16 @@ ALL += index #+end_src This script is a big one, but it is not that complex. -For every file, I generate a new file =DATE-dirname=, I sort them in -reverse order and put their content in the middle of an HTML file. +For every file, I generate a new file =DATE-dirname=. +I sort them in reverse order and put their content in the middle of an HTML +file. -The important part is that it is only generated if the index change. -So first part of the script handle the creation of file using the date in -their file name which will help us sort them later. +Important note: this file updates only if the index change. +The first part of the script creates files with the creation date in their +metadatas. +The created file name will contain the creation date, this will be helpful +later. #+begin_src sh #!/usr/bin/env zsh @@ -480,11 +480,11 @@ echo "* HTML INDEX [done]" :CUSTOM_ID: rss :END: -So for my RSS generation this is quite similar to the system I use to -generate my index file. +My RSS generation is similar to the system I used to generate the index +file. I just slightly improved the rules. -The makefile blocks look like: +The =Makefile= blocks look like: #+begin_src makefile # RSS @@ -553,7 +553,7 @@ gemini: $(DST_GMI_FILES) $(GMI_INDEX) $(GEM_ATOM) :CUSTOM_ID: images :END: -For images, I try to convert all of them with imagemagick to compress them. +For images, I try to compress them all with imagemagick. #+begin_src makefile # Images @@ -586,7 +586,6 @@ ALL += $(DST_IMG_FILES) :END: A nice bonus is that I also deploy my website using make. -And note I protect myself from Makefile temporary bugs for the =clean= rule. #+begin_src makefile # DEPLOY