fullstorydev / fullstory-babel-plugin-annotate-react

A Babel plugin that annotates React components, making them easier to target with FullStory search
MIT License
30 stars 13 forks source link

Babel Plugin: Annotate React

CircleCI

This is a Babel plugin that annotates React components with stable attributes that can be used to search and select using FullStory. This is most useful when using a React system that generates dynamic names for Components or rearranges elements.

Getting started

with npm

npm i @fullstory/babel-plugin-annotate-react --save

with yarn

yarn add @fullstory/babel-plugin-annotate-react

Babel configuration

Add the @fullstory/babel-plugin-annotate-react plugin to your babel plugin configuration (e.g., babel.config.js).

module.exports = {
  /* ... */
  plugins: [
    /* ... */
    "@fullstory/babel-plugin-annotate-react"
  ]
};

Description

For React on the web, the attributes data-component, data-element, and data-source-file are added to each element. For React Native, the attributes added are dataComponent, dataElement, and dataSourceFile.

Note that for both web and native, these attributes will appear as kebab-case in the Fullstory application due to backend processing. End users of Fullstory should create search filters (i.e. segments, metrics, etc) using kebab-case.

The component attribute names the React.Component and the element attribute names the original native elements like View or Image or an emitter of DOM elements like Fragment.

Example input:

class HelloComponent extends Component {
  render() {
    return <div>
      <h1>Hello world</h1>
    </div>;
  }
}

Example JS output:

class HelloComponent extends Component {
  render() {
    return React.createElement("div", {
      "data-component": "HelloComponent",
      "data-file-source": "hello-component.js"
    }, React.createElement("h1", {
      null
    }, "Hello world"));
  }
}

Final render:

<div data-component="HelloComponent" data-file-source="hello-component.js">
  <h1>Hello world</h1>
</div>

Configuration options

React Native

To activate React Native support you must pass in a native plugin option like so:

plugins: [
  ["@fullstory/babel-plugin-annotate-react", { native: true }]
]

See Getting Started with FullStory React Native Capture for more info.

setFSTagName setting

When using this library with FullStory for Mobile Apps, we recommend setting setFSTagName: true to generate better privacy selectors. This setting will automatically set fsTagName with the value of dataElement or dataComponent, which will truncate the privacy selector and avoid duplicate naming.

Example:

plugins: [
  '@fullstory/react-native',
  ["@fullstory/annotate-react", {
    native: true,
    setFSTagName: true,
  }]
]

⚠️ Important: Existing FullStory privacy selectors and defined elements may need to be updated if the app was previously published without setFSTagName: true.

Fragments

By default, the plugin does not annotate React.Fragments because they may or may not contain a child that ends up being an HTML element.

An example with no child element:

const componentName = () => (
  <Fragment>Hello, there.</Fragment>
);

An example with child elements:

const componentName = () => (
  <Fragment>
    Some text
    <h1>Hello, there.</h1> /* This one could be annotated */
    <a href="#foo">Click me</a>
  </Fragment>
);

If you would like the plugin to attempt to annotate the first HTML element created by a Fragment (if it exists) then set the annotate-fragments flag:

plugins: [
  ["@fullstory/babel-plugin-annotate-react", { "annotate-fragments": true }]
]

Ignoring Components

If you would like the plugin to skip the annotation for certain components, use the ignoreComponents option:

  plugins: [
      [
        "@fullstory/annotate-react",
        {
          ignoreComponents:[
            // each item must be a string array containing three items: file name, component name, element name
            // corresponding to the values for data-source-file, data-component, data-element
            // use wild card (*) to match anything
            ["myBoxComponent.jsx","MyBox","Box"],
            ["App.jsx", "*", "ThemeProvider"], // use wild-card to match anything
            ["App.jsx", "App", "*"],
          ]
        }
      ],
  ]

Sample Apps

We have a few samples to demonstrate this plugin:

Much of the logic for adding the attributes originated in the transform-react-qa-classes plugin.

Getting Help

Please refer to our Knowledge Base article or contact mobile-support@fullstory.com for additional help.

React Native

Please see our Getting Started with FullStory React Native Capture guide or email mobile-support@fullstory.com for additional help.