I have been using the Astro-Paper theme for a few days now, this is documenting my Tips and Tricks.
Table of contents
Open Table of contents
Dates
I knew that I would struggle to remember to set the dates of new posts and to update them when I add to a post so I looked at ways to automate it.
I found this blog post that has a hook to automate updating the frontmatter on other markdown posts. I took this and tweaked it to add the pubDatetime if it is a new post and adds the modDatetime if the file has been modified. There is a PR open on the main repo or the code is in my repo.
If the hook is not what you are after then I have a solution for the new posts date, snippets. I have created a snippet for the frontmatter and the template for the page. They are nested so it does need two key presses but keeps the code DRY. Again there is a PR open on the main repo or you can find it on mine.
The modDatetime
key needs to be left in the frontmatter, but this is not allowed to be null as it currently stands. The modDatetime:
definition in the src/content/config.ts
file needs to have .nullable()
added to it, so it looks like modDatetime: z.date().optional().nullable()
.
Deploying to GitLab Pages
I am looking to get more proficient on GitLab CI so I wanted to deploy the application using it to their Pages offering. I have used the NPM scripts that are offered by the author to do some checks, then bundle the application to be deployed. I have posted a PR and it is also in my repo too.
Stages
I have included 3 stages (plus I am using the built in .pre stage)
stages:
- code-style
- build
- deploy
Setting some Defaults
I am using this block to set the default docker image and the scripts needed to get the code ready for the main stage functions.
npm ci
is used to remove any current node-modules, use the package-lock file so it is repeatable and some other bits for a CI run over a dev install.
--cache .npm --prefer-offline
sets the build to use the cached version of the installation rather than downloading them each time.
default:
image: node:20.10.0
before_script:
- npm pkg delete scripts.prepare
- npm ci --cache .npm --prefer-offline
Caching
This sets the global cache config and the &
allows the config to be referenced later on and modified. Not sure if this is 100% necessary but I was referencing a few different sources to get the parts to work.
I am using the hash of the package-lock file as the key, so it will only get the cache when it matches the lock file, another level of protection.
The .npm
directory is where we are storing the npm level cache. Usually it is stored at ~/.npm
but this is not cacheable in GitLab so needs to be relocated.
By default we want the cache to be read (or pull) only.
cache:
- &global_cache_node_mods
key:
files:
- package-lock.json
paths:
- .npm/
policy: pull
Stage 0
.pre
is a GitLab default stage and runs before anything else and run the ci install.
With this stage we are wanting to push to the cache as it will it only run when the cache needs to be updated, so we are pulling in the config and overwriting the policy to allow pushing and to only do it on successfully running the stage.
Again we are using the .npm
directory and storing it as an artefact. I don’t think this is needed but does no harm (as far as I can tell).
This stage, as alluded to earlier, will only run when there has been a change that will make the cache invalid. Using only.changes: <FILE>
means this will only run when there is a modification to the package.json
file.
install_dependencies:
stage: .pre
script:
- npm run ci
cache:
- <<: *global_cache_node_mods
when: on_success
policy: pull-push
artifacts:
paths:
- .npm
only:
changes:
- package.json
Stage 1 - Code Style Checks
There are 2 defined npm commands for the repo and we are using them here to do our code style checks, with some logging.
lint-job:
stage: code-style
script:
- echo "Starting to lint the application..."
- npm run lint
- echo "Finished linting the application..."
format-job:
stage: code-style
script:
- echo "Starting to format check the application..."
- npm run format:check
- echo "Finished format checking the application..."
Stage 2 - Build it
This could probably be merged with stage 3, but I liked the idea of keeping them separate in case there was anything else I wanted to do first, like changelogs or IoC.
On a successful run we are pulling the dist dir and calling it astro-paper-blog and storing it for 30 days.
build-job:
stage: build
script:
- echo "Building the code..."
- npm run build
- echo "Build complete."
artifacts:
name: "astro-paper-blog"
when: on_success
expire_in: "30 days"
paths:
- "dist/*"
Stage 3 - Deploy it to GitLab Pages
GitLab Pages deployment has to be done from a job called pages
, and we are defining this as the production release.
We are relying on the job before for its artefacts so define the dependency.
We do not need the code for this step so we can tell it that we do not need to run the check out with variables: GIT_STRATEGY: none
. As we don’t have the code we can’t run the install, so overwrite the default before_script.
We already have the built artefact, but Pages needs it to be in a dir called public
, so move it and then save it.
Any of the other stages can happen whenever, but the deploy should only happen from the main
branch.
pages:
stage: deploy
environment: production
dependencies:
- "build-job"
variables:
GIT_STRATEGY: none
before_script:
- ""
script:
- mv dist public
artifacts:
paths:
- public
only:
- main
Reading time
I saw the post in the main repo about adding reading time to the posts. The guide did well to document the parts needing to be updated, other than the tag part.
In src/utils/getPostsByTag.ts
I needed to add await
to getSortedPosts
and async
to the main function.
import type { CollectionEntry } from "astro:content";
import getSortedPosts from "./getSortedPosts";
import { slugifyAll } from "./slugify";
const getPostsByTag = async (posts: CollectionEntry<"blog">[], tag: string) =>
await getSortedPosts(
posts.filter(post => slugifyAll(post.data.tags).includes(tag))
);
export default getPostsByTag;
In src/pages/tags/[tag]/index.astro
the getPostsByTag
function needs to be updated to have await
.