How to share Html2React processors

Hi everyone :slightly_smiling_face:

I’d like to start a conversation about the best way to share Gutenberg processors between Frontity projects.

@mmczaplinski did a PR to add syntax highlighting to the Gutenberg <code> block using Prism.js:

It’s really cool and it works great, but that feature is only in our theme. No other Frontity theme can use it without copy-pasting the code in their own project.

It is in Frontity’s vision that:

  • We encourage the community to share the code they create for their projects.
  • We provide extensibility patterns and best-practices to make sharing features easy.
  • People are able to add functionalities without having to modify the code of their themes (like they do in WordPress by installing plugins).

So far we have shared some processors in the @frontity/html2react package: https://github.com/frontity/frontity/tree/dev/packages/html2react/processors

We have image and iframe that add native lazy load. I think that we should remove them at some point, because WordPress 5.5 already provides that functionality.

These processors are not included by default and it’s up to the theme to add them or not.

And we have script, which is added by default because this is more of a fix: React breaks <script> tags and that processor “fixes” them.


I think a “Syntax highlighting processor for the Gutenberg <code> block” it’s something different, something that doesn’t depend on the theme, but on the type of content you are creating in WordPress.

Ideally, a Frontity user should be able to add that functionality to its project without having to write a single line of code, just by using their frontity.settings.js file.

Possible extensibility patterns that come to my mind:

  1. Create a package for that processor: @frontity/prism-code-blocks.
  2. Add that processor and similar ones to the upcoming @frontity/gutenberg package.
  3. Add it to @frontity/html2react/processors like the existing ones.

For options 2 and 3 we could expose the processors in the settings so people can choose the ones they want. Something like this:

const settings = {
  packages: [
    {
      name: "@frontity/html2react",
      state: {
        html2react: {
          processors: {
            code: true,
          },
        },
      },
    },
  ],
};

Or even with options:

const settings = {
  packages: [
    {
      name: "@frontity/html2react",
      state: {
        html2react: {
          processors: {
            code: {
              theme: "funky",
              languages: ["javascript", "json"],
            },
          },
        },
      },
    },
  ],
};

More ideas are welcomed :smile:

4 Likes

Would it make sense to make the API for Html2React’s processors similar to our Slot and Fill pattern, regarding how fills are exposed?

I was thinking of expose processors in libraries.html2react.processors and configure them in state.html2react.processors.

That way, people could add new processors using Frontity packages and configure them in frontity.settings.js

Yes. That is what I am proposing for option 2 and 3 :slightly_smiling_face:

But we could use that same pattern for option 1 as well, right?

I mean, the @frontity/prism-code-blocks package can export its own processor in libraries, and users could include and configure it in state.html2react.processors. Does it make sense?

Oh, ok. Sorry I didn’t get it before.

So you mean the configuration of @frontity/prism-code-block would be something like this:

import code from "./processors/code";

const prismCodeBlock = {
  state: {
    html2react: {
      processors: {
        code: {
          // The code of this processor, found in libraries, like Fill components.
          library: "prismCodeBlock.code",
          // Priority, like Fill priorities.
          priority: 10,
          // Other options passed to the processor, like Fill props.
          options: {
            theme: "funky",
            languages: {
              javascript: true,
              php: true,
            },
          },
        },
      },
    },
  },
  libraries: {
    html2react: {
      prismCodeBlock: {
        code,
      },
    },
  },
};

And if people want to change something, they can use state in their frontity.settings.js file:

const settings = {
  // ...
  packages: [
    {
      name: "@frontity/prism-code-block",
      state: {
        html2react: {
          processors: {
            code: {
              options: {
                theme: "plain",
                languages: {
                  typescript: true,
                  php: false,
                },
              },
            },
          },
        },
      },
    },
  ],
};

Yes, I think making it as similar as possible to Slot and Fills makes a lot of sense @david! :slightly_smiling_face:

I like the idea of being able to enable/disable processors and also pass options to them.

I just have one question though - how would this work if packages enable its own processors? would themes always override packages configs if let’s say a theme doesn’t want a processor added by a custom package?

Yes, if a custom package adds a processor by default it could be overwritten by both another package or the frontity.settings.js file. That’s how fills work.

Let’s imagine the awesome-forms package adds two processors by default: simpleForms, complexForms. If for some reason you don’t want the complexForms to be added, you could simple declare that in your frontity.settings.js file:

const settings = {
  // ...
  packages: [
    {
      name: "awesome-forms",
      state: {
        html2react: {
          processors: {
            awesomeForms: {
              complexForms: false,
            },
          },
        },
      },
    },
  ],
};

Also, another package can use its own state definition to overwrite it if it knows that it never wants that processor present:

const state = {
  html2react: {
    processors: {
      awesomeForms: {
        complexForms: false,
      },
    },
  },
};

Although this has the caveat that the order in which the packages are merged together determines which package writes to the state in last position.

For that you can:

  • Move your package to the last position of the array in the packages array of the frontity.settings.js file. This is not very intuitive.
  • Wait until we release package priorities, which is part of the AMP packages and assign the proper priority to each package.
  • Do the state mutation in the init function:
const actions = {
  myPackage: {
    init: ({ state }) => {
      state.html2react.processors.awesomeForms.complexForms = false;
    },
  },
};

I am open to better ideas on how to organize the order in which packages are merged together by the way :slightly_smiling_face: