A bit of re-reading my article.
This commit is contained in:
vanhempi
09b0af122a
commit
2acd6effce
|
@ -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
|
||||
|
|
Ladataan…
Viittaa uudesa ongelmassa