Play+ Performance Helper: playperf
Introduction
In the Play+ ecosystem, performance is not a feature to be added later—it's a foundational commitment. We believe great design must feel fast. This helper is based on the concept of Performance by Default, where speed, responsiveness, and stability are architected and enforced from day one.
A performant application builds user trust and delight. This directly supports our core design pillars by creating an Engaging experience that feels fluid and responsive, and an Adaptive interface that performs well across all devices and network conditions. By ensuring a fast, stable experience, we also make our products more Intuitive and less frustrating to use.
Package Info
The Play+ performance helper and its associated CI configurations are included by default in the Golden Path starter kit.
Description
Package / Path | Golden Path (Recommended) |
---|---|
Pre-installed | /system/play.perf.ts |
Uplift Path | npm install @playplus/perf |
Folder Reference
The performance helper and its configuration follow our standardized folder structure for core system logic.
File / Directory | Purpose & Guidelines |
---|---|
system/play.perf.ts | The core performance helper. It provides utilities for deferring tasks and monitoring real-world performance. |
config/play.performance.config.json | User-overridable configuration for performance budgets (Lighthouse) and monitoring settings. |
reports/performance/ | The git-ignored directory where Lighthouse CI reports are saved for local inspection. |
Helper - Pillars Alignment
The playperf
helper is a direct implementation of our core design pillars, focused on the user's perception of speed.
Pillar | How This Helper Aligns |
---|---|
Engaging | Primary Pillar: Ensures snappy interactions and fluid animations, which are key to a delightful and engaging user experience. |
Adaptive | Enforces performance budgets that ensure the application is fast and responsive on a wide range of devices and networks. |
Intuitive | A fast and stable application feels more predictable and intuitive, as users aren't left waiting or dealing with layout shifts. |
Helper Overview
The playperf
toolchain is a combination of automated guardrails and developer-facing utilities designed to abstract the plumbing of performance management. Instead of manually configuring performance budgets or writing complex code to defer non-critical tasks, developers can rely on the Play+ system to handle it.
It automates performance quality control in two key ways:
-
Preventative Guardrails: In the CI/CD pipeline,
playperf
automatically runs Lighthouse audits against every pull request. If key metrics (like LCP or CLS) exceed the configured budgets, the build fails, preventing performance regressions from ever reaching production. -
Developer Empowerment Utilities: It provides a simple runtime helper with methods like
defer()
andmonitor()
that make it trivial to implement common performance patterns without writing boilerplate code.
The goal is to make high performance the default path, not an extra chore.
Config Options
Global performance budgets and settings are managed in config/play.performance.config.json
. These values are consumed by the CI pipeline and runtime helpers.
Config Key Table
Config Key | Default Value | Description | Recommended Value |
---|---|---|---|
lighthouse.lcp | 2500 | Lighthouse budget for Largest Contentful Paint (ms). | 2500 |
lighthouse.cls | 0.1 | Lighthouse budget for Cumulative Layout Shift. | 0.1 |
lighthouse.inp | 200 | Lighthouse budget for Interaction to Next Paint (ms). | 200 |
lighthouse.maxBundleSize | 250 | Lighthouse budget for initial JS bundle size (KB, gzipped). | 250 |
enforce.blockBuildOnFail | true | If true, the CI build will fail if performance budgets are exceeded. | true |
enforce.enableBundleDiff | true | If true, PRs will be flagged with any unexpected changes to bundle size. | true |
monitor.webVitals | true | If true, enables the real-user monitoring of Core Web Vitals via playperf.monitor . | true |
monitor.sentry | true | Enables integration with Sentry Performance for transaction tracking. | true |
assist.highlightHeavyComponents | true | In dev mode, flags components that are computationally expensive or re-rendering unnecessarily. | true |
Helper Methods
Method: defer
Schedules a function to run during browser idle time, preventing it from blocking critical rendering.
defer(callback: () => void): void
Method: monitor
Initializes real-user monitoring of Core Web Vitals, sending data to a specified reporting function.
monitor(options: { onReport: (metric) => void }): void
Usage Examples
React: Deferring a Non-Critical Script
This example shows how to defer the initialization of an analytics script so it doesn't interfere with the initial page load.
import React, { useEffect } from 'react';
import { playperf } from '../../system/play.perf';
import { initializeAnalytics } from '../lib/analytics';
function App() {
useEffect(() => {
// Defer the analytics script to run after the main thread is free.
playperf.defer(() => {
initializeAnalytics({ apiKey: '...' });
});
}, []);
return (
// ... your application components
);
}
Angular: Monitoring Real-World Performance
This example shows how to initialize Web Vitals monitoring in your main application component and log the results.
// app.component.ts
import { Component, OnInit } from '@angular/core';
import { playperf } from '@playplus/core'; // Assuming helper is available
import { playlog } from '@playplus/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent implements OnInit {
ngOnInit() {
// Start monitoring real-user performance metrics.
playperf.monitor({
onReport: (metric) => {
// Send the collected metric to our logging service.
playlog.info(`Web Vitals Metric: ${metric.name}`, {
value: metric.value,
id: metric.id
});
}
});
}
}
Additional Info
Why We Created This Helper
Web performance is critical, but its tooling is complex. Without a dedicated system, each team would need to:
- Manually set up, configure, and maintain Lighthouse CI for every project.
- Write custom logic to track bundle sizes.
- Implement their own utilities for deferring scripts or monitoring Web Vitals.
This is inefficient and leads to inconsistent standards. The playperf
helper automates the enforcement and simplifies the implementation of performance best practices. It provides a pre-configured safety net and easy-to-use tools so developers can build fast experiences by default.
Developer Checklist
- Are all non-critical third-party scripts or tasks wrapped in
playperf.defer()
? - Is the code for my route being dynamically imported (code-splitting)?
- Are all images lazy-loaded and served in modern formats (e.g., WebP) with explicit width and height attributes to prevent CLS?
- Have I used skeleton loaders for data-heavy components instead of spinners?
- For long lists, am I using a virtualized scrolling solution?
- Are pure components memoized using
React.memo
or Angular'sOnPush
change detection strategy? - Have I analyzed the bundle size impact of any new dependencies I've added?
- Does my feature pass the Lighthouse CI performance budget checks?
MISC
Recommended Monitoring Tools
For a full view of real-world performance, we recommend integrating with:
- Web Vitals JS Library: To send Core Web Vitals from the browser to your analytics or logging provider.
- Sentry Performance: To track slow transactions and identify main thread stalls.
- SpeedCurve or New Relic: For in-depth Real User Monitoring (RUM) analysis over time, across geographies and devices.
Minimum Enforcement Thresholds
All Play+ applications in the Golden Path are held to these baseline standards, which are enforced automatically in the CI/CD pipeline.
Metric | Target |
---|---|
LCP (Largest Contentful Paint) | < 2.5s |
INP (Interaction to Next Paint) | < 200ms |
CLS (Cumulative Layout Shift) | < 0.1 |
JS Bundle Size (gzipped) | < 250KB |
Main Thread Long Tasks (>50ms) | 0 |
Lighthouse CI Configuration Example
This is a sample of the configuration used by CI to assert performance budgets. It is managed by the @playplus/perf
package.
{
"ci": {
"collect": {
"numberOfRuns": 3
},
"assert": {
"assertions": {
"core-web-vitals": "error",
"largest-contentful-paint": ["error", {"maxNumericValue": 2500}],
"cumulative-layout-shift": ["error", {"maxNumericValue": 0.1}],
"interactive": ["warn", {"maxNumericValue": 3800}]
}
}
}
}