diff --git a/analytics.code-workspace b/analytics.code-workspace new file mode 100644 index 00000000..fff086ac --- /dev/null +++ b/analytics.code-workspace @@ -0,0 +1,7 @@ +{ + "folders": [ + { + "path": "examples/using-perfumejs" + } + ] +} \ No newline at end of file diff --git a/examples/demo/module/module.code-workspace b/examples/demo/module/module.code-workspace new file mode 100644 index 00000000..876a1499 --- /dev/null +++ b/examples/demo/module/module.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} \ No newline at end of file diff --git a/examples/using-perfumejs/AGENTS.md b/examples/using-perfumejs/AGENTS.md new file mode 100644 index 00000000..a4a62755 --- /dev/null +++ b/examples/using-perfumejs/AGENTS.md @@ -0,0 +1,117 @@ +# Analytics Perfume.js Example - Agent Instructions + +This is a React example demonstrating how to integrate [Perfume.js](https://github.com/Zizzamia/perfume.js/) (web performance monitoring) with the [Analytics](https://github.com/DavidWells/analytics) library to automatically track and report performance metrics to multiple analytics providers. + +## Quick Start + +- **Start development**: `npm start` (hot reload on http://localhost:3000) +- **Build for production**: `npm build` +- **Run tests**: `npm test` +- **Deploy to Netlify**: `npm deploy` + +## Project Structure & Purpose + +This is an **example/demo app**, not a library. The key goal is to demonstrate the pattern: + +``` +src/ +├── App.js # Main app - initializes analytics with perfume.js plugin +├── plugins/ +│ ├── perfume.js # Perfume.js integration plugin (tracks Web Vitals) +│ └── custom.js # Simple example of a custom analytics plugin +└── index.js # React entry point +``` + +## Core Concepts & Patterns + +### Analytics Initialization (src/App.js) + +The app initializes a centralized `analytics` instance with multiple plugins: + +```javascript +const analytics = Analytics({ + app: 'my-app', + plugins: [ + { name: 'test-plugin', track: ({ payload }) => { ... } }, + customAnalyticsPlugin, + googleAnalytics({ trackingId: '...' }), + perfumePlugin({ category: 'perf', perfume: Perfume }) + ] +}) +``` + +**Key pattern**: Plugins are composed together. When `analytics.track()` is called, all plugins receive the event. + +### Plugin Architecture (src/plugins/) + +Plugins follow this interface: + +```javascript +{ + name: 'plugin-name', // Required: unique identifier + track: ({ payload }) => { ... } // Track events + initialize: ({ instance, config }) => {} // Optional: initialization hook +} +``` + +**Perfume.js plugin (`perfume.js`)**: Automatically tracks Web Vitals (FP, FCP, LCP, FID, CLS, TBT) and forwards them through analytics to all attached providers. + +**Custom plugin (`custom.js`)**: Simple logger example - shows minimal plugin implementation. + +### Performance Metrics Tracked + +Perfume.js monitors Core Web Vitals: +- **FP** (First Paint) +- **FCP** (First Contentful Paint) +- **LCP** (Largest Contentful Paint) +- **FID** (First Input Delay) +- **CLS** (Cumulative Layout Shift) +- **TBT** (Total Blocking Time) + +These are categorized as `lowEndExperience` or `highEndExperience` for segmentation. + +## Common Tasks + +### Add a new analytics provider + +1. Install the provider plugin: `npm install @analytics/[provider-name]` +2. Add to the `plugins` array in `App.js`: + ```javascript + providerName({ config: 'values' }) + ``` +3. The provider automatically receives all tracked events (including perfume.js metrics) + +### Create a custom analytics plugin + +Create a new file in `src/plugins/` following the plugin interface: +- Minimal: just need `name` and `track` function +- Advanced: add `initialize` hook for setup +- Plugin receives all analytics events via the `track` callback + +### Debug what's being tracked + +Open browser DevTools console: +- The `test-plugin` in App.js logs all events to console +- Each plugin sees the full `payload` with event name, properties, and metadata + +### Modify what perfume.js tracks + +Edit `src/plugins/perfume.js`: +- `metricNames` array: which metrics to report +- The `analyticsTracker` callback: customize how metrics are formatted and sent +- Note: Metrics are scaled for Google Analytics (integers) - adjust per provider + +## Design Decisions + +- **Centralized analytics instance** in `App.js`: All tracking goes through one place +- **Plugin composition**: Decoupled providers - add/remove without changing core logic +- **Non-interaction events**: Perfume metrics don't affect bounce rate in GA +- **Value scaling**: CLS values multiplied by 1000 for GA (which requires integers) +- **Device experience segmentation**: Metrics tagged as `lowEndExperience` or `highEndExperience` + +## Related Resources + +- [Live example app](https://analytics-perfumejs-example.netlify.app/) +- [Perfume.js documentation](https://zizzamia.github.io/perfume/) +- [Analytics library docs](https://github.com/DavidWells/analytics) +- [Example video](https://www.youtube.com/watch?v=9DZAVpAubtQ) diff --git a/site/gatsby-theme-base/package.json b/site/gatsby-theme-base/package.json old mode 100755 new mode 100644 index 73cee8a9..d1009e83 --- a/site/gatsby-theme-base/package.json +++ b/site/gatsby-theme-base/package.json @@ -13,7 +13,7 @@ "gatsby-plugin-react-helmet": "^3.0.2", "gatsby-plugin-svgr": "^2.0.1", "less": "^3.9.0", - "lodash": "^4.17.11", + "lodash": "^4.18.1", "polished": "^2.3.3", "prop-types": "^15.6.2", "react": "^16.8.6", diff --git a/site/yarn.lock b/site/yarn.lock index 269a47ad..0530e736 100644 --- a/site/yarn.lock +++ b/site/yarn.lock @@ -10010,15 +10010,10 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.11.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0: - version "4.17.14" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba" - integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw== - -lodash@^4.17.13, lodash@^4.17.15, lodash@^4.2.1: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== +lodash@^4.11.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.18.1, lodash@^4.2.1, lodash@^4.3.0: + version "4.18.1" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.18.1.tgz#ff2b66c1f6326d59513de2407bf881439812771c" + integrity sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q== log-process-errors@^5.1.1: version "5.1.2"