Hugo + Alpine.js + TailwindCSS Quickstart
Using my development environment setup I’m going to generate a new hugo site.
The first time we access the hugo container we need to ensure the hugo/src
folder exists:
mkdir hugo/src
We will start by opening a bash terminal to our hugo container:
./run.sh hugo bash
Then we can verify our Hugo version:
hugo version
# => hugo v0.107.0-2221b5b30a285d01220a26a82305906ad3291880 linux/amd64 BuildDate=2022-11-24T13:59:45Z VendorInfo=gohugoio
From here, we can refer to the official Hugo quick start and initialize Hugo:
hugo new site . --format yaml
Next we will setup tailwind
, alpinejs
, @tailwindcss/aspect-ratio
, @tailwindcss/typography
and a few other javascript modules used for development:
npm init -y
npm install -D \
@tailwindcss/aspect-ratio \
@tailwindcss/typography \
alpinejs \
autoprefixer \
concurrently \
postcss \
postcss-cli \
postcss-import \
tailwindcss
We will leverage the Tailwind CLI to manage the Tailwind build outside of Hugo. We will also modify the hugo/src/package.json
scripts
to add some helper scripts for managing the hugo and tailwind build pipelines:
// hugo/src/package.json
{
"scripts": {
"start": "concurrently \"npm:watch:*\"",
"release": "concurrently -m 1 \"npm:build\" \"npm:deploy\"",
"watch:tailwind": "npm run build:tailwind -- --watch",
"watch:hugo": "npm run hugo:memory -- -D server --baseURL ${HUGO_BASEURL:-localhost:1313} --bind=0.0.0.0 --templateMetrics",
"build": "concurrently -m 1 \"npm:build:tailwind\" \"npm:build:hugo\"",
"build:tailwind": "tailwindcss -c ./tailwind/config.js -i ./tailwind/app.css -o ./assets/app.css",
"build:hugo": "hugo -v --minify",
"deploy": "concurrently \"npm:deploy:*\"",
"deploy:hugo": "hugo deploy -v",
"hugo:memory": "hugo",
"hugo:disk": "hugo --renderToDisk --cleanDestinationDir --disableFastRender"
},
"devDependencies": {
"@tailwindcss/aspect-ratio": "^0.4.2",
"@tailwindcss/typography": "^0.5.8",
"alpinejs": "^3.10.5",
"autoprefixer": "^10.4.13",
"concurrently": "^7.6.0",
"postcss": "^8.4.19",
"postcss-cli": "^10.1.0",
"postcss-import": "^15.0.0",
"tailwindcss": "^3.2.4"
}
}
The next step is setting up TailwindCSS which requires two files:
// hugo/src/tailwind/config.js
/* global module require */
module.exports = {
mode: 'jit',
content: [
'./layouts/**/*.html',
'./content/**/*.{md,html}',
],
plugins: [
require('@tailwindcss/aspect-ratio'),
require('@tailwindcss/typography'),
]
};
/* hugo/src/tailwind/app.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
With those files added we can uncomment the lines in our hugo/Dockerfile
and run ./up.sh
in a new terminal session. Once started we can visit our site at http://localhost:1313
and see an “Empty Response” page because we dont have any content files or templates in our Hugo site.
Let’s add the required files to actually see something.
<!-- hugo/src/layouts/_default/baseof.html -->
<!doctype html>
<html lang="{{ .Lang }}">
<head>
{{ block "head" . }}
<title>{{ .Title }}</title>
{{ partial "style" . }}
{{ end }}
</head>
<body>
{{ block "main" . }}
{{ end }}
{{ partial "script" . }}
</body>
</html>
<!-- hugo/src/layouts/_default/home.html -->
{{ define "main" }}
<div x-data="sampleComponent({{ jsonify .Title }})">
{{ .Content }}
</div>
{{ end }}
<!-- hugo/src/layouts/partials/script.html -->
{{ $build := dict
"targetPath" "app.js"
"params" (dict
"basePath" ("/" | relURL)
)
}}
{{ with resources.Get "script/index.js" }}
{{ $script := js.Build $build . | resources.Fingerprint "sha512" }}
<script src="{{ $script.RelPermalink }}" integrity="{{ $script.Data.Integrity }}"></script>
{{ end }}
<!-- hugo/src/layouts/partials/style.html -->
{{ with resources.Get "app.css" }}
{{ $style := minify . | resources.Fingerprint "sha512" }}
<link rel="stylesheet" href="{{ $style.RelPermalink }}" />
{{ end }}
<!-- hugo/src/content/_index.md -->
---
title: Hello World Title
---
# Hello World
// hugo/src/assets/script/sample-component/index.js
import { basePath } from '@params';
export default (...initArgs) => {
return {
init() {
console.info(JSON.stringify({ basePath, initArgs }, null, 2));
}
};
};
// hugo/src/assets/script/index.js
import Alpine from 'alpinejs';
import sampleComponent from './sample-component';
Alpine.data('sampleComponent', sampleComponent);
Alpine.start();
With all of those files added we can run ./up.sh
and load up our page at http://localhost:1313/
and see a TailwindCSS styles “Hello World”. If we open up the javascript console in the developer tools we should see an object output that looks like this:
{
"basePath": "/",
"initArgs": [
"Hello World Title"
]
}
Note that the basePath
is embedded in the code from Hugo on build while the initArgs
are passed in at runtime when we initialize the Alpine.js component with x-data
.
The last little bit before we commit the project to git is adding the .gitignore
which should look something like this:
# .gitignore
.env
hugo/src/node_modules
hugo/src/.hugo_build.lock
hugo/src/assets/app.css