Open CalvinAllen opened 4 years ago
I had a similar requirement.
In the end I created several utility scripts, which enabled me to put images next to the related post. These images could be accessed via a custom media(page)
filter, which rewrote the images path to the final path. Another script copied all assets from src/posts/
.
With this directory layout:
src/posts/
/some-title/
/index.html
/cover.png
/image.jpg
/good-title/
/index.html
/cover.png
The posts get resolved this way:
dist/posts/
/some-title/
/index.html
/good-title/
/index.html
And the assets get copied this way:
dist/assets/media/
/some-title/
/cover.png
/image.jpg
/good-title/
/cover.png
In order to resolve the (relative) images, an extra filter
is needed:
// .eleventy.js
module.exports = function (config) {
config.addFilter(`media`, (filename, page) => {
// filename: 'image.jpg'
// page.inputPath: './src/posts/some-title/index.md',
// want: '/assets/media/some-title/image.jpg',
if (!page.inputPath.split(`/`).includes(`posts`)) {
return filename;
}
const path = require(`path`);
const subdir = path.basename(path.dirname(page.inputPath));
return `/assets/media/${subdir}/${filename}`;
});
// further config...
}
Call the media(page)
filter in your markdown:
// src/posts/some-title/index.md
<figure class="wide">
<img src="{{ 'image.jpg' | media(page) }}" alt="some blog image" loading="lazy">
<figcaption>
Some image caption.
</figcaption>
</figure>
Use this script to copy the assets from your posts (you might call it with postbuild
in package.json
.)
// _utils/copy.js
const fs = require(`fs`);
const path = require(`path`);
const fastglob = require(`fast-glob`); // 11ty uses `fast-glob` internally
async function copy() {
const base = `src/posts`;
const entries = await fastglob([`**/*.{jpg,jpeg,png,gif,webp,mp3,mp4,webm,ogg}`], { cwd: base });
for (const entry of entries) {
const src = path.join(base, entry);
const dst = path.join(`dist/assets/media`, entry);
await fs.promises.mkdir(path.dirname(dst), { recursive: true });
await fs.promises.copyFile(src, dst);
}
}
copy().catch(console.error);
I had the same issue in the beginning (also coming from Jekyll and the jekyll-postfiles
plugin), and instead of adding computing to get the expected result, I chose to adapt to Eleventy's default behavior as much as possible.
I changed my source folders hierarchy so that it matches the build hierarchy, which means I don't need any permalink
, and used the standard addPassthroughCopy
for all images.
I had to reorganize my content in the beginning, but now it works perfectly, and i didn't add any complexity or build time.
I had the same issue in the beginning (also coming from Jekyll and the
jekyll-postfiles
plugin), and instead of adding computing to get the expected result, I chose to adapt to Eleventy's default behavior as much as possible.I changed my source folders hierarchy so that it matches the build hierarchy, which means I don't need any
permalink
, and used the standardaddPassthroughCopy
for all images.I had to reorganize my content in the beginning, but now it works perfectly, and i didn't add any complexity or build time.
@nhoizey This is a totally fine and a very hassle-free approach, which I very much prefer! But then again comes my client and wants their preferred workflow and that's when one goes down the rabbit hole 😅
@denisbrodbeck indeed, clients not always allow us making simple things… 😅
I just made this plugin to solve this limitation https://www.npmjs.com/package/eleventy-plugin-page-assets
I had to reorganize my content in the beginning, but now it works perfectly, and i didn't add any complexity or build time.
If you’re making & writing a blog over time, a big problem in matching build output with src input is that you’re forced into one of two unfortunate situations:
src/post
paths don’t include dates, they will look okay in permalinks, but will be more unorganized and harder to deal with over time, in a writing workflow.src/post
paths do have dates, then so will permalinks on the website, making these links more ugly and more hostile to visitors, sharing, etc.Instead, it’s very nice to have dated paths in the src, and custom permalinks for site URLs. This is probably a big reason 11ty supports permalinks in the first place. So, extending that to assets used in posts seems like a natural and important feature.
* If `src/post` paths _do_ have dates, then so will permalinks on the website, making these links more ugly and more hostile to visitors, sharing, etc.
This is not exactly true, as 1 very good point with Eleventy you can do whatever you need! I have a starter template where I wanted to "solve" that exact problem: ECBS It's just an idea!
This is not exactly true, as 1 very good point with Eleventy you can do whatever you need!
Part of what makes me interested in 11ty is that this does seem to be the case! However, I’m just somewhat confused on how to do this, as a newcomer.
Placing images next to posts & controlling permalinks seem like things that shouldn’t be too difficult, but I’m not exactly sure where to start. ECBS seems promising, but didn’t build quite as I expected it to (https://github.com/TigersWay/eleventy-classic-blog-starter/issues/1).
Thanks for pointing out that there might be an existing solution!
Got here by looking for a way to copy a central, shared asset folder to each output folder. Anyone got an idea and is willing to nudge me in the right direction? Goal is to create self-contained output folders that contain no relative links leading outside of that folder, allowing the folder to be moved around at will.
Sorry for bringing this up again.
I have transferred multiple projects to Eleventy—and it was a joy!
Yet, some teaching projects (made with Jekyll or Hugo) have a structure like the one mentioned in @CalvinAllen’s initial post with dozens of files in each article folder.
For these projects Eleventy does not seem an option, yet, although keeping articles and assets together in one folder makes perfect sense and is supported by many SSGs.
Would it make sense to address this issue before a 1.0 release of Eleventy? This would allow to switch projects to Eleventy without changing a complex folder structure.
@arrowtype a late answer:
- If
src/post
paths do have dates, then so will permalinks on the website, making these links more ugly and more hostile to visitors, sharing, etc.
I disagree. I love to see dates in URLs, as it allows me to decide if I want to load the page or forget it because it's too old.
I also love being able to navigate "up" in the content hierarchy by removing the article slug from the URL and having the list of content from the same month.
For example, if I'm in https://nicolas-hoizey.com/articles/2018/07/02/leaving-500px/ , I can remove leaving-500px/
from the URL in the browser, and get all articles from July 2018 (I don't write enough these days… 😅) or remove 07/02/leaving-500px/
to get all articles from 2018.
Is it possible to customize the pass-through copy when the output directory is NOT the same as the source directory when using explicit permalinks?
I have a Jekyll blog I'm working on converting, but I'm running into an issue (one that I solved with a custom Jekyll plugin), and my structure looks like this:
Dates are not part of my permalinks, which ends up only being the 'some-blog-post-title'. The custom plugin I have copies that 'cover.png' to the proper output folder. I end up with something like this:
Coming to Eleventy, I have to specify a slug + permalink to get the output structure the same (okay, no big deal), but with all the normal passthrough options, I end up retaining the dated folders from the original.
I want to, somehow, use the source directory during the build combined with the permalink of the item its building, to copy the specific assets along with the rendered output.
Any way to do this?
Thanks!