DavidWells / DavidWells/analytics

Chain plugins to modify payload in sequence

Open
#24 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
2.7k
Forks
267
PR merge metrics
No merged PRs in 30d

Description

Hi, is it possible to chain multiple plugins to modify the payload so that changes from one plugin are passed to another?

Example:
The setup is like this:

Analytics({
    ...
    plugins: [
        // Plugins that disable tracking on certain conditions
        doNotTrackPlugin(),
        ...
        // plugins that modify the payload
        enrichAnalyticsPlugin(),
        dropNoValuePropertiesPlugin(),
        snakecasePropertiesPlugin(),
        // 3rd party analytics
        googleAnalyticsPlugin({ ... })
    ],
    ...
}

where each of the plugins that modifies the payload changes only a single specific part of it. E.g. this is a plugin which converts the property keys in payload.properties from camelCase to snake_case:

export function snakecasePropertiesPlugin() {
  return {
    name: "snakecase-properties",
    track: ({ payload }) => {
      return {
        ...payload,
        properties: snakeCaseProperties(payload.properties)
      };
    },
    identify: ({ payload }) => {
      return {
        ...payload,
        traits: snakeCaseProperties(payload.traits)
      };
    },
    page: ({ payload }) => {
      return {
        ...payload,
        properties: snakeCaseProperties(payload.properties)
      };
    }
  };

  function snakeCaseProperties(obj) {
    return Object.keys(obj).reduce((agg, key) => {
      agg[_.snakeCase(key)] = obj[key];
      return agg;
    }, {});
  }
}

The assumption is that the plugins that modify the payload should be run for all data that is passed to the Analytics instance, hence I did not want to use the namespacing as described in the docs.

But what this leads to is that instead of the data being passed from plugin to plugin sequentially, they are all fed with the initial data. So when there are multiple plugins modifying the payload before it is sent to the 3rd party analytics, those changes are just overwriting one another when the new returned value is merged with result from previous plugin, instead of those changes compounding.

Is this use case supported?

I assume (haven't tested yet) that in this scenario, it could be solved by namespacing all the modifying plugins? (e.g. so that all their functions are namespaced, e.g. 'track:google-analytics'). But if all these changes should be applied to multiple 3rd party analytics, it would quickly get inconvenient as the same functions would have to be namespaced for all of them? (So each plugin would have to have not only 'track:google-analytics', but also 'track:hubspot', for example).

Additional issue is that with my approach, the order is important (e.g. payload should be first enriched, and only then the value-less properties should be dropped). Could that be achieved with this approach? Or would I have to specify for each plugin the namespace of the plugin that should go after it? (So that in the example above, enrichAnalyticsPlugin needs to be namespaced to dropNoValuePropertiesPlugin, that in turn namespaced to snakecasePropertiesPlugin, and so on, so they are all sequentially run?). The downside of that approach is that I cannot just reorder the plugins easily, but I would have to rename the namespaces for all affected plugins.

Or is there maybe a plugin that could be given a list of other plugins, and subplugins would modify the payload sequentially? Or will I have to squash the plugins into a big one and namespace it to the desired 3rd party analytics plugin?

What's the best course of action here? Thanks.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with packages/analytics-core/src/middleware/plugins/engine.js, especially the behavior around line 334, and compare it with the linked plugin-namespacing documentation. Trace how track, identify, and page plugin results are combined, then determine the expected ordering and composition semantics for multiple payload-modifying plugins. Done means the supported behavior and its constraints are documented or implemented with coverage for the stated plugin sequence.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
api
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.