jan 06, 2025
🔗 Serve static files with Eleventy
Eleventy is a static site generator that can be configured to do everything that you can imagine. A nice addition for a technical blog can be to serve static files. This is useful when you want to include files like PDFs, or downloadable code snippets in your project. This was a research needed to make the code-sandbox web component fetch files correctly.
The first tool to reach to in this case, is Passthrough File Copy, the Eleventy utility that allows you to copy files from the input directory to the output directory, otherwise Eleventy will ignore all non-templates files.
eleventyConfig.addPassthroughCopy("content/posts/*/**/*.{js,pdf}");
This command allow you to put the files directly in your posts directory and Eleventy will copy them to the output directory while preserving the same directory structure.
🔗 Bundling with Vite
Vite is the most recommended bundling tool for Eleventy and this blog too has been originally setup to use Vite to run after the Eleventy build, using the official Eleventy plugin eleventy-plugin-vite.
This works very well for quickly setting up a feature-rich development environment, because its default configuration provides a lot of features out-of-the-box, like asset hashing, tree-shaking, and of course, bundling and minification of JavaScript and CSS files.
However, in case you want to serve static files the Vite step can silently work against you, since Vite will remove all files which are not linked in the outputted html files or hash and move, usually in the /asset folder, the rest of the files during in the production build, and this can break the links to the files in your posts.
After a tedious debug to figure out which was the issue, a possible solution is funnily another Vite unsolicited feature, the public directory. Maybe it's not widely known that Vite by default will copy the files in the public directory to the output directory without touching them, and it will also flat the /public directory structure in the project root.
public
├── assets
│ └── pdf.pdf
└── og-image.png
The above will be transformed to this:
dist
├── assets
│ └── pdf.pdf
└── og-image.png
To take advantage of this feature, you can copy all the static files to the /public/asset directory, which Vite will then move to the root output directory leaving only the existing /asset folder.
eleventyConfig.addPassthroughCopy({
"content/posts/*/**/*.{js,pdf}": "public/assets",
});
I can then link the files in the markdown files like this:
[Download PDF](demo.pdf)
And transform the link in the final HTML to point to the correct location with eleventy-plugin-markdown-links:
mdLib.use(markdownItLinks, {
processHTML: true, // defaults to false for backwards compatibility
replaceLink: function (link, env, token, htmlToken) {
if (link.endsWith(".pdf")) {
// add class to the link
const newToken = token;
const newLink = "/assets/" + link;
const title = link.split("/").pop();
newToken.attrs = [
["href", newLink],
["target", "_blank"],
["download", title],
];
return newToken;
}
return link;
},
});
# CSS Icon
To display a nice little icon in front of downloadable files, I added a CSS down arrow to the markdown.css, like this demo.pdf
a[href$=".pdf"]::before {
content: "";
display: inline-block;
background-color: currentColor;
mask-image: url("data:image/svg+xml,%3Csvg ... %3E");
mask-repeat: no-repeat;
mask-size: contain;
}