An Eleventy Starter with Tailwind CSS and Alpine.js
When I decided to try to base my current personal website on Eleventy, I didn’t want to reinvent the wheel: I tested all the Eleventy starters built with Tailwind CSS that I could find in Starter Projects from the documentation.
Many of the starters seemed to integrate Tailwind CSS in a contrived way. Also, some of them seemed to assume that no one updates Tailwind’s configuration on the fly while working on a website. That’s why I integrated Eleventy with Tailwind CSS and Alpine.js myself. I have reason to believe that you’ll like the simplicity of my solution.
Good design is as little design as possible.
—Dieter Rams, 10 Principles for Good Design
If you’re uninterested in the details, feel free to grab my starter and jump right in.
Getting started
I’m going to assume you have a general understanding of Tailwind CSS, HTML, JavaScript, Nunjucks, the command line, and npm.
Let’s start by with a new a folder, then cd
to it in the command line, and initialize it with a package.json
file:
npm init -y
Now we can install Eleventy and Tailwind CSS. We’ll throw in PostCSS as well:
npm install --save-dev @11ty/eleventy tailwindcss postcss-cli
We need to create a page to test whether we’ve successfully set things up. In a real use case, our pages will use templates, so we’ll do that here as well. That’s where Nunjucks fits into the mix, serving as a templating engine.
Let’s make a new file called index.njk
in the project folder. We’ll designate it as the homepage:
{% extends "_includes/default.njk" %}
{% block title %}It does work{% endblock %}
{% block content %}
<div class="fixed inset-0 flex justify-center items-center">
<div>
<span class="text-change">Good design</span><br/>
<span class="change">is<br/>as little design<br/>as possible</span>
</div>
</div>
{% endblock %}
Basic templating
Now let’s create a new folder in the project folder called _includes
(and yes, the folder name matters). Inside this new folder, we’ll create a file called default.njk
that we’ll use as the default template for our layout. We’ll keep things simple with a basic HTML boilerplate:
<!DOCTYPE html>
<html lang="en">
<head>
<title>
{% block title %}Does it work?{% endblock %}
</title>
<meta charset="UTF-8"/>
{% if description %}
<meta name="description" content="{{description}}"/>
{% endif %}
<meta http-equiv="x-ua-compatible" content="ie=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover"/>
<link rel="stylesheet" href="/style.css?v={% version %}"/>
{% block head %}{% endblock %}
</head>
<body>
{% block content %}
{{ content | safe }}
{% endblock %}
</body>
</html>
Configuring Tailwind CSS
Let’s take care of a test for Tailwind CSS in as few moves as possible. First, create a new subfolder called styles
and a file in it called tailwind.config.js
:
module.exports = {
theme: {
colors: {
change: "transparent"
}
},
variants: {},
plugins: [],
}
Then, create a file called tailwind.css
in that same styles
folder:
/* purgecss start ignore */
@tailwind base;
/* purgecss end ignore */
.change {
color: transparent;
}
/* purgecss start ignore */
@tailwind components;
/* purgecss end ignore */
@tailwind utilities;
We’re done with the styles folder for now. What we do need is a configuration file that tells PostCSS to use Tailwind CSS, which we can get by creating a new file in the root directory of the project folder called postcss.config.js
. Here’s how we require Tailwind CSS and its configuration file with PostCSS:
module.exports = {
plugins: [
require(`tailwindcss`)(`./styles/tailwind.config.js`)
],
};
Starting and building the project
Now let’s create another new file in the same root directory called .gitignore
. This will allow us to define what files to skip when committing the project to a repo, like on GitHub:
_site/
_tmp/
.DS_Store
node_modules/
package-lock.json
Next, is another new file, this time one that tells Eleventy what it can ignore, called .eleventyignore
. It only needs one line:
node_modules
OK, now we will create a file called .eleventy.js
(note the leading dot!) that basically configures Eleventy, telling it what files to watch and where to save its work:
module.exports = function (eleventyConfig) {
eleventyConfig.setUseGitIgnore(false);
eleventyConfig.addWatchTarget("./_tmp/style.css");
eleventyConfig.addPassthroughCopy({ "./_tmp/style.css": "./style.css" });
eleventyConfig.addShortcode("version", function () {
return String(Date.now());
});
};
We can now update the package.json
file with all of the scripts we need to start and build the site during development. The dependencies should already be there from the initial setup.
{
"scripts": {
"start": "eleventy --serve & postcss styles/tailwind.css --o _tmp/style.css --watch",
"build": "ELEVENTY_PRODUCTION=true eleventy & ELEVENTY_PRODUCTION=true postcss styles/tailwind.css --o _site/style.css"
},
"devDependencies": {
"@11ty/eleventy": "^0.11.0",
"postcss-cli": "^7.1.0",
"tailwindcss": "^1.4.6"
}
}
Hey, great job! We made it. Build the project to generate the initial CSS — this step is only required the very first time we set up. From the command line:
npm run build
And — drumroll, please — let’s officially start the site:
npm run start
Open the page http://localhost:8080
in your browser. It’s not gonna look like much, but check out the page title in the browser tab:
We can still do a little more checking to make sure everything’s good. Open up /styles/tailwind.config.js
and change the transparent
color value to something else, say black
. Tailwind’s configuration should reload, along with the page in your browser.
Don’t lose sight of your browser and edit /styles/tailwind.css
by changing transparent
to black
again. Your CSS file should reload and refresh in your browser.
Now we can work nicely with Eleventy and Tailwind CSS!
Optimizing the output
At this point, Tailwind CSS works with Eleventy, but the CSS file is huge. The generated HTML isn’t perfect either because it contains stuff like redundant newline characters. Let’s clean it up:
npm install --save-dev @fullhuman/postcss-purgecss postcss-clean html-minifier
Open up postcss.config.js
and replace what’s in there with this:
module.exports = {
plugins: [
require(`tailwindcss`)(`./styles/tailwind.config.js`),
require(`autoprefixer`),
...(process.env.ELEVENTY_PRODUCTION
? [
require(`postcss-clean`),
require(`@fullhuman/postcss-purgecss`)({
content: ["_site/**/*.html"],
defaultExtractor: (content) =>
content.match(/[w-/:]+(?<!:)/g) || [],
whitelist: [],
whitelistPatterns: [/body/, /headroom/, /ril/],
}),
]
: []),
],
};
In the future, in the process of creating your website, if something looks wrong after you build the project and you have the impression that fragments of CSS are missing, add “ignored” class names to the whitelist in the file above.
Add the following line to the beginning of the .eleventy.js
file:
const htmlmin = require("html-minifier");
We also need to configure htmlmin
in .eleventy.js
as well:
eleventyConfig.addTransform("htmlmin", function (content, outputPath) {
if (
process.env.ELEVENTY_PRODUCTION &&
outputPath &&
outputPath.endsWith(".html")
) {
let minified = htmlmin.minify(content, {
useShortDoctype: true,
removeComments: true,
collapseWhitespace: true,
});
return minified;
}
return content;
});
We’re using a transform here which is an Eleventy thing. Transforms can modify a template’s output. At this point, .eleventy.js
should look like this:
const htmlmin = require("html-minifier");
module.exports = function (eleventyConfig) {
eleventyConfig.setUseGitIgnore(false);
eleventyConfig.addWatchTarget("./_tmp/style.css");
eleventyConfig.addPassthroughCopy({ "./_tmp/style.css": "./style.css" });
eleventyConfig.addShortcode("version", function () {
return String(Date.now());
});
eleventyConfig.addTransform("htmlmin", function (content, outputPath) {
if (
process.env.ELEVENTY_PRODUCTION &&
outputPath &&
outputPath.endsWith(".html")
) {
let minified = htmlmin.minify(content, {
useShortDoctype: true,
removeComments: true,
collapseWhitespace: true,
});
return minified;
}
return content;
});
};
Alright, let’s run npm run start
once again. You’ll see that nothing has changed and that’s because optimization only happens during build. So, instead, let’s try npm run build
and then look at the _site folder
. There shouldn’t be a single unnecessary character in the index.html
file. The same goes for the style.cs
s file.
A project built like this is now ready to deploy. Good job! ?
Integrating Alpine.js
I decided to switch to Eleventy from Gatsby.js because it just felt like too much JavaScript to me. I’m more into the reasonable dose of vanilla JavaScript mixed with Alpine.js. We won’t get into the specifics of Alpine.js here, but it’s worth checking out Hugo DiFrancesco’s primer because it’s a perfect starting point.
Here’s how we can install it to our project from the command line:
npm install --save-dev alpinejs
Now we need to update .eleventy.js
with this to the function that passes things through Alpine.js:
eleventyConfig.addPassthroughCopy({
"./node_modules/alpinejs/dist/alpine.js": "./js/alpine.js",
});
Lastly, we’ll open up _includes/default.njk
and add Alpine.js right before the closing tag:
<script src="/js/alpine.js?v={% version %}"></script>
We can check if Alpine is working by adding this to index.njk
:
{% extends "_includes/default.njk" %}
{% block title %}It does work{% endblock %}
{% block content %}
<div class="fixed inset-0 flex justify-center items-center">
<div>
<span class="text-change">Good design</span><br/>
<span class="change">is<br/>as little design<br/>as possible</span><br/>
<span x-data="{message:'🤖 Hello World 🤓'}" x-text="message"></span>
</div>
</div>
{% endblock %}
Launch the project:
npm run start
If Alpine.js works, you’ll see “Hello World” in your browser. Congratulations, times two! ??
I hope you can see how quick it can be to set up an Eleventy project, including integrations with Nunjucks for templating, Tailwind for styles and Alpine.js for scripts. I know working with new tech can be overwhelming and even confusing, so feel free to email me at csstricks@gregwolanski.com
if you have problems starting up or have an idea for how to simplify this even further.
The post An Eleventy Starter with Tailwind CSS and Alpine.js appeared first on CSS-Tricks.