react-amphtml

repository·master·Indexed 40 days ago

https://github.com/dfrankland/react-amphtml

A library for using AMP (Accelerated Mobile Pages) components within React applications. It provides React wrappers for AMP directives, handles boilerplate requirements, and manages AMP scripts automatically. Version 4.0.2 includes TypeScript interfaces and PropTypes derived from AMP's validator rules, along with helpers for actions and bindings.

Tokens
4.5K
Snippets
12
Records
19
Agent score
50%

What's inside react-amphtml

  1. Set up an AMP HTML page with react-amphtml

    master

    To generate a valid AMP HTML page, you must include specific boilerplate and the scripts required by the AMP directives you use. The react-amphtml/setup module provides the necessary tools to automate this.

    Workflow

    1. Initialize AmpScripts to track required scripts.
    2. Wrap your body content in AmpScriptsManager to collect the necessary scripts.
    3. Use headerBoilerplate to generate the required <head> content.
    4. Use Amp.Html to structure the document.
    5. Use ampScripts.getScriptElements() to inject the collected scripts into the <head>.
    import * as Amp from 'react-amphtml';
    import { AmpScripts, AmpScriptsManager, headerBoilerplate } from 'react-amphtml/setup';
    import { renderToStaticMarkup } from 'react-dom/server';
    
    const ampScripts = new AmpScripts();
    
    // 1. Prepare body content with Script Manager
    const bodyContent = renderToStaticMarkup(
      <AmpScriptsManager ampScripts={ampScripts}>
        <div>
          <Amp.AmpImg
            specName="default"
            src="/"
            width={0}
            height={0}
            layout="responsive"
            alt="test"
          />
          <Amp.AmpAccordion />
        </div>
      </AmpScriptsManager>
    );
    
    // 2. Assemble the full HTML document
    /* eslint-disable react/no-danger */
    const html = renderToStaticMarkup(
      <Amp.Html>
        <head>
          {headerBoilerplate('/')}
          <title>react-amphtml</title>
          {ampScripts.getScriptElements()}
        </head>
        <body dangerouslySetInnerHTML={{ __html: bodyContent }} />
      </Amp.Html>
    );
    /* eslint-enable */
    
    const htmlPage = `<!doctype html>${html}`;
    import * as Amp from 'react-amphtml';
    import { AmpScripts, AmpScriptsManager, headerBoilerplate } from 'react-amphtml/setup';
    
    const ampScripts = new AmpScripts();
    
    const bodyContent = renderToStaticMarkup(
      <AmpScriptsManager ampScripts={ampScripts}>
        <div>
          <Amp.AmpImg specName="default" src="/" width={0} height={0} layout="responsive" alt="test" />
          <Amp.AmpAccordion />
        </div>
      </AmpScriptsManager>
    );
    
    const html = renderToStaticMarkup(
      <Amp.Html>
        <head>
          {headerBoilerplate('/')}
          <title>react-amphtml</title>
          {ampScripts.getScriptElements()}
        </head>
        <body dangerouslySetInnerHTML={{ __html: bodyContent }} />
      </Amp.Html>
    );
  2. Use Amp Helpers for actions and bindings

    master

    The react-amphtml/helpers module provides render prop components to easily attach AMP attribute directives for actions and bindings to your elements.

    Attaching Actions

    Use AmpHelpers.Action to wrap an element and provide an events object:

    import * as AmpHelpers from 'react-amphtml/helpers';
    
    <AmpHelpers.Action events={{...}}>
      {(props) => (
        <button type="button" {...props}>
          Do Something
        </button>
      )}
    </AmpHelpers.Action>

    Using State and Bindings

    Combine Amp.AmpState with AmpHelpers.Bind to create interactive elements that react to state changes:

    import * as Amp from 'react-amphtml';
    import * as AmpHelpers from 'react-amphtml/helpers';
    
    const defaultHeading = { text: 'Hello, World!' };
    
    // Define the state
    <Amp.AmpState specName="amp-state" id="heading">
      {defaultHeading}
    </Amp.AmpState>
    
    // Bind an element to the state
    <AmpHelpers.Bind text="heading.text">
      {(props) => <h1 {...props}>{defaultHeading.text}</h1>}
    </AmpHelpers.Bind>
  3. Use AMP HTML components in React

    master

    The main entry point react-amphtml exports all AMP HTML directives as React components. This includes amp-* custom elements, standard HTML directives with AMP validations, and specialized components like Html, AmpState (for the amp-state directive), and Script. Each component includes TypeScript interfaces and PropTypes derived from AMP's validator rules to ensure type safety and compliance.

    To access all available components, import the entire module:

    import * as Amp from 'react-amphtml';
    
    // Usage example
    <Amp.AmpCarousel {...props} />
  4. Development commands for react-amphtml

    master

    If you are contributing to or developing react-amphtml, use the following npm commands:

    • npm run codegen: Generates React components from the AMP HTML validator rules. This must be run at least once before building and whenever the underlying rules change.
    • npm run build: Bundles the source files into the dist directory.
    • npm run typecheck: Runs TypeScript type checking on the bundled files in dist.
    • npm run lint: Runs ESLint to check source code quality.
    • npm run test: Runs the test suite using Jest.
  5. Use AmpScriptsManager to provide AmpScripts context

    master

    The AmpScriptsManager component is used to provide an AmpScripts instance to its child components via React context. It requires exactly one child element. This allows deeply nested components to access the ampScripts instance using the CONTEXT_KEY constant.

    To use it, wrap your component tree with AmpScriptsManager and pass an instance of AmpScripts to the ampScripts prop.

    import AmpScriptsManager from './AmpScriptsManager';
    import AmpScripts from './AmpScripts';
    
    // Assuming ampScripts is an instance of AmpScripts
    <AmpScriptsManager ampScripts={ampScripts}>
      <YourApp />
    </AmpScriptsManager>
  6. ScriptProps interface

    master

    The ScriptProps interface defines the configuration for the Script component:

    PropTypeDefaultDescription
    srcstring''The direct URL of the script source.
    extensionstring''The extension name used when src is not provided.
    versionstring'latest'The version of the extension.
    isCustomTemplatebooleanfalseDetermines if the extension is applied as custom-template or custom-element.
    idstringundefinedThe id attribute for the script tag.
    noncestringundefinedThe nonce attribute for the script tag.
    typestringundefinedThe type attribute (e.g., module) for the script tag.
  7. Use the Bind component to attach AMP bindings

    master

    The Bind component is used to wrap elements and provide them with AMP-compatible binding attributes. It transforms standard props passed to the component into data-amp-bind-* attributes, which are then passed to the child function.

    Key behaviors:

    • Attribute Transformation: Any prop passed to Bind that does not start with data-amp- and is not in the BLACKLIST (which includes ON_ATTRIBUTE) is automatically prefixed with data-amp-bind-.
    • Blacklist: The ON_ATTRIBUTE constant is blacklisted to prevent it from being transformed into a binding attribute.
    • Version Control: You can specify a specific version for the amp-bind extension (defaults to 'latest').
    • Render Pattern: Bind uses a render prop pattern. It expects a children function that receives an object containing the transformed AmpBindProps.
    import Bind from './helpers/Bind';
    
    // Example usage with a render prop
    <Bind myProperty="someValue" version="v1">
      {(boundProps) => (
        <div {...boundProps}>
          {/* This div will have data-amp-bind-myProperty="someValue" */}
        </div>
      )}
    </Bind>
  8. Manage AMP scripts with the AmpScripts class

    master

    The AmpScripts class is used to manage the collection of required AMP scripts and extensions for a React application. It handles the registration of extensions and provides methods to retrieve either the raw script source data or ready-to-use React <Script /> elements.

    Initialization

    When you instantiate AmpScripts, it automatically includes the base AMP script corresponding to the provided htmlFormat (defaults to AMP).

    Adding Extensions

    Use the addExtension method to register additional AMP extensions. You can optionally specify a version for the extension.

    Retrieving Scripts

    • getScripts(): Returns an array of ScriptSource objects containing the calculated src and the extension name.
    • getScriptElements(): Returns an array of React elements (using the <Script /> component) that can be rendered directly into your application's head or body.
    import AmpScripts from 'react-amphtml/setup/AmpScripts';
    
    // 1. Initialize with default AMP scripts
    const ampScripts = new AmpScripts();
    
    // 2. Add an extension (e.g., amp-accordion)
    ampScripts.addExtension({ extension: 'amp-accordion', version: '1.0.0' });
    
    // 3. Get React elements to render in your component tree
    const scriptElements = ampScripts.getScriptElements();
    
    // In your React component:
    function MyAmpPage() {
      return (
        <html>
          <head>
            {ampScripts.getScriptElements()}
          </head>
          <body>...</body>
        </html>
      );
    }
  9. Import the react-amphtml package

    master

    The react-amphtml package exports the core amphtml module. You can access the library by requiring or importing the package directly. This module serves as the primary entry point for interacting with AMP components and helpers within a React environment.

    const amphtml = require('react-amphtml');
    // or
    import amphtml from 'react-amphtml';
  10. Use the Action component to attach AMP events

    master

    The Action component is a helper used to generate the string format required by AMP for event attributes (e.g., on='tap:my-element#action').

    It works by taking an events object where keys are the event names (like tap) and values are arrays of action strings. It then passes a generated string via the on attribute to a render function provided in its children prop.

    Props:

    • events: An object mapping event names to an array of action strings. Example: { tap: ['my-element#action1', 'my-element#action2'] }.
    • children: A function that receives an object containing the generated on attribute string. This function must return a ReactElement.

    Generated String Format: The component joins multiple actions for a single event with commas (,) and multiple event types with semicolons (;). The format is eventName:action1,action2;eventName2:action3.

    import Action, { ON_ATTRIBUTE } from 'react-amphtml/helpers/Action';
    
    const MyComponent = () => (
      <Action
        events={{
          tap: ['my-element#action1', 'my-element#action2'],
          click: ['other-element#action3']
        }}
      >
        {({ [ON_ATTRIBUTE]: onAttribute }) => (
          <div on={onAttribute}>
            Click me to trigger AMP actions
          </div>
        )}
      </Action>
    );
  11. BindProps interface definition

    master

    The BindProps interface defines the configuration for the Bind component.

    PropTypeDescription
    children(props: AmpBindProps) => ReactElementA render function that receives the transformed AMP binding attributes.
    versionScriptProps['version']The version of the amp-bind extension to use. Defaults to 'latest'.
    [prop: string]string | undefined | anyArbitrary props that will be transformed into data-amp-bind-{propName} attributes.
  12. AmpScripts API Reference

    master

    The AmpScripts class provides the following public methods:

    constructor(htmlFormat?: Formats)

    Initializes the script manager.

    • Parameter: htmlFormat (optional) - The HTML format to use (defaults to AMP).

    addExtension({ extension, version })

    Registers a new AMP extension.

    • Parameter: extension (required) - The specName of the extension.
    • Parameter: version (optional) - The specific version of the extension to load.

    getScripts(): ScriptSource[]

    Returns an array of script metadata.

    • Returns: ScriptSource[] where each object contains { src: string, extension: string }.

    getScriptElements(): ReactElement[]

    Returns an array of React <Script /> components.

    • Returns: An array of ReactElement objects configured with async enabled.