Expose input, root, source, config path to plugins
MangelMaxime opened this issue · comments
Is your feature request related to a problem? Please describe.
I am working on an Eleventy plugin which aims to provide an ready out of the box template for Eleventy.
In order, to do that I need to know where the root project is so I can copy includes
files in it.
My problem is that Eleventy doesn't expose all the information it has to the plugins.
For example, if I use the programmatic API (mainly for the tests) then the provided input path is never exposed to the plugin.
const elev = new Eleventy("./fixtures/menu-2/", "./fixtures/menu-2/_site", {
configPath: "./fixtures/menu-2/.eleventy.js",
});
This means that the plugin only knows of the process.cwd()
but not where the input files are located.
The same problem exist if when using the CLI the user provides an input argument.
Describe the solution you'd like
It would be nice if Eleventy was exposing more information to the plugin.
List of information I have in mind:
- input
- root
- destination
- config path
Describe alternatives you've considered
I tried to find another way to find the input path but I could not do that.
Additional context
No response
Your 3 best bets are:
- Events https://www.11ty.dev/docs/events/#event-arguments
- Env variables https://www.11ty.dev/docs/environment-vars/#eleventy-supplied
eleventy
global data: https://www.11ty.dev/docs/data-eleventy-supplied/#eleventy-variable
The other thing I would mention is that:
module.exports = function(eleventyConfig) {
eleventyConfig.addPlugin(eleventyConfig => {
// eleventyConfig.dir has the resolved values from the config file
});
};
I don't know why, in the past I was under the impression that events listener where not awaited. This could lead to a situation where the files where not yet copied. But it seems to be ok now.
I was able to kind of workaround my problem using:
function configFunction(eleventyConfig: any, options?: Options) {
let isFirstBuild = true;
eleventyConfig.on("eleventy.before", async (args : any) => {
if (isFirstBuild) {
isFirstBuild = false;
copyIncludesToUserFolder(args);
}
});
}
Args contains the following value:
{
inputDir: './fixtures/navigation-3/',
dir: { input: '.', includes: '_includes', data: '_data', output: '_site' },
runMode: 'build',
outputMode: 'json',
incremental: false
}
where inputDir
seems to match the path I give to Eleventy via
const elev = new Eleventy(
"./fixtures/navigation-3/",
"./fixtures/navigation-3/_site",
{
configPath: "./fixtures/navigation-3/.eleventy.js",
}
);
I still don't have access to the root
path computed by Eleventy but it seems like I can use the current working dir and the inputDir
to replicate it.
inputDir
is not documented on https://www.11ty.dev/docs/events/#eleventy.before. Is the documentation not update to date or should inputDir
not be accessible?
I think the inconsistency here is limited to CLI arguments not being reflected in those configuration values—work is moving forward to fix that in #2729.
I don’t think inputDir
is what you want there.
given the following config object return:
return {
dir: {
input: "myinput",
output: "myoutput",
}
};
it yields the following values in 2.0.0-beta.3:
[inside addPlugin] {
data: '_data',
includes: '_includes',
input: 'myinput',
output: 'myoutput'
}
[argument to eleventy.before] {
dir: {
data: '_data',
includes: '_includes',
input: 'myinput',
output: 'myoutput'
},
incremental: false,
inputDir: '.',
outputMode: 'fs',
runMode: 'build'
}
That looks correct to me. If you’re also using CLI arguments, I think home base for that is #2729
I don’t think
inputDir
is what you want there.
Indeed using inputDir
is a workaround because I don't have access to `eleventy.env.root.
What I am looking for is the absolute path for the includes
folder.
The way I had in mind to access it was to access the root
path and then join includes
path to it.
But because I don't have access to the root path from the plugin, what I am doing right now is:
export function copyIncludesToUserFolder(args : EleventyBeforeEventArgs) {
const includesDir = args.dir.includes;
const destination = path.join(process.cwd(), args.inputDir, includesDir, "nacara");
// ...
}
function configFunction(eleventyConfig: any, options?: Options) {
let isFirstBuild = true;
eleventyConfig.on("eleventy.before", async (args : any) => {
if (isFirstBuild) {
isFirstBuild = false;
copyIncludesToUserFolder(args);
}
});
// ...
}
what command do you use to run Eleventy?
@zachleat It depends.
When consuming Eleventy as a user (to build a site) I run npx @11ty/eleventy
.
But I am also writing unit tests and in this case, I use the AVA test framework and Eleventy programmatic API:
const elev = new Eleventy(
"./fixtures/navigation-4/",
"./fixtures/navigation-4/_site",
{
configPath: "./fixtures/navigation-4/.eleventy.js",
}
);
const json = await elev.toJSON();
The project, I am working on is https://github.com/MangelMaxime/eleventy-layout-nacara.
It is still in WIP, but the idea is to provide a plug-in-play solution to had a ready to use layout to an Eleventy project.
The user just need to add eleventyConfig.addPlugin(eleventyLayoutNacara);
to their configuration, and then they get access to ready to use layouts, components and filters.
The way it is archived for the layouts and components, is that when Nacara plugin is loaded it will copy these files under <root>/_includes/nacara
so the user can access the layouts by adding layout: nacara/layouts/docs.njk
to their Markdown files.
Thank you for taking the time to look at my issue, I am aware that I am probably pushing the plugin system of Eleventy a bit far :)
I'm now also using process.cwd()
to find the path to the project root from inside a plugin.
@MangelMaxime I think you should join the discussion in this other issue: