NightlyCommit / twing

First-class Twig engine for Node.js
BSD 2-Clause "Simplified" License
199 stars 23 forks source link

Support request re: using the `drupal-attribute` class as an async Twing function #535

Open philwolstenholme opened 3 years ago

philwolstenholme commented 3 years ago

I'm trying to use Twing in Storybook to demonstrate Twig templates that will be used on a Drupal 9 site.

I am using Twing 5.0.2 and twing-loader 0.5.5.

In my environment file I am defining a create_attribute function like this:

const drupalAttribute = require('drupal-attribute');

const createAttribute = new TwingFunction('create_attribute', () =>
  return Promise.resolve(new drupalAttribute()),
);

const environment = new TwingEnvironment(loader, { autoescape: false });
environment.addFunction(createAttribute);

module.exports = environment;

new drupalAttribute() is a class that comes from @ericmorand 's https://github.com/ericmorand/drupal-attribute package.

This package and approach worked perfectly in Twing 2 when functions did not return Promises:

// This is how I did it with Twing 2:
const createAttribute = new TwingFunction('create_attribute', function() {
  return new drupalAttribute();
});

So I am wondering if the async nature of Twing 5 is what is tripping me up?

My templates are rendering, but with no attributes, so I know I am doing something wrong. There's no TwingErrorSyntax: Unknown "create_attribute" function error though. It looks like my create_attribute function can be found, but it is not usable by the templates because of how I have set things up at the moment.

My templates are pretty basic, they look like this sort of thing:

{% set attributes = attributes|default(create_attribute()) %}
{% set attributes = attributes.addClass(['btn']) %}

<button {{ attributes }}>Stripped down example</button>

Twing and using the JavaScript version of create_attribute() is new to me and I have a feeling I'm doing something silly. Is Promise.resolve(new drupalAttribute()), likely to work or am I being over optimistic here? I read something about classes not being callable? I know this isn't a Twing issue (sorry) but I wondered if anyone here had encountered the same issue, especially as Eric is also a Twing maintainer.

Other things I have tried

const createAttribute = new TwingFunction('create_attribute', () => {
  const create_attribute = new drupalAttribute();
  return Promise.resolve(create_attribute);
});
const createAttribute = function() {
  return Promise.resolve(() => {
    return new drupalAttribute();
  });
};

environment.addFunction(new TwingFunction('create_attribute', createAttribute));
const createAttribute = async () => await new drupalAttribute();
philwolstenholme commented 3 years ago

I've just spotted https://github.com/ericmorand/drupal-attribute/issues/9#issuecomment-816561929 but not sure if that helps with using drupal-attribute in a function that needs to be async/return a resolved promise?

ericmorand commented 3 years ago

What is the result that you get and what is your expected result? What you did looks fine to me.

philwolstenholme commented 3 years ago

Hi @ericmorand, thank you for replying even at the weekend, I really appreciate it.

So, if we use this example:

{% set attributes = attributes|default(create_attribute()) %}
{% set attributes = attributes.addClass(['btn']) %}

<button {{ attributes }}>Stripped down example</button>

Then the expected result would be:

<button class="btn">Stripped down example</button>

However, the result I am getting has no attributes at all:

<button>Stripped down example</button>

Would it be helpful if I could make you a CodeSandbox or a Git repo with a stripped back example?

I opened up the drupal-attribute class and added a debugger; line to the constructor/init method and also to the toString and addClass methods, but the breakpoints were never reached.

philwolstenholme commented 3 years ago

I wonder if it's the |default filter causing the issue? Although, the same template works fine with Twing 2, which is what made me think the async/promises nature of Twing 5 might be the issue. When I switch between Twing 5 and Twing 2 (and change Promise.resolve(new drupalAttribute()) to return new drupalAttribute()) then I get the expected result.