dfrankland/react-amphtml

Need to accommodate custom templates

Closed this issue · 7 comments

Not every script tag used by AMP HTML is of custom-element="*", some like amp-mustache use custom-template="*".

https://github.com/ampproject/amphtml/blob/master/extensions/amp-mustache/amp-mustache.md

https://ampbyexample.com/components/amp-mustache/

Hi drfrankland,

I just bumped into the "amp-mustache" Problem you mentioned. Do you have any ideas how you would like to solve this problem? Are you working on this project at the moment?

cheers
Gido

Hello there! There are several different mappings that we'd have to do internally to accommodate this, but nothing too difficult 👍

I am not actively working on this, but I'll try to take a look at this as soon as I have some time. Probably over the next weekend I'll push out this feature.

Any news on support for templates, i.e.:

<amp-list height="24"
      layout="fixed-height"
      src="https://www.ampbyexample.com/json/product.json"
      class="m1">
      <template type="amp-mustache">
        Price: ${{price}}
      </template>
    </amp-list>

I solved it as follows (not ideal, but it works):

MustacheTemplace.tsx:

import * as React from 'react'

export const MustacheTemplate = ({ children, ...attrs }) => (
    <template type="amp-mustache"
      {...attrs}
      dangerouslySetInnerHTML={{ __html: children }}
    />
)

Example usage:

<Amp.List width="auto"
      height="100"
      layout="fixed-height"
      src="/static/data/amp-list-urls.json">
      <MustacheTemplate>
      {`
        <div class="url-entry">
          <a href="{{url}}">{{title}}</a>
        </div>
      `}
      </MustacheTemplate>
</Amp.List>
<Amp.List height="24"
      layout="fixed-height"
      src="https://www.ampbyexample.com/json/product.json"
      class="m1">
      <MustacheTemplate>
      {`
        The Price: \${{price}}
      `}
      </MustacheTemplate>
</Amp.List>

Note the usage of multiline template strings using {` ...`}. Combination ${ can't be used in template strings due to template expandion on ${...}. Escape $ using \ to use this combination.

I think that I've got this much better figured out now. Instead of 1 by 1 adding new features as they get added to AMPHTML, we can generate components that will—at the very least—add a script tag using AMPHTML's own validation rules (amphtml-validator-rules).

Anyone can then start adding components that wrap those to make them more ergonomic. The point of this is to help with AMPHTML components that enhance normal HTML (non-custom amp- components) e.g. <template />.

This will be the start of v3 I believe.

@dfrankland this sounds like a great idea. I'm really searching for the best approach to do component-based design for AMP, where we can use a system like storybook to do develop our components out of context, and use the full spectrum of AMP features. I hope that React can be the way to go - react-amphtml already brings us far in reaching this holy grail. Looking forward to your new approach:-)

This is now available published under react-amphtml@^3.0.0.

Tests for templates can be found here:

it('renders amp-html extensions, and generates script tags', () => {
const ampScripts = new AmpScripts();
render((
<AmpScriptsManager ampScripts={ampScripts}>
<div>
<Amp.AmpYoutube something="blah" />
<Amp.AmpAccordion something="blah" />
<Amp.Template specName="default" type="amp-mustache">
Hello, {'{{world}}'}!
</Amp.Template>
</div>
</AmpScriptsManager>
));
const ampScriptElements = ampScripts.getScriptElements();
const wrapper = mount(<div>{ampScriptElements}</div>);
expect(wrapper.find('[custom-element]').length).toEqual(2);
expect(wrapper.find('[custom-template]').length).toEqual(1);
expect(wrapper.find('script').length).toEqual(4);
});

An example is already live at https://ampreact-szogszfmrw.now.sh/
Source for the example here:
https://github.com/dfrankland/ampreact/blob/416c060dbb29ac10c1a2ed26337b81e1d503e239/pages/index.js#L109-L141