Hi and thanks for 11ty :) I'm slowly getting into it since yesterday. I come from metalsmith which allows basically total control of output, at the cost of basically total configuration haha.
My question is: is it possible to match a directoy inside our input directory to another directory when generated in _site? Kinda like the possibility to do this for passthrough copy, but for processed files.
My use case is, I have a content folder inside my input, and I want to define in one place that content is generated in _site instead of _site/content.
I tried to define stuff via the eleventy config, via global data files, directory-specific data files⦠without luck for now. So I didn't find any way to do this but maybe I'm wrong? Thanks for your help!
_Here are a few more details:_
I want my project's directory structure to totally put apart "content files" and other ones. But I still want some "non-content files" to be processed via 11ty, so I don't want them in the content folder.
Kinda like this:
.
βββ _build
βΒ Β βββ css.11ty.js
# ^ this uses _includes/css/style.css and generates _site/css/style.css
# via 11ty processing and custom permalink
# (same principle as in https://github.com/philhawksworth/eleventyone)
βββ content
βΒ Β βββ articles
βΒ Β βΒ Β βββ hello-world.md
βΒ Β βββ index.njk
βββ _data
βββ _includes
Β Β βββ css
Β Β βΒ Β βββ _article.css
Β Β βΒ Β βββ _breadcrumbs.css
Β Β βΒ Β βββ style.css
Β Β βββ js # this is copied in _site as is via passthrough copy
Β Β βΒ Β βββ script.js
Β Β βββ templates
Β Β βββ layouts
Β Β βΒ Β βββ article.njk
Β Β βΒ Β βββ base.njk
Β Β βββ breadcrumbs.njk
The eleventy config matching this for now is:
module.exports = function(eleventyConfig) {
eleventyConfig.addPassthroughCopy({"_includes/js": "js"});
return {
templateFormats: ["md", "njk", "11ty.js"],
dir: {
input: ".",
includes: "_includes",
data: "../_data",
output: "_site",
}
}
};
Eleventy generates a _site folder like this:
_site
βββ content
βΒ Β βββ articles
βΒ Β βΒ Β βββ hello-world
βΒ Β βΒ Β βββ index.html
βΒ Β βββ index.html
βββ css
βΒ Β βββ style.css # via the processing of _build/css.11ty.js that sets its own permalink
βββ js
βββ script.js # via passthrough copy
But I want this:
_site
βββ articles
βΒ Β βββ hello-world
βΒ Β βββ index.html
βββ css
βΒ Β βββ style.css
βββ js
βΒ Β βββ script.js
βββ index.html
My "solution" for now is to set content as my input and create a symlink of external folders in it, like this:
module.exports = function(eleventyConfig) {
eleventyConfig.addPassthroughCopy({"_includes/js": "js"});
return {
templateFormats: ["md", "njk", "11ty.js"],
dir: {
input: "content",
includes: "../_includes",
data: "../_data",
output: "_site",
}
}
};
.
βββ _build
βββ content
βΒ Β βββ .do-not-touch
βΒ Β βΒ Β βββ _build -> ../../_build
βΒ Β βββ articles
βΒ Β βΒ Β βββ hello-world.md
βΒ Β βββ index.njk
βββ _data
βββ _includes
Knowing that the files in _build set their own permalink manually, it works great.
I'd be happy if there was a cleaner way to do this :)
Jekyll may be good inspiration on this one.
In it's config, you can set permalinks for specific collections like so:
collections:
pages:
output: true
permalink: /:path
implementation:
output: true
permalink: /:collection/:path/
A pass-through for processed files sounds like a great idea.
You can do this with permalinks: https://www.11ty.dev/docs/permalinks/
Eg if you have this:
βββ articles
β βββ article-1.md
β βββ article-2.md
By default you get:
βββ _site
β βββ articles
β β βββ article-1/index.html
β β βββ article-2/index.html
To change the default output /articles/article-i/index.html to just /article-i/index.html, like this:
βββ _site
β βββ article-1/index.md
β βββ article-2/index.md
Add a file articles.json inside the articles folder that changes the permalink:
{
"permalink": "{{ page.fileSlug }}/index.html",
"layout": "layouts/article.njk", <-- optional
"tags": ["articles"], <-- optional
}
That's all!
Here you have the list of the page variable contents (in case you want to use something else than fileSlug): https://www.11ty.dev/docs/data-eleventy-supplied/#page-variable-contentshttps://www.11ty.dev/docs/data-eleventy-supplied/#page-variable-contents
The solution from @AlbertVilaCalvo is correct, but works only for folders one level deep, like in the example provided.
If you have deeper folder tree and want to move it up to the tree by dropping one folder, page.fileSlug won't work for you because it return only the slug of the file, not the whole path. The solution is to use page.filePathStem and remove nondesired paths from it.
If you have this folder stucture:
βββ content
β βββ articles
β β βββ hello-world.md
β βββ index.njk
And want instead of this:
βββ content
β βββ articles
β β βββ hello-world
β β βββ index.html
β βββ index.html
to have this:
βββ articles
β βββ hello-world
β βββ index.html
Add a file content.json to the content folder with this content:
{
"permalink": "{{ page.filePathStem | dropContentFolder }}/index.html"
}
And you have to write the dropContentFolder filter that recieves the full path to the current file and removes /content from it. The quick and dirty implementation can be (in .eleventy.js):
config.addFilter("dropContentFolder" function (path) {
const pathToDrop = "/content"
if (path.indexOf(pathToDrop) !== 0) {
return path
}
return path.slice(pathToDrop.length)
})
Most helpful comment
You can do this with permalinks: https://www.11ty.dev/docs/permalinks/
Eg if you have this:
By default you get:
To change the default output
/articles/article-i/index.htmlto just/article-i/index.html, like this:Add a file
articles.jsoninside thearticlesfolder that changes the permalink:That's all!
Here you have the list of the
pagevariable contents (in case you want to use something else thanfileSlug): https://www.11ty.dev/docs/data-eleventy-supplied/#page-variable-contentshttps://www.11ty.dev/docs/data-eleventy-supplied/#page-variable-contents