@diosmosis opened this Pull Request on July 22nd 2021 Member

Description:

This is a complete (for some definition of "complete") PoC of using React to replace AngularJS directives & components in Matomo, while still running alongside AngularJS.

Like the Angular PoC it migrates the site selector, enriched headline and content block directives, + any related directives/components.

Current State

This one is more functional than the Angular proof of concept. The site selector works without errors or (obvious) issues, as do the other components. It took much less time to code. The only part that is unfinished is the build system, which was not already prepackaged as with Angular. It works, but is not too flexible and will need to be modified (which is doable and shouldn't be too time consuming, but it is more work than w/ Angular).

Core Concepts

Same as with Angular, components are used here to encapsulate parts of the UI. The only difference is where Angular allows many different options, components, directives, pipes, in React there are only components. Everything you can do in Angular you can do in React, it just takes less thinking. For example, the 'focus-anywhere-but-here' directive in the Angular poc is just a component here. The translate pipe in the Angular poc doesn't even exist, we just use _pk_translate() directly (since it's all javascript this is fine).

The small footprint and set of responsibilities React covers means we can implement other things how we want or need, and do not need to be afraid of it breaking in a future release. Routing, for example, is completely out of scope of React. There are libraries to deal with it, but we don't have to use them. And if we keep our existing routing, and update React, nothing will break.

This also goes for having a solution to automatically initialize react components in twig templates. If we choose to keep that part of matomo, and create such a mechanism, updating react is very unlikely to break it. On the other hand, Angular has already deprecated entryComponents, so we have reason to fear future Angular releases.

Another thing to note is that services aren't a special thing here. It's all just javascript, so we create a class for the service and create a new instance to consume it or consume a singleton, as we would in php. Nothing special needed to mark something as a "service".

Finally, this isn't really a React thing, but with companion libraries like redux can allow us to separate component state (what is owned by the component) from application state (what must be kept in sync across components). None of this is truly needed though, and matomo probably doesn't need it.

Modularization

Modularization is achieved in a way similar to the Angular PoC. Each plugin can have a react subfolder that compiles to a UMD. They are loaded if the plugin is activated.

Unlike the ANgular PoC, loading order does not matter, and we do not need to bootstrap the application with any extra modules.

Again two commands are supplied:

  • generate:react: generates a blank library in a plugin
  • corereact:build: builds one or more plugins

It's not needed to use these commands as it is with Angular, but it's far more convenient. Any library that compiles with our webpack config can be used. And you can run the build script directly in any react folder if you want.

The Build System

The build system here uses webpack. It uses an ejected configuration from a create-react-app app modified for this specific use case. Unfortunately, our use case is far away from most react apps, so this may not have been the best approach.

Currently it works, but there's a lot there that we don't need, and a lot we'd need to modify to make sure we have optimal builds (for example, right now parts of core js appear in every plugin build, even though we include it in CoreReact.php).

Migration Path

The migration path is the same as in the Angular PoC. The process of rewriting is the same and we maintain backwards compatibility in the same way. We just don't need to do any sort of downgrading.

Other implementation details/challenges

  • Build system: Again, the build system is the primary challenge. We'd need to spend some time making sure it works how we want. This can be done in parallel to conversion work.

  • Transclusion: Adding angular elements to React is not straightforward. React elements are wrapped HTMLElements, created via the React.createElement function. The elements angular creates when transcluding and rendering are not wrapped this way and I can't see a way to wrap them after they are created. So we can't just add them via the normal React mechanism (this.props.children). Instead there is a TranscludeTarget component that manually appends them to a node. This approach appears to work, but I'm unsure whether it will work w/ more complicated transcludes.

  • Keeping twig templates: We can sort of do this, but not to the extent we currently do. Right now we could, for example, add a
    element and add regular markup inside that we want to be rendered a certain way. We can't do this in React. With AngularJS the inside elements are just normal markup. But in React (as in Angular), everything has to be JSX, we can't really output any HTML and have it automagically turn into react components. The best we can do is something like:
    <div init-react="HeatmapSessionRecording.ManageHeatmapsComponent" .../>

    then have React initialize it. Any HTML we put in side would be lost, unless we keep the same transclusion hack that's there now.

    Pros & Cons

    • Pros

      • Using babel to provide modern ES... features makes development faster just like TypeScript.
      • Coding in React seems to be faster than with Angular because there's less choice, but the same amount of power.
      • We don't have to do things in a prescribed way and still be confident it won't break if we update React (unlike angular).
      • Module structures end up being a lot simpler. Just folders with JavaScript that get bundled into one file.
      • (Like angular) OOP in the frontend.
    • Cons

      • The build system will need an investment of time.
      • The twig templates will also have to be converted mostly which means more time spent.
@github-actions[bot] commented on August 6th 2021 Contributor

If you don't want this PR to be closed automatically in 28 days then you need to assign the label 'Do not close'.

@tsteur commented on August 25th 2021 Member

fyi closing these for now. We'll still have the code just in case

This Pull Request was closed on August 25th 2021
Powered by GitHub Issue Mirror