Open cossssmin opened 1 year ago
Hi Cosmin,
The problem you are facing can be quickly fixed, but there are others issues that need to be solved.
For the error tree.match is not a function
we could just use the same solution used by posthtml-include here https://github.com/posthtml/posthtml-include/blob/master/lib/index.js#L16 where the function match
is added if not defined:
const {match} = require('posthtml/lib/api');
// ...
tree.match = tree.match || match;
I have the same issue with markdown it plugin which I am using, and I have propose here the fix https://github.com/posthtml/posthtml-markdownit/pull/26
However, the main problem is that the async plugin like posthtml-fetch
will not works how currently passed plugins process the tree. I suppose the same issue is with posthtml-extend
but not with posthtml-modules
since it process plugins using Promise.
For fix this I think is required several refactors how the plugin process the tree. Maybe I will check into, but not sure yet when I will get time soon.
There is a solution that I used in this case, it's not ideal, but it works with plugins I tested, including the posthtml-fetch
, is to load the posthtml-fetch
after the posthtml-component
process whole tree.
Example:
const posthtml = require('posthtml')
const fetchPlugin = require('posthtml-fetch')
const components = require('posthtml-component')
posthtml([
components({
root: './',
folders: ['src'],
tagName: 'component',
attribute: 'src',
yield: 'content',
expressions: {strictMode: false},
}),
fetchPlugin()
])
Another thing you need to do for avoid that posthtml-expressions
process the response
local before the fetch plugin is to add @
like below:
<fetch url="https://jsonplaceholder.typicode.com/users/1">
@{{ response.name }}'s username is @{{ response.username }}
</fetch>
In this way after posthtml-component
process whole tree you will get below which can be then processed by posthtml-expressions plugin loaded by fetch plugin.
<fetch url="https://jsonplaceholder.typicode.com/users/1">
{{ response.name }}'s username is {{ response.username }}
</fetch>
It did test and it works also with x-tag inside fetch, example:
<!-- user.html component -->
<script props>
module.exports = {
name: props.name || 'Default name',
username: props.username || 'Default username',
}
</script>
<div>
{{ name }}'s username is {{ username }}
</div>
Usage with fetch:
<fetch url="https://jsonplaceholder.typicode.com/users/2">
<x-user name="@{{ response.name }}" username="@{{ response.username }}"></x-user>
</fetch>
I know it's not ideal, but I hope this will works for you.
The most annoying thing is to prefix the locals with @
.
I will think a bit more about processing async plugins and let you know.
Hmm, I think I've got it working like this, by running posthtml-fetch
before posthtml-component
instead of passing it as a plugin:
posthtml([
fetchPlugin({expressions: {...expressionsOptions, locals}}),
components({
root: './',
folders: ['src/components', 'src/layouts', 'src/templates'],
tagName: 'component',
attribute: 'src',
yield: 'content',
expressions: {...expressionsOptions, locals},
}),
])
.process(html, {...posthtmlOptions})
.then(result => result.html)
Works without having to add @
to expressions in attributes, though in order to ignore them I need to do @@
, like:
<fetch url="https://jsonplaceholder.typicode.com/users/2">
<x-user name="@@{{ response.name }}"></x-user>
</fetch>
... but that might just something on my end, not sure yet.
But yeah, would be cool to be able to just pass posthtml-fetch
as a plugin to posthtml-component
. Regarding this, I've also noticed the tree.render
method needs setting as well, in addition to tree.match
.
But if you pass fetch plugin before components, then <fetch>
tag inside nested components will not be processed.
I mean if you have a page like:
<html>
<body>
<!-- This fetch tag will be processed -->
<fetch url="https://jsonplaceholder.typicode.com/users/2">
<x-user name="@@{{ response.name }}"></x-user>
</fetch>
<!-- If this component has a fetch tag it will not be processed -->
<x-component-with-fetch> </x-component-with-fetch>
</body>
</html>
A solution for this is to load before and after the component plugin like:
posthtml([
fetchPlugin({expressions: {...expressionsOptions, locals}}),
components({
root: './',
folders: ['src/components', 'src/layouts', 'src/templates'],
tagName: 'component',
attribute: 'src',
yield: 'content',
expressions: {...expressionsOptions, locals},
}),
fetchPlugin({expressions: {...expressionsOptions, locals}}),
])
.process(html, {...posthtmlOptions})
.then(result => result.html)
But I think is just enough one time after the component.
Works without having to add @ to expressions in attributes, though in order to ignore them I need to do @@, like:
The only reason for this could be that somewhere in the code the expressions plugin process twice the locals, so first time it remove the @
and second time it process it again by another plugin that use expression plugin. Make sense?
Another solution for avoid to use @
is to set custom delimiter only for fetch plugin, example:
fetchPlugin({expressions: {delimiters: ['[[', ']]'], locals}}),
Then:
<fetch url="https://jsonplaceholder.typicode.com/users/2">
<x-user name="[[ response.name ]]"></x-user>
</fetch>
This way the locals inside fetch plugin will be only processed by expression plugin initialized by fetch.
But yeah, would be cool to be able to just pass posthtml-fetch as a plugin to posthtml-component.
Yes that would be the best solution. I regret that I didn't do this before, but I remember that I had some issues when I tried. Will check again.
Regarding this, I've also noticed the tree.render method needs setting as well, in addition to tree.match.
Not sure what you mean, which setting need?
Maybe I got what you mean. I think this could be fixed like for match:
const render = require('posthtml-render');
// ...
tree.render = tree.render || render;
But maybe the best solution would be just to fix this in posthtml-component plugin by wrapping tree in posthtml()
function, something like posthtml-modules is doing here https://github.com/posthtml/posthtml-modules/blob/master/index.js#L125
Not sure what you mean, which setting need?
Similar to your solution in posthtml-markdownit
, otherwise it's also undefined
.
Not sure what you mean, which setting need?
Similar to your solution in
posthtml-markdownit
, otherwise it's alsoundefined
.
Maybe you have missed but I have edited my reply about this.
I think this could be fixed like for match:
const render = require('posthtml-render');
// ...
tree.render = tree.render || render;
But the best solution would be just to fix this in posthtml-component plugin by wrapping tree in posthtml() function, something like posthtml-modules is doing here https://github.com/posthtml/posthtml-modules/blob/master/index.js#L125 Or just set match and render function on tree before next process. I will check into in next days.
Hey, thanks so much for creating this, I'm currently testing it in Maizzle as a replacement for posthtml-modules.
Tried using it with posthtml-fetch:
... but I get a TypeError:
Any way we can get them to work?