posthtml / posthtml-expressions

Use variables, JS-like expressions, and even markup-powered logic in your HTML.
Other
123 stars 20 forks source link

locals can only be JSON string #70

Closed cossssmin closed 4 years ago

cossssmin commented 4 years ago

Consider {{ title }} is a string equal to test.

<!-- include.html -->
<p>The title in the include is: {{ title }}</p>
<!-- test.html -->
<p>The title is: {{ title }}</p>
<include src="include.html" locals="{{ title }}"></include>

Result: SyntaxError: Unexpected token { in JSON at position 1

These won't work, either:

<include src="include.html" locals=locals='{"title": {{ title }} }'></include>

<include src="include.html"  locals='{{ {"title": title } }}'></include>

<include src="include.html"  locals='{"title": title }'></include>

Would be awesome if you could pass expressions variables inside the locals="" attribute - sometimes you need to pass in something that has a dynamic/computed value, so you can't write it out by hand.

Any ideas?

cossssmin commented 4 years ago

If there is a solution to this, we could also apply it to posthtml-modules, since its locals functionality is basically ported from this plugin.

Scrum commented 4 years ago

I think that attribute interpolation is not implemented https://github.com/posthtml/posthtml-include/blob/45330d22b6a46558551afac0241377fdd3ae2543/index.js#L26

you also need some kind of scope that is visible in this space

cossssmin commented 4 years ago

I was looking at fixing this today, but ran into development issues with the plugin.

Would you accept a PR that refactors the code using the same style as other plugins? Specifically, using ava/xo, as well as modern code where applicable.

Scrum commented 4 years ago

Would you accept a PR that refactors the code using the same style as other plugins? Specifically, using ava/xo, as well as modern code where applicable.

You can feel bolder in relation to PR, I really appreciate any contributions that prevent the project from stagnating

cossssmin commented 4 years ago

Went back to try fixing this issue, now that we've updated the plugin, but I'm afraid I don't know how to do it. Can you please help? We basically need to evaluate the value of the locals="" attribute. Just as posthtml-expressions evaluates with="" attributes for <scope> tags, I suppose?

Scrum commented 4 years ago

@cossssmin Hi, could you please throw tests or examples so that I can concentrate on the solution, unfortunately I lost a little the essence of the problem ))

cossssmin commented 4 years ago

Hey!

Not sure how to write the test, but I'll try to describe an example using posthtml-fetch.

Imagine you have a variable in context, like it is the case with response in posthtml-fetch:

<fetch url="...">
  {{ response }} 
</fetch>

As you know, we can use {{ response }} to render that variable.

But what happens if you want to pass the entire response variable down to an <include>?

<fetch url="...">
  <include src="some-file.html" locals="response"></include>
</fetch>

This will not work, as currently locals is only treated as a JSON string, and parsed with JSON.parse - so it will throw an error.

The idea is that you should be able to pass a variable inside an attribute, just as you do it with the <scope> tag in posthtml-expressions, where the contents of the with="" attribute are evaluated in context.

Does that make sense?

Scrum commented 4 years ago

@cossssmin Hello, thanks, it became I caught the direction

Scrum commented 4 years ago

@cossssmin I tried to understand the reason for a long time and finally found it #71

Scrum commented 4 years ago

@cossssmin publish v1.3.2, The only thing that needs to be done since execution of plugins is asynchronous, you need to finish the option after, before in posthtml-fetch which will add plugins before and after the expression plugin Screenshot 2020-04-10 at 13 32 42

cossssmin commented 4 years ago

Awesome, will have a look and get back to you. Will also need to implement this somehow in posthtml-modules ('somehow' because it's not using the same codebase...)

cossssmin commented 4 years ago

Hmm, just tried this with posthtml-include and it still fails?

<!-- page is an object I already have -->
<include src="footer.html" locals="page">
<!-- footer.html -->
<div>Copyright {{ year }}</div>
SyntaxError: Unexpected token p in JSON at position 0 at JSON.parse

Note: let's leave posthtml-fetch aside for a moment. The above is just using the extend, expressions and include plugins, like so:

const config = { /* an object I already have */ }

posthtml([
    require('posthtml-extend'),
    require('posthtml-include'),
    require('posthtml-expressions')({ locals: { page: config } }),
    ...posthtmlPlugins
  ])
    .process(html)
    .then(result => result.html)
Scrum commented 4 years ago

@cossssmin Yes, in this case, you need to check whether the string is of the form json,

the correct result for you then will be

<div>Copyright undefined</div>
cossssmin commented 4 years ago

I'm not sure I understand, how can someone pass in that page object to that include?

These won't work, either:

<include src="footer.html" locals="{{ page }}">

<include src="footer.html" locals='{"page": page}'>

The idea is to be able to pass in locals dynamically.

In my example, page.year is set dynamically, so I can't write it by hand every time I add an include.