Closed jakearchibald closed 10 months ago
I'd expect the same...
I doubt the same happens if using a separate .11tydata.js
file instead of JS front-matter.
The docs say
The directory name of the current module. This is the same as the path.dirname() of the __filename.
Could you use process.cwd()
instead?
Could you use
process.cwd()
instead?
No that's a different thing.
I doubt the same happens if using a separate
.11tydata.js
file instead of JS front-matter.
In .11tydata.js
files, __filename
and __dirname
are relatively to the .11tydata.js
file (as expected). It also works as expected in ejs files.
Hmm …
The only reference for gray-matter
is https://github.com/11ty/eleventy/blob/f2de24821b47dfbeef1fff9716d4f442bb93060a/src/TemplateContent.js#L72
So …
The directory name of the current module.
Would be the gray-matter lib at that time (because it is parsing the frontmatter at that point).
@jakearchibald What do you want to do with the __dirname
?
Could https://github.com/11ty/11ty.io/issues/33 be related here?
Maybe the eleventy-base-blog could give you some starters as well.
@jakearchibald Thinking more about it, I wonder if you'd be better off explicitly defining front-matter (or probably more likely template/directory data), just in case you end up changing your structure in the future. Seems a little cumbersome at first, but you may end up with separate directories that share parts of your layout css that you might prefer to reuse vs ending up having to duplicate something from your "layout chain" or code up exceptions to your lookups related to your current-template. (Just thinking out loud here)
(I'm assuming your other issue is related, but please feel free to correct me and/or provide more context.)
Gonna have to think on this one a bit.
This is what __filename
(and relatedly __dirname
) are resolving to here: https://github.com/jonschlinkert/gray-matter/blob/master/lib/engines.js#L39
Looks like the JS front matter parsing does an eval in our dependency (gray-matter
).
Somewhat relatedly, I did add the option to do custom front matter engines in the next version (see https://www.11ty.io/docs/data-frontmatter/#example%3A-using-toml-for-front-matter-parsing for a TOML example)
Related docs has a nice example: https://nodejs.org/api/modules.html#modules_filename
Given two modules: a and b, where b is a dependency of a and there is a directory structure of:
/Users/mjr/app/a.js /Users/mjr/app/node_modules/b/b.js
References to __filename within b.js will return /Users/mjr/app/node_modules/b/b.js while references to __filename within a.js will return /Users/mjr/app/a.js.
@jakearchibald when you say:
It also works as expected in ejs files.
Can you provide a sample of a working ejs file test? In my local tests it’s still resolving to that gray matter node_modules path.
Sorry, I meant in ejs templates, not in grey matter. So the test would be <%= __dirname %>
I think a possible solution for this is to pass the currently rendered path into matter from here by overwriting the original JS engine in gray-matter via the options.engine.javascript
argument to something like this:
{
parse: function parse(str, options, wrap) {
/* eslint no-eval: 0 */
try {
if (wrap !== false) {
const injections = {
__filename: this.inputPath,
__dirname: this.inputDir
};
str = `(function() {
${
[...Object.entries(injections)]
.map(([key, value]) => `let ${key} = ${value};`)
.join('\n')
}
return ${str.trim()};
}());`;
}
return eval(str) || {};
} catch (err) {
if (wrap !== false && /(unexpected|identifier)/i.test(err.message)) {
return parse(str, options, false);
}
throw new SyntaxError(err);
}
},
stringify: function() {
throw new Error('stringifying JavaScript is not supported');
}
}
The code above is not the nicest way to write it, but hopefully gets my point across.
I think this is the only place where you can actually do this, because outside of this you don't have access to the currently rendering path and the matter parser.
This also means that this doesn't work of a user decides to override the config.frontMatterParsingOptions
.
The only alternative right now that I see is monkeypatching some 11ty attribute into the gray-matter options, which a custom matter engine can extract again. That would at least allow for users to use their own parsing engine and enable further injections in the future.
As things are moving towards ESM long term, I don’t think we’ll probably tackle this directly.
https://nodejs.org/dist/latest-v20.x/docs/api/esm.html#no-__filename-or-__dirname
I would have expected our new node
front matter format to have access to __filename
though (as it isn’t fully ESM), but in testing it doesn’t look like Node’s vm
module has __filename
either. That’s okay, it’ll save us some headache later when the ESM version of vm
is stable.
HOWEVER, in working on #2819 there is one some small change to your comment @Snapstromegon:
filePath
in the options object there now (3.0+). This is used by gray-matter. https://github.com/11ty/eleventy/blob/fbfbd4365dbd2fe6c16bfd3e8aad3c6e205ac69e/src/TemplateContent.js#L179All of that said, I’ll make a change to the node
front matter format to make page.inputPath
available (per Eleventy conventions). Noting also (taking a 10000 foot view), that page.inputPath
is the cross-template syntax Eleventy convention to access the file name inside of a template.
https://www.11ty.dev/docs/data-eleventy-supplied/#page-variable
Just to be clear, in Eleventy 3.0 you’ll be able to (nunjucks/liquid template):
---js
let whatever = page.inputPath;
---
{{ whatever }}
I would expect
whatever
to be the directory of the current template, but it's…node_modules/gray-matter/lib
.