@wazir-dev/cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +111 -0
- package/CHANGELOG.md +14 -0
- package/CONTRIBUTING.md +101 -0
- package/LICENSE +21 -0
- package/README.md +314 -0
- package/assets/composition-engine.mmd +34 -0
- package/assets/demo-script.sh +17 -0
- package/assets/logo-dark.svg +14 -0
- package/assets/logo.svg +14 -0
- package/assets/pipeline.mmd +39 -0
- package/assets/record-demo.sh +51 -0
- package/docs/README.md +51 -0
- package/docs/adapters/context-mode.md +60 -0
- package/docs/concepts/architecture.md +87 -0
- package/docs/concepts/artifact-model.md +60 -0
- package/docs/concepts/composition-engine.md +36 -0
- package/docs/concepts/indexing-and-recall.md +160 -0
- package/docs/concepts/observability.md +41 -0
- package/docs/concepts/roles-and-workflows.md +59 -0
- package/docs/concepts/terminology-policy.md +27 -0
- package/docs/getting-started/01-installation.md +78 -0
- package/docs/getting-started/02-first-run.md +102 -0
- package/docs/getting-started/03-adding-to-project.md +15 -0
- package/docs/getting-started/04-host-setup.md +15 -0
- package/docs/guides/ci-integration.md +15 -0
- package/docs/guides/creating-skills.md +15 -0
- package/docs/guides/expertise-module-authoring.md +15 -0
- package/docs/guides/hook-development.md +15 -0
- package/docs/guides/memory-and-learnings.md +34 -0
- package/docs/guides/multi-host-export.md +15 -0
- package/docs/guides/troubleshooting.md +101 -0
- package/docs/guides/writing-custom-roles.md +15 -0
- package/docs/plans/2026-03-15-cli-pipeline-integration-design.md +592 -0
- package/docs/plans/2026-03-15-cli-pipeline-integration-plan.md +598 -0
- package/docs/plans/2026-03-15-docs-enforcement-plan.md +238 -0
- package/docs/readmes/INDEX.md +99 -0
- package/docs/readmes/features/expertise/README.md +171 -0
- package/docs/readmes/features/exports/README.md +222 -0
- package/docs/readmes/features/hooks/README.md +103 -0
- package/docs/readmes/features/hooks/loop-cap-guard.md +133 -0
- package/docs/readmes/features/hooks/post-tool-capture.md +121 -0
- package/docs/readmes/features/hooks/post-tool-lint.md +130 -0
- package/docs/readmes/features/hooks/pre-compact-summary.md +122 -0
- package/docs/readmes/features/hooks/pre-tool-capture-route.md +100 -0
- package/docs/readmes/features/hooks/protected-path-write-guard.md +128 -0
- package/docs/readmes/features/hooks/session-start.md +119 -0
- package/docs/readmes/features/hooks/stop-handoff-harvest.md +125 -0
- package/docs/readmes/features/roles/README.md +157 -0
- package/docs/readmes/features/roles/clarifier.md +152 -0
- package/docs/readmes/features/roles/content-author.md +190 -0
- package/docs/readmes/features/roles/designer.md +193 -0
- package/docs/readmes/features/roles/executor.md +184 -0
- package/docs/readmes/features/roles/learner.md +210 -0
- package/docs/readmes/features/roles/planner.md +182 -0
- package/docs/readmes/features/roles/researcher.md +164 -0
- package/docs/readmes/features/roles/reviewer.md +184 -0
- package/docs/readmes/features/roles/specifier.md +162 -0
- package/docs/readmes/features/roles/verifier.md +215 -0
- package/docs/readmes/features/schemas/README.md +178 -0
- package/docs/readmes/features/skills/README.md +63 -0
- package/docs/readmes/features/skills/brainstorming.md +96 -0
- package/docs/readmes/features/skills/debugging.md +148 -0
- package/docs/readmes/features/skills/design.md +120 -0
- package/docs/readmes/features/skills/prepare-next.md +109 -0
- package/docs/readmes/features/skills/run-audit.md +159 -0
- package/docs/readmes/features/skills/scan-project.md +109 -0
- package/docs/readmes/features/skills/self-audit.md +176 -0
- package/docs/readmes/features/skills/tdd.md +137 -0
- package/docs/readmes/features/skills/using-skills.md +92 -0
- package/docs/readmes/features/skills/verification.md +120 -0
- package/docs/readmes/features/skills/writing-plans.md +104 -0
- package/docs/readmes/features/tooling/README.md +320 -0
- package/docs/readmes/features/workflows/README.md +186 -0
- package/docs/readmes/features/workflows/author.md +181 -0
- package/docs/readmes/features/workflows/clarify.md +154 -0
- package/docs/readmes/features/workflows/design-review.md +171 -0
- package/docs/readmes/features/workflows/design.md +169 -0
- package/docs/readmes/features/workflows/discover.md +162 -0
- package/docs/readmes/features/workflows/execute.md +173 -0
- package/docs/readmes/features/workflows/learn.md +167 -0
- package/docs/readmes/features/workflows/plan-review.md +165 -0
- package/docs/readmes/features/workflows/plan.md +170 -0
- package/docs/readmes/features/workflows/prepare-next.md +167 -0
- package/docs/readmes/features/workflows/review.md +169 -0
- package/docs/readmes/features/workflows/run-audit.md +191 -0
- package/docs/readmes/features/workflows/spec-challenge.md +159 -0
- package/docs/readmes/features/workflows/specify.md +160 -0
- package/docs/readmes/features/workflows/verify.md +177 -0
- package/docs/readmes/packages/README.md +50 -0
- package/docs/readmes/packages/ajv.md +117 -0
- package/docs/readmes/packages/context-mode.md +118 -0
- package/docs/readmes/packages/gray-matter.md +116 -0
- package/docs/readmes/packages/node-test.md +137 -0
- package/docs/readmes/packages/yaml.md +112 -0
- package/docs/reference/configuration-reference.md +159 -0
- package/docs/reference/expertise-index.md +52 -0
- package/docs/reference/git-flow.md +43 -0
- package/docs/reference/hooks.md +87 -0
- package/docs/reference/host-exports.md +50 -0
- package/docs/reference/launch-checklist.md +172 -0
- package/docs/reference/marketplace-listings.md +76 -0
- package/docs/reference/release-process.md +34 -0
- package/docs/reference/roles-reference.md +77 -0
- package/docs/reference/skills.md +33 -0
- package/docs/reference/templates.md +29 -0
- package/docs/reference/tooling-cli.md +94 -0
- package/docs/truth-claims.yaml +222 -0
- package/expertise/PROGRESS.md +63 -0
- package/expertise/README.md +18 -0
- package/expertise/antipatterns/PROGRESS.md +56 -0
- package/expertise/antipatterns/backend/api-design-antipatterns.md +1271 -0
- package/expertise/antipatterns/backend/auth-antipatterns.md +1195 -0
- package/expertise/antipatterns/backend/caching-antipatterns.md +622 -0
- package/expertise/antipatterns/backend/database-antipatterns.md +1038 -0
- package/expertise/antipatterns/backend/index.md +24 -0
- package/expertise/antipatterns/backend/microservices-antipatterns.md +850 -0
- package/expertise/antipatterns/code/architecture-antipatterns.md +919 -0
- package/expertise/antipatterns/code/async-antipatterns.md +622 -0
- package/expertise/antipatterns/code/code-smells.md +1186 -0
- package/expertise/antipatterns/code/dependency-antipatterns.md +1209 -0
- package/expertise/antipatterns/code/error-handling-antipatterns.md +1360 -0
- package/expertise/antipatterns/code/index.md +27 -0
- package/expertise/antipatterns/code/naming-and-abstraction.md +1118 -0
- package/expertise/antipatterns/code/state-management-antipatterns.md +1076 -0
- package/expertise/antipatterns/code/testing-antipatterns.md +1053 -0
- package/expertise/antipatterns/design/accessibility-antipatterns.md +1136 -0
- package/expertise/antipatterns/design/dark-patterns.md +1121 -0
- package/expertise/antipatterns/design/index.md +22 -0
- package/expertise/antipatterns/design/ui-antipatterns.md +1202 -0
- package/expertise/antipatterns/design/ux-antipatterns.md +680 -0
- package/expertise/antipatterns/frontend/css-layout-antipatterns.md +691 -0
- package/expertise/antipatterns/frontend/flutter-antipatterns.md +1827 -0
- package/expertise/antipatterns/frontend/index.md +23 -0
- package/expertise/antipatterns/frontend/mobile-antipatterns.md +573 -0
- package/expertise/antipatterns/frontend/react-antipatterns.md +1128 -0
- package/expertise/antipatterns/frontend/spa-antipatterns.md +1235 -0
- package/expertise/antipatterns/index.md +31 -0
- package/expertise/antipatterns/performance/index.md +20 -0
- package/expertise/antipatterns/performance/performance-antipatterns.md +1013 -0
- package/expertise/antipatterns/performance/premature-optimization.md +623 -0
- package/expertise/antipatterns/performance/scaling-antipatterns.md +785 -0
- package/expertise/antipatterns/process/ai-coding-antipatterns.md +853 -0
- package/expertise/antipatterns/process/code-review-antipatterns.md +656 -0
- package/expertise/antipatterns/process/deployment-antipatterns.md +920 -0
- package/expertise/antipatterns/process/index.md +23 -0
- package/expertise/antipatterns/process/technical-debt-antipatterns.md +647 -0
- package/expertise/antipatterns/security/index.md +20 -0
- package/expertise/antipatterns/security/secrets-antipatterns.md +849 -0
- package/expertise/antipatterns/security/security-theater.md +843 -0
- package/expertise/antipatterns/security/vulnerability-patterns.md +801 -0
- package/expertise/architecture/PROGRESS.md +70 -0
- package/expertise/architecture/data/caching-architecture.md +671 -0
- package/expertise/architecture/data/data-consistency.md +574 -0
- package/expertise/architecture/data/data-modeling.md +536 -0
- package/expertise/architecture/data/event-streams-and-queues.md +634 -0
- package/expertise/architecture/data/index.md +25 -0
- package/expertise/architecture/data/search-architecture.md +663 -0
- package/expertise/architecture/data/sql-vs-nosql.md +708 -0
- package/expertise/architecture/decisions/architecture-decision-records.md +640 -0
- package/expertise/architecture/decisions/build-vs-buy.md +616 -0
- package/expertise/architecture/decisions/index.md +23 -0
- package/expertise/architecture/decisions/monolith-to-microservices.md +790 -0
- package/expertise/architecture/decisions/technology-selection.md +616 -0
- package/expertise/architecture/distributed/cap-theorem-and-tradeoffs.md +800 -0
- package/expertise/architecture/distributed/circuit-breaker-bulkhead.md +741 -0
- package/expertise/architecture/distributed/consensus-and-coordination.md +796 -0
- package/expertise/architecture/distributed/distributed-systems-fundamentals.md +564 -0
- package/expertise/architecture/distributed/idempotency-and-retry.md +796 -0
- package/expertise/architecture/distributed/index.md +25 -0
- package/expertise/architecture/distributed/saga-pattern.md +797 -0
- package/expertise/architecture/foundations/architectural-thinking.md +460 -0
- package/expertise/architecture/foundations/coupling-and-cohesion.md +770 -0
- package/expertise/architecture/foundations/design-principles-solid.md +649 -0
- package/expertise/architecture/foundations/domain-driven-design.md +719 -0
- package/expertise/architecture/foundations/index.md +25 -0
- package/expertise/architecture/foundations/separation-of-concerns.md +472 -0
- package/expertise/architecture/foundations/twelve-factor-app.md +797 -0
- package/expertise/architecture/index.md +34 -0
- package/expertise/architecture/integration/api-design-graphql.md +638 -0
- package/expertise/architecture/integration/api-design-grpc.md +804 -0
- package/expertise/architecture/integration/api-design-rest.md +892 -0
- package/expertise/architecture/integration/index.md +25 -0
- package/expertise/architecture/integration/third-party-integration.md +795 -0
- package/expertise/architecture/integration/webhooks-and-callbacks.md +1152 -0
- package/expertise/architecture/integration/websockets-realtime.md +791 -0
- package/expertise/architecture/mobile-architecture/index.md +22 -0
- package/expertise/architecture/mobile-architecture/mobile-app-architecture.md +780 -0
- package/expertise/architecture/mobile-architecture/mobile-backend-for-frontend.md +670 -0
- package/expertise/architecture/mobile-architecture/offline-first.md +719 -0
- package/expertise/architecture/mobile-architecture/push-and-sync.md +782 -0
- package/expertise/architecture/patterns/cqrs-event-sourcing.md +717 -0
- package/expertise/architecture/patterns/event-driven.md +797 -0
- package/expertise/architecture/patterns/hexagonal-clean-architecture.md +870 -0
- package/expertise/architecture/patterns/index.md +27 -0
- package/expertise/architecture/patterns/layered-architecture.md +736 -0
- package/expertise/architecture/patterns/microservices.md +753 -0
- package/expertise/architecture/patterns/modular-monolith.md +692 -0
- package/expertise/architecture/patterns/monolith.md +626 -0
- package/expertise/architecture/patterns/plugin-architecture.md +735 -0
- package/expertise/architecture/patterns/serverless.md +780 -0
- package/expertise/architecture/scaling/database-scaling.md +615 -0
- package/expertise/architecture/scaling/feature-flags-and-rollouts.md +757 -0
- package/expertise/architecture/scaling/horizontal-vs-vertical.md +606 -0
- package/expertise/architecture/scaling/index.md +24 -0
- package/expertise/architecture/scaling/multi-tenancy.md +800 -0
- package/expertise/architecture/scaling/stateless-design.md +787 -0
- package/expertise/backend/embedded-firmware.md +625 -0
- package/expertise/backend/go.md +853 -0
- package/expertise/backend/index.md +24 -0
- package/expertise/backend/java-spring.md +448 -0
- package/expertise/backend/node-typescript.md +625 -0
- package/expertise/backend/python-fastapi.md +724 -0
- package/expertise/backend/rust.md +458 -0
- package/expertise/backend/solidity.md +711 -0
- package/expertise/composition-map.yaml +443 -0
- package/expertise/content/foundations/content-modeling.md +395 -0
- package/expertise/content/foundations/editorial-standards.md +449 -0
- package/expertise/content/foundations/index.md +24 -0
- package/expertise/content/foundations/microcopy.md +455 -0
- package/expertise/content/foundations/terminology-governance.md +509 -0
- package/expertise/content/index.md +34 -0
- package/expertise/content/patterns/accessibility-copy.md +518 -0
- package/expertise/content/patterns/index.md +24 -0
- package/expertise/content/patterns/notification-content.md +433 -0
- package/expertise/content/patterns/sample-content.md +486 -0
- package/expertise/content/patterns/state-copy.md +439 -0
- package/expertise/design/PROGRESS.md +58 -0
- package/expertise/design/disciplines/dark-mode-theming.md +577 -0
- package/expertise/design/disciplines/design-systems.md +595 -0
- package/expertise/design/disciplines/index.md +25 -0
- package/expertise/design/disciplines/information-architecture.md +800 -0
- package/expertise/design/disciplines/interaction-design.md +788 -0
- package/expertise/design/disciplines/responsive-design.md +552 -0
- package/expertise/design/disciplines/usability-testing.md +516 -0
- package/expertise/design/disciplines/user-research.md +792 -0
- package/expertise/design/foundations/accessibility-design.md +796 -0
- package/expertise/design/foundations/color-theory.md +797 -0
- package/expertise/design/foundations/iconography.md +795 -0
- package/expertise/design/foundations/index.md +26 -0
- package/expertise/design/foundations/motion-and-animation.md +653 -0
- package/expertise/design/foundations/rtl-design.md +585 -0
- package/expertise/design/foundations/spacing-and-layout.md +607 -0
- package/expertise/design/foundations/typography.md +800 -0
- package/expertise/design/foundations/visual-hierarchy.md +761 -0
- package/expertise/design/index.md +32 -0
- package/expertise/design/patterns/authentication-flows.md +474 -0
- package/expertise/design/patterns/content-consumption.md +789 -0
- package/expertise/design/patterns/data-display.md +618 -0
- package/expertise/design/patterns/e-commerce.md +1494 -0
- package/expertise/design/patterns/feedback-and-states.md +642 -0
- package/expertise/design/patterns/forms-and-input.md +819 -0
- package/expertise/design/patterns/gamification.md +801 -0
- package/expertise/design/patterns/index.md +31 -0
- package/expertise/design/patterns/microinteractions.md +449 -0
- package/expertise/design/patterns/navigation.md +800 -0
- package/expertise/design/patterns/notifications.md +705 -0
- package/expertise/design/patterns/onboarding.md +700 -0
- package/expertise/design/patterns/search-and-filter.md +601 -0
- package/expertise/design/patterns/settings-and-preferences.md +768 -0
- package/expertise/design/patterns/social-and-community.md +748 -0
- package/expertise/design/platforms/desktop-native.md +612 -0
- package/expertise/design/platforms/index.md +25 -0
- package/expertise/design/platforms/mobile-android.md +825 -0
- package/expertise/design/platforms/mobile-cross-platform.md +983 -0
- package/expertise/design/platforms/mobile-ios.md +699 -0
- package/expertise/design/platforms/tablet.md +794 -0
- package/expertise/design/platforms/web-dashboard.md +790 -0
- package/expertise/design/platforms/web-responsive.md +550 -0
- package/expertise/design/psychology/behavioral-nudges.md +449 -0
- package/expertise/design/psychology/cognitive-load.md +1191 -0
- package/expertise/design/psychology/error-psychology.md +778 -0
- package/expertise/design/psychology/index.md +22 -0
- package/expertise/design/psychology/persuasive-design.md +736 -0
- package/expertise/design/psychology/user-mental-models.md +623 -0
- package/expertise/design/tooling/open-pencil.md +266 -0
- package/expertise/frontend/angular.md +1073 -0
- package/expertise/frontend/desktop-electron.md +546 -0
- package/expertise/frontend/flutter.md +782 -0
- package/expertise/frontend/index.md +27 -0
- package/expertise/frontend/native-android.md +409 -0
- package/expertise/frontend/native-ios.md +490 -0
- package/expertise/frontend/react-native.md +1160 -0
- package/expertise/frontend/react.md +808 -0
- package/expertise/frontend/vue.md +1089 -0
- package/expertise/humanize/domain-rules-code.md +79 -0
- package/expertise/humanize/domain-rules-content.md +67 -0
- package/expertise/humanize/domain-rules-technical-docs.md +56 -0
- package/expertise/humanize/index.md +35 -0
- package/expertise/humanize/self-audit-checklist.md +87 -0
- package/expertise/humanize/sentence-patterns.md +218 -0
- package/expertise/humanize/vocabulary-blacklist.md +105 -0
- package/expertise/i18n/PROGRESS.md +65 -0
- package/expertise/i18n/advanced/accessibility-and-i18n.md +28 -0
- package/expertise/i18n/advanced/bidirectional-text-algorithm.md +38 -0
- package/expertise/i18n/advanced/complex-scripts.md +30 -0
- package/expertise/i18n/advanced/performance-and-i18n.md +27 -0
- package/expertise/i18n/advanced/testing-i18n.md +28 -0
- package/expertise/i18n/content/content-adaptation.md +23 -0
- package/expertise/i18n/content/locale-specific-formatting.md +23 -0
- package/expertise/i18n/content/machine-translation-integration.md +28 -0
- package/expertise/i18n/content/translation-management.md +29 -0
- package/expertise/i18n/foundations/date-time-calendars.md +67 -0
- package/expertise/i18n/foundations/i18n-architecture.md +272 -0
- package/expertise/i18n/foundations/locale-and-language-tags.md +79 -0
- package/expertise/i18n/foundations/numbers-currency-units.md +61 -0
- package/expertise/i18n/foundations/pluralization-and-gender.md +109 -0
- package/expertise/i18n/foundations/string-externalization.md +236 -0
- package/expertise/i18n/foundations/text-direction-bidi.md +241 -0
- package/expertise/i18n/foundations/unicode-and-encoding.md +86 -0
- package/expertise/i18n/index.md +38 -0
- package/expertise/i18n/platform/backend-i18n.md +31 -0
- package/expertise/i18n/platform/flutter-i18n.md +148 -0
- package/expertise/i18n/platform/native-android-i18n.md +36 -0
- package/expertise/i18n/platform/native-ios-i18n.md +36 -0
- package/expertise/i18n/platform/react-i18n.md +103 -0
- package/expertise/i18n/platform/web-css-i18n.md +81 -0
- package/expertise/i18n/rtl/arabic-specific.md +175 -0
- package/expertise/i18n/rtl/hebrew-specific.md +149 -0
- package/expertise/i18n/rtl/rtl-animations-and-transitions.md +111 -0
- package/expertise/i18n/rtl/rtl-forms-and-input.md +161 -0
- package/expertise/i18n/rtl/rtl-fundamentals.md +211 -0
- package/expertise/i18n/rtl/rtl-icons-and-images.md +181 -0
- package/expertise/i18n/rtl/rtl-layout-mirroring.md +252 -0
- package/expertise/i18n/rtl/rtl-navigation-and-gestures.md +107 -0
- package/expertise/i18n/rtl/rtl-testing-and-qa.md +147 -0
- package/expertise/i18n/rtl/rtl-typography.md +160 -0
- package/expertise/index.md +113 -0
- package/expertise/index.yaml +216 -0
- package/expertise/infrastructure/cloud-aws.md +597 -0
- package/expertise/infrastructure/cloud-gcp.md +599 -0
- package/expertise/infrastructure/cybersecurity.md +816 -0
- package/expertise/infrastructure/database-mongodb.md +447 -0
- package/expertise/infrastructure/database-postgres.md +400 -0
- package/expertise/infrastructure/devops-cicd.md +787 -0
- package/expertise/infrastructure/index.md +27 -0
- package/expertise/performance/PROGRESS.md +50 -0
- package/expertise/performance/backend/api-latency.md +1204 -0
- package/expertise/performance/backend/background-jobs.md +506 -0
- package/expertise/performance/backend/connection-pooling.md +1209 -0
- package/expertise/performance/backend/database-query-optimization.md +515 -0
- package/expertise/performance/backend/index.md +23 -0
- package/expertise/performance/backend/rate-limiting-and-throttling.md +971 -0
- package/expertise/performance/foundations/algorithmic-complexity.md +954 -0
- package/expertise/performance/foundations/caching-strategies.md +489 -0
- package/expertise/performance/foundations/concurrency-and-parallelism.md +847 -0
- package/expertise/performance/foundations/index.md +24 -0
- package/expertise/performance/foundations/measuring-and-profiling.md +440 -0
- package/expertise/performance/foundations/memory-management.md +964 -0
- package/expertise/performance/foundations/performance-budgets.md +1314 -0
- package/expertise/performance/index.md +31 -0
- package/expertise/performance/infrastructure/auto-scaling.md +1059 -0
- package/expertise/performance/infrastructure/cdn-and-edge.md +1081 -0
- package/expertise/performance/infrastructure/index.md +22 -0
- package/expertise/performance/infrastructure/load-balancing.md +1081 -0
- package/expertise/performance/infrastructure/observability.md +1079 -0
- package/expertise/performance/mobile/index.md +23 -0
- package/expertise/performance/mobile/mobile-animations.md +544 -0
- package/expertise/performance/mobile/mobile-memory-battery.md +416 -0
- package/expertise/performance/mobile/mobile-network.md +452 -0
- package/expertise/performance/mobile/mobile-rendering.md +599 -0
- package/expertise/performance/mobile/mobile-startup-time.md +505 -0
- package/expertise/performance/platform-specific/flutter-performance.md +647 -0
- package/expertise/performance/platform-specific/index.md +22 -0
- package/expertise/performance/platform-specific/node-performance.md +1307 -0
- package/expertise/performance/platform-specific/postgres-performance.md +1366 -0
- package/expertise/performance/platform-specific/react-performance.md +1403 -0
- package/expertise/performance/web/bundle-optimization.md +1239 -0
- package/expertise/performance/web/image-and-media.md +636 -0
- package/expertise/performance/web/index.md +24 -0
- package/expertise/performance/web/network-optimization.md +1133 -0
- package/expertise/performance/web/rendering-performance.md +1098 -0
- package/expertise/performance/web/ssr-and-hydration.md +918 -0
- package/expertise/performance/web/web-vitals.md +1374 -0
- package/expertise/quality/accessibility.md +985 -0
- package/expertise/quality/evidence-based-verification.md +499 -0
- package/expertise/quality/index.md +24 -0
- package/expertise/quality/ml-model-audit.md +614 -0
- package/expertise/quality/performance.md +600 -0
- package/expertise/quality/testing-api.md +891 -0
- package/expertise/quality/testing-mobile.md +496 -0
- package/expertise/quality/testing-web.md +849 -0
- package/expertise/security/PROGRESS.md +54 -0
- package/expertise/security/agentic-identity.md +540 -0
- package/expertise/security/compliance-frameworks.md +601 -0
- package/expertise/security/data/data-encryption.md +364 -0
- package/expertise/security/data/data-privacy-gdpr.md +692 -0
- package/expertise/security/data/database-security.md +1171 -0
- package/expertise/security/data/index.md +22 -0
- package/expertise/security/data/pii-handling.md +531 -0
- package/expertise/security/foundations/authentication.md +1041 -0
- package/expertise/security/foundations/authorization.md +603 -0
- package/expertise/security/foundations/cryptography.md +1001 -0
- package/expertise/security/foundations/index.md +25 -0
- package/expertise/security/foundations/owasp-top-10.md +1354 -0
- package/expertise/security/foundations/secrets-management.md +1217 -0
- package/expertise/security/foundations/secure-sdlc.md +700 -0
- package/expertise/security/foundations/supply-chain-security.md +698 -0
- package/expertise/security/index.md +31 -0
- package/expertise/security/infrastructure/cloud-security-aws.md +1296 -0
- package/expertise/security/infrastructure/cloud-security-gcp.md +1376 -0
- package/expertise/security/infrastructure/container-security.md +721 -0
- package/expertise/security/infrastructure/incident-response.md +1295 -0
- package/expertise/security/infrastructure/index.md +24 -0
- package/expertise/security/infrastructure/logging-and-monitoring.md +1618 -0
- package/expertise/security/infrastructure/network-security.md +1337 -0
- package/expertise/security/mobile/index.md +23 -0
- package/expertise/security/mobile/mobile-android-security.md +1218 -0
- package/expertise/security/mobile/mobile-binary-protection.md +1229 -0
- package/expertise/security/mobile/mobile-data-storage.md +1265 -0
- package/expertise/security/mobile/mobile-ios-security.md +1401 -0
- package/expertise/security/mobile/mobile-network-security.md +1520 -0
- package/expertise/security/smart-contract-security.md +594 -0
- package/expertise/security/testing/index.md +22 -0
- package/expertise/security/testing/penetration-testing.md +1258 -0
- package/expertise/security/testing/security-code-review.md +1765 -0
- package/expertise/security/testing/threat-modeling.md +1074 -0
- package/expertise/security/testing/vulnerability-scanning.md +1062 -0
- package/expertise/security/web/api-security.md +586 -0
- package/expertise/security/web/cors-and-headers.md +433 -0
- package/expertise/security/web/csrf.md +562 -0
- package/expertise/security/web/file-upload.md +1477 -0
- package/expertise/security/web/index.md +25 -0
- package/expertise/security/web/injection.md +1375 -0
- package/expertise/security/web/session-management.md +1101 -0
- package/expertise/security/web/xss.md +1158 -0
- package/exports/README.md +17 -0
- package/exports/hosts/claude/.claude/agents/clarifier.md +42 -0
- package/exports/hosts/claude/.claude/agents/content-author.md +63 -0
- package/exports/hosts/claude/.claude/agents/designer.md +55 -0
- package/exports/hosts/claude/.claude/agents/executor.md +55 -0
- package/exports/hosts/claude/.claude/agents/learner.md +51 -0
- package/exports/hosts/claude/.claude/agents/planner.md +53 -0
- package/exports/hosts/claude/.claude/agents/researcher.md +43 -0
- package/exports/hosts/claude/.claude/agents/reviewer.md +54 -0
- package/exports/hosts/claude/.claude/agents/specifier.md +47 -0
- package/exports/hosts/claude/.claude/agents/verifier.md +71 -0
- package/exports/hosts/claude/.claude/commands/author.md +42 -0
- package/exports/hosts/claude/.claude/commands/clarify.md +38 -0
- package/exports/hosts/claude/.claude/commands/design-review.md +46 -0
- package/exports/hosts/claude/.claude/commands/design.md +44 -0
- package/exports/hosts/claude/.claude/commands/discover.md +37 -0
- package/exports/hosts/claude/.claude/commands/execute.md +48 -0
- package/exports/hosts/claude/.claude/commands/learn.md +38 -0
- package/exports/hosts/claude/.claude/commands/plan-review.md +42 -0
- package/exports/hosts/claude/.claude/commands/plan.md +39 -0
- package/exports/hosts/claude/.claude/commands/prepare-next.md +37 -0
- package/exports/hosts/claude/.claude/commands/review.md +40 -0
- package/exports/hosts/claude/.claude/commands/run-audit.md +41 -0
- package/exports/hosts/claude/.claude/commands/spec-challenge.md +41 -0
- package/exports/hosts/claude/.claude/commands/specify.md +38 -0
- package/exports/hosts/claude/.claude/commands/verify.md +37 -0
- package/exports/hosts/claude/.claude/settings.json +34 -0
- package/exports/hosts/claude/CLAUDE.md +19 -0
- package/exports/hosts/claude/export.manifest.json +38 -0
- package/exports/hosts/claude/host-package.json +67 -0
- package/exports/hosts/codex/AGENTS.md +19 -0
- package/exports/hosts/codex/export.manifest.json +38 -0
- package/exports/hosts/codex/host-package.json +41 -0
- package/exports/hosts/cursor/.cursor/hooks.json +16 -0
- package/exports/hosts/cursor/.cursor/rules/wazir-core.mdc +19 -0
- package/exports/hosts/cursor/export.manifest.json +38 -0
- package/exports/hosts/cursor/host-package.json +42 -0
- package/exports/hosts/gemini/GEMINI.md +19 -0
- package/exports/hosts/gemini/export.manifest.json +38 -0
- package/exports/hosts/gemini/host-package.json +41 -0
- package/hooks/README.md +18 -0
- package/hooks/definitions/loop_cap_guard.yaml +21 -0
- package/hooks/definitions/post_tool_capture.yaml +24 -0
- package/hooks/definitions/pre_compact_summary.yaml +19 -0
- package/hooks/definitions/pre_tool_capture_route.yaml +19 -0
- package/hooks/definitions/protected_path_write_guard.yaml +19 -0
- package/hooks/definitions/session_start.yaml +19 -0
- package/hooks/definitions/stop_handoff_harvest.yaml +20 -0
- package/hooks/loop-cap-guard +17 -0
- package/hooks/post-tool-lint +36 -0
- package/hooks/protected-path-write-guard +17 -0
- package/hooks/session-start +41 -0
- package/llms-full.txt +2355 -0
- package/llms.txt +43 -0
- package/package.json +79 -0
- package/roles/README.md +20 -0
- package/roles/clarifier.md +42 -0
- package/roles/content-author.md +63 -0
- package/roles/designer.md +55 -0
- package/roles/executor.md +55 -0
- package/roles/learner.md +51 -0
- package/roles/planner.md +53 -0
- package/roles/researcher.md +43 -0
- package/roles/reviewer.md +54 -0
- package/roles/specifier.md +47 -0
- package/roles/verifier.md +71 -0
- package/schemas/README.md +24 -0
- package/schemas/accepted-learning.schema.json +20 -0
- package/schemas/author-artifact.schema.json +156 -0
- package/schemas/clarification.schema.json +19 -0
- package/schemas/design-artifact.schema.json +80 -0
- package/schemas/docs-claim.schema.json +18 -0
- package/schemas/export-manifest.schema.json +20 -0
- package/schemas/hook.schema.json +67 -0
- package/schemas/host-export-package.schema.json +18 -0
- package/schemas/implementation-plan.schema.json +19 -0
- package/schemas/proposed-learning.schema.json +19 -0
- package/schemas/research.schema.json +18 -0
- package/schemas/review.schema.json +29 -0
- package/schemas/run-manifest.schema.json +18 -0
- package/schemas/spec-challenge.schema.json +18 -0
- package/schemas/spec.schema.json +20 -0
- package/schemas/usage.schema.json +102 -0
- package/schemas/verification-proof.schema.json +29 -0
- package/schemas/wazir-manifest.schema.json +173 -0
- package/skills/README.md +40 -0
- package/skills/brainstorming/SKILL.md +77 -0
- package/skills/debugging/SKILL.md +50 -0
- package/skills/design/SKILL.md +61 -0
- package/skills/dispatching-parallel-agents/SKILL.md +128 -0
- package/skills/executing-plans/SKILL.md +70 -0
- package/skills/finishing-a-development-branch/SKILL.md +169 -0
- package/skills/humanize/SKILL.md +123 -0
- package/skills/init-pipeline/SKILL.md +124 -0
- package/skills/prepare-next/SKILL.md +20 -0
- package/skills/receiving-code-review/SKILL.md +123 -0
- package/skills/requesting-code-review/SKILL.md +105 -0
- package/skills/requesting-code-review/code-reviewer.md +108 -0
- package/skills/run-audit/SKILL.md +197 -0
- package/skills/scan-project/SKILL.md +41 -0
- package/skills/self-audit/SKILL.md +153 -0
- package/skills/subagent-driven-development/SKILL.md +154 -0
- package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -0
- package/skills/subagent-driven-development/implementer-prompt.md +102 -0
- package/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/skills/tdd/SKILL.md +23 -0
- package/skills/using-git-worktrees/SKILL.md +163 -0
- package/skills/using-skills/SKILL.md +95 -0
- package/skills/verification/SKILL.md +22 -0
- package/skills/wazir/SKILL.md +463 -0
- package/skills/writing-plans/SKILL.md +30 -0
- package/skills/writing-skills/SKILL.md +157 -0
- package/skills/writing-skills/anthropic-best-practices.md +122 -0
- package/skills/writing-skills/persuasion-principles.md +50 -0
- package/templates/README.md +20 -0
- package/templates/artifacts/README.md +10 -0
- package/templates/artifacts/accepted-learning.md +19 -0
- package/templates/artifacts/accepted-learning.template.json +12 -0
- package/templates/artifacts/author.md +74 -0
- package/templates/artifacts/author.template.json +19 -0
- package/templates/artifacts/clarification.md +21 -0
- package/templates/artifacts/clarification.template.json +12 -0
- package/templates/artifacts/execute-notes.md +19 -0
- package/templates/artifacts/implementation-plan.md +21 -0
- package/templates/artifacts/implementation-plan.template.json +11 -0
- package/templates/artifacts/learning-proposal.md +19 -0
- package/templates/artifacts/next-run-handoff.md +21 -0
- package/templates/artifacts/plan-review.md +19 -0
- package/templates/artifacts/proposed-learning.template.json +12 -0
- package/templates/artifacts/research.md +21 -0
- package/templates/artifacts/research.template.json +12 -0
- package/templates/artifacts/review-findings.md +19 -0
- package/templates/artifacts/review.template.json +11 -0
- package/templates/artifacts/run-manifest.template.json +8 -0
- package/templates/artifacts/spec-challenge.md +19 -0
- package/templates/artifacts/spec-challenge.template.json +11 -0
- package/templates/artifacts/spec.md +21 -0
- package/templates/artifacts/spec.template.json +12 -0
- package/templates/artifacts/verification-proof.md +19 -0
- package/templates/artifacts/verification-proof.template.json +11 -0
- package/templates/examples/accepted-learning.example.json +14 -0
- package/templates/examples/author.example.json +152 -0
- package/templates/examples/clarification.example.json +15 -0
- package/templates/examples/docs-claim.example.json +8 -0
- package/templates/examples/export-manifest.example.json +7 -0
- package/templates/examples/host-export-package.example.json +11 -0
- package/templates/examples/implementation-plan.example.json +17 -0
- package/templates/examples/proposed-learning.example.json +13 -0
- package/templates/examples/research.example.json +15 -0
- package/templates/examples/research.example.md +6 -0
- package/templates/examples/review.example.json +17 -0
- package/templates/examples/run-manifest.example.json +9 -0
- package/templates/examples/spec-challenge.example.json +14 -0
- package/templates/examples/spec.example.json +21 -0
- package/templates/examples/verification-proof.example.json +21 -0
- package/templates/examples/wazir-manifest.example.yaml +65 -0
- package/templates/task-definition-schema.md +99 -0
- package/tooling/README.md +20 -0
- package/tooling/src/adapters/context-mode.js +50 -0
- package/tooling/src/capture/command.js +376 -0
- package/tooling/src/capture/store.js +99 -0
- package/tooling/src/capture/usage.js +270 -0
- package/tooling/src/checks/branches.js +50 -0
- package/tooling/src/checks/brand-truth.js +110 -0
- package/tooling/src/checks/changelog.js +231 -0
- package/tooling/src/checks/command-registry.js +36 -0
- package/tooling/src/checks/commits.js +102 -0
- package/tooling/src/checks/docs-drift.js +103 -0
- package/tooling/src/checks/docs-truth.js +201 -0
- package/tooling/src/checks/runtime-surface.js +156 -0
- package/tooling/src/cli.js +116 -0
- package/tooling/src/command-options.js +56 -0
- package/tooling/src/commands/validate.js +320 -0
- package/tooling/src/doctor/command.js +91 -0
- package/tooling/src/export/command.js +77 -0
- package/tooling/src/export/compiler.js +498 -0
- package/tooling/src/guards/loop-cap-guard.js +52 -0
- package/tooling/src/guards/protected-path-write-guard.js +67 -0
- package/tooling/src/index/command.js +152 -0
- package/tooling/src/index/storage.js +1061 -0
- package/tooling/src/index/summarizers.js +261 -0
- package/tooling/src/loaders.js +18 -0
- package/tooling/src/project-root.js +22 -0
- package/tooling/src/recall/command.js +225 -0
- package/tooling/src/schema-validator.js +30 -0
- package/tooling/src/state-root.js +40 -0
- package/tooling/src/status/command.js +71 -0
- package/wazir.manifest.yaml +135 -0
- package/workflows/README.md +19 -0
- package/workflows/author.md +42 -0
- package/workflows/clarify.md +38 -0
- package/workflows/design-review.md +46 -0
- package/workflows/design.md +44 -0
- package/workflows/discover.md +37 -0
- package/workflows/execute.md +48 -0
- package/workflows/learn.md +38 -0
- package/workflows/plan-review.md +42 -0
- package/workflows/plan.md +39 -0
- package/workflows/prepare-next.md +37 -0
- package/workflows/review.md +40 -0
- package/workflows/run-audit.md +41 -0
- package/workflows/spec-challenge.md +41 -0
- package/workflows/specify.md +38 -0
- package/workflows/verify.md +37 -0
|
@@ -0,0 +1,1314 @@
|
|
|
1
|
+
# Performance Budgets -- Performance Expertise Module
|
|
2
|
+
|
|
3
|
+
> Performance budgets are predefined limits on metrics that affect user experience -- page weight, load time, time to interactive, API response time. They transform performance from a subjective "feels fast" into a measurable engineering constraint that can be enforced in CI, tracked over time, and tied directly to business outcomes.
|
|
4
|
+
|
|
5
|
+
> **Impact:** Critical
|
|
6
|
+
> **Applies to:** All (Web, Mobile, Backend, Infrastructure)
|
|
7
|
+
> **Key metrics:** Largest Contentful Paint (LCP), Interaction to Next Paint (INP), Cumulative Layout Shift (CLS), Total Bundle Size, API p95 Latency, Database Query p95
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Why This Matters
|
|
12
|
+
|
|
13
|
+
Performance is not a nice-to-have. It is a revenue lever, a retention mechanism, and an SEO ranking signal. Every millisecond of delay has a measurable cost.
|
|
14
|
+
|
|
15
|
+
### Business Impact -- Real Numbers
|
|
16
|
+
|
|
17
|
+
| Company | Finding | Source |
|
|
18
|
+
|---------|---------|--------|
|
|
19
|
+
| Amazon | Every 100ms of added latency cost 1% in sales | Conductor / Greg Linden (2006) |
|
|
20
|
+
| Google | 500ms additional load time caused a 20% drop in traffic | Google research |
|
|
21
|
+
| Walmart | Accelerating page load by 100ms increased incremental revenue measurably | Walmart Labs engineering |
|
|
22
|
+
| Vodafone Italy | Improving LCP by 31% drove 8% more sales | web.dev case study |
|
|
23
|
+
| Rakuten 24 | Improved Core Web Vitals led to 53.4% increase in revenue per visitor, 33.1% increase in conversion rate, 15.2% increase in average order value | web.dev case study |
|
|
24
|
+
| Cdiscount | Improving all 3 Core Web Vitals contributed to 6% revenue uplift during Black Friday | web.dev case study |
|
|
25
|
+
| The Telegraph | An 8-second load delay caused a 17.52% decrease in pageviews | WPO Stats |
|
|
26
|
+
| Pinterest | Reducing perceived wait time by 40% increased search engine traffic by 15% and sign-ups by 15% | WPO Stats |
|
|
27
|
+
|
|
28
|
+
### Human Perception Thresholds
|
|
29
|
+
|
|
30
|
+
Understanding how humans perceive delay is essential to setting meaningful budgets:
|
|
31
|
+
|
|
32
|
+
| Delay | Perception |
|
|
33
|
+
|-------|------------|
|
|
34
|
+
| 0-100ms | Feels instantaneous. Users perceive direct manipulation. |
|
|
35
|
+
| 100-300ms | Slight delay noticed, but flow of thought is unbroken. |
|
|
36
|
+
| 300-1000ms | Noticeable lag. Users sense the system is working. |
|
|
37
|
+
| 1000-3000ms | Users lose focus. They may switch tabs. |
|
|
38
|
+
| 3000-5000ms | Frustration sets in. Significant abandonment begins. |
|
|
39
|
+
| >5000ms | Task abandonment. 53% of mobile users leave if load exceeds 3s (Google). |
|
|
40
|
+
|
|
41
|
+
### SEO and Ranking Signal
|
|
42
|
+
|
|
43
|
+
Google uses Core Web Vitals as a ranking factor. As of 2025, only 48% of mobile pages and 56% of desktop pages pass all three Core Web Vitals (LCP, INP, CLS). Pages that pass get preferential treatment in search rankings. Performance budgets are the mechanism that ensures your pages stay in the passing zone.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Performance Budgets and Targets
|
|
48
|
+
|
|
49
|
+
### Core Web Vitals Thresholds (2025)
|
|
50
|
+
|
|
51
|
+
Google evaluates Core Web Vitals at the 75th percentile (p75) of real user data. This means 75% of page visits must have a "good" experience for the page to pass.
|
|
52
|
+
|
|
53
|
+
| Metric | Good | Needs Improvement | Poor |
|
|
54
|
+
|--------|------|--------------------|------|
|
|
55
|
+
| LCP (Largest Contentful Paint) | <=2.5s | 2.5s-4.0s | >4.0s |
|
|
56
|
+
| INP (Interaction to Next Paint) | <=200ms | 200ms-500ms | >500ms |
|
|
57
|
+
| CLS (Cumulative Layout Shift) | <=0.1 | 0.1-0.25 | >0.25 |
|
|
58
|
+
|
|
59
|
+
Note: INP replaced First Input Delay (FID) as a Core Web Vital in March 2024. INP measures responsiveness across the entire page lifecycle, not just the first interaction.
|
|
60
|
+
|
|
61
|
+
### Frontend Resource Budgets
|
|
62
|
+
|
|
63
|
+
| Resource | Consumer App (Good) | Consumer App (Acceptable) | Enterprise/Internal (Acceptable) |
|
|
64
|
+
|----------|---------------------|---------------------------|----------------------------------|
|
|
65
|
+
| Total page weight (compressed) | <500 KB | <1 MB | <2 MB |
|
|
66
|
+
| JavaScript (compressed) | <170 KB | <400 KB | <800 KB |
|
|
67
|
+
| CSS (compressed) | <50 KB | <100 KB | <200 KB |
|
|
68
|
+
| Images (total per page) | <500 KB | <1 MB | <2 MB |
|
|
69
|
+
| Fonts (all files) | <100 KB | <200 KB | <300 KB |
|
|
70
|
+
| Third-party scripts | <100 KB | <250 KB | <400 KB |
|
|
71
|
+
| Document (HTML) | <18 KB | <50 KB | <100 KB |
|
|
72
|
+
|
|
73
|
+
### Timing Budgets by Application Type
|
|
74
|
+
|
|
75
|
+
| Metric | Consumer Mobile | Consumer Desktop | Enterprise SPA | Internal Tool |
|
|
76
|
+
|--------|----------------|-----------------|----------------|---------------|
|
|
77
|
+
| LCP | <2.0s | <2.5s | <3.0s | <4.0s |
|
|
78
|
+
| INP | <150ms | <200ms | <300ms | <500ms |
|
|
79
|
+
| CLS | <0.05 | <0.1 | <0.1 | <0.25 |
|
|
80
|
+
| Time to First Byte (TTFB) | <600ms | <800ms | <1.0s | <1.5s |
|
|
81
|
+
| First Contentful Paint (FCP) | <1.5s | <1.8s | <2.5s | <3.0s |
|
|
82
|
+
| Total Blocking Time (TBT) | <200ms | <300ms | <500ms | <800ms |
|
|
83
|
+
|
|
84
|
+
E-commerce sites should use the strictest thresholds -- lower LCP (2.0s vs 2.5s), tighter INP (150ms vs 200ms), and stricter CLS (0.05 vs 0.1) because conversion-critical pages must feel instant.
|
|
85
|
+
|
|
86
|
+
### Backend and API Budgets
|
|
87
|
+
|
|
88
|
+
| Metric | Good | Acceptable | Needs Work |
|
|
89
|
+
|--------|------|------------|------------|
|
|
90
|
+
| API response p50 | <100ms | <200ms | >500ms |
|
|
91
|
+
| API response p95 | <300ms | <800ms | >1500ms |
|
|
92
|
+
| API response p99 | <1000ms | <2000ms | >5000ms |
|
|
93
|
+
| Database query p50 | <10ms | <50ms | >100ms |
|
|
94
|
+
| Database query p95 | <50ms | <200ms | >500ms |
|
|
95
|
+
| Database query p99 | <200ms | <500ms | >1000ms |
|
|
96
|
+
| Slow query log threshold | 200ms | 500ms | 1000ms |
|
|
97
|
+
|
|
98
|
+
Best-in-class API response times are 100-300ms. Responses under 100ms are perceived as instantaneous by users. The 100-300ms range causes no disruption to flow of thought.
|
|
99
|
+
|
|
100
|
+
Structure latency SLOs as: "95% of checkout requests complete under 300ms over 30 days" -- the 5% overage serves as your latency error budget.
|
|
101
|
+
|
|
102
|
+
### Mobile-Specific Considerations
|
|
103
|
+
|
|
104
|
+
Mobile devices have 4-8x less processing power than desktop. A JavaScript bundle that parses in 200ms on a MacBook Pro can take 2-4 seconds on a mid-range Android phone. Budget accordingly:
|
|
105
|
+
|
|
106
|
+
- Target devices: Moto G Power (or equivalent ~$200 Android phone)
|
|
107
|
+
- Network: Regular 4G (9 Mbps down, 1.5 Mbps up, 170ms RTT)
|
|
108
|
+
- JS budget for mobile: <130-170 KB compressed critical-path JavaScript
|
|
109
|
+
- Total critical resource budget depends on composition -- the more JS, the smaller other resources must be
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Measurement and Profiling
|
|
114
|
+
|
|
115
|
+
### Lab vs Field Data
|
|
116
|
+
|
|
117
|
+
| Aspect | Lab (Synthetic) | Field (RUM) |
|
|
118
|
+
|--------|----------------|-------------|
|
|
119
|
+
| Tool examples | Lighthouse, WebPageTest | CrUX, SpeedCurve, DebugBear |
|
|
120
|
+
| Controls | Consistent network, CPU | Real user conditions |
|
|
121
|
+
| Use case | CI enforcement, debugging | Understanding real user experience |
|
|
122
|
+
| Weakness | Does not reflect real diversity | Noisy, harder to action |
|
|
123
|
+
| When to use | Every PR/deploy | Continuous monitoring |
|
|
124
|
+
|
|
125
|
+
Start with field data (RUM) to identify weaknesses, then use lab tools (Lighthouse) to diagnose and fix. Most teams do this backwards.
|
|
126
|
+
|
|
127
|
+
### Lighthouse CI Setup -- Step by Step
|
|
128
|
+
|
|
129
|
+
1. Install Lighthouse CI:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
npm install -g @lhci/cli
|
|
133
|
+
# or as a dev dependency
|
|
134
|
+
npm install --save-dev @lhci/cli
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
2. Create `budget.json` at project root:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
[
|
|
141
|
+
{
|
|
142
|
+
"path": "/*",
|
|
143
|
+
"resourceSizes": [
|
|
144
|
+
{ "resourceType": "document", "budget": 18 },
|
|
145
|
+
{ "resourceType": "script", "budget": 170 },
|
|
146
|
+
{ "resourceType": "stylesheet", "budget": 50 },
|
|
147
|
+
{ "resourceType": "image", "budget": 500 },
|
|
148
|
+
{ "resourceType": "font", "budget": 100 },
|
|
149
|
+
{ "resourceType": "third-party", "budget": 100 },
|
|
150
|
+
{ "resourceType": "total", "budget": 500 }
|
|
151
|
+
],
|
|
152
|
+
"resourceCounts": [
|
|
153
|
+
{ "resourceType": "script", "budget": 15 },
|
|
154
|
+
{ "resourceType": "third-party", "budget": 5 },
|
|
155
|
+
{ "resourceType": "total", "budget": 50 }
|
|
156
|
+
],
|
|
157
|
+
"timings": [
|
|
158
|
+
{ "metric": "interactive", "budget": 3000 },
|
|
159
|
+
{ "metric": "first-contentful-paint", "budget": 1500 },
|
|
160
|
+
{ "metric": "largest-contentful-paint", "budget": 2500 },
|
|
161
|
+
{ "metric": "cumulative-layout-shift", "budget": 0.1 },
|
|
162
|
+
{ "metric": "total-blocking-time", "budget": 300 }
|
|
163
|
+
]
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"path": "/checkout/*",
|
|
167
|
+
"timings": [
|
|
168
|
+
{ "metric": "interactive", "budget": 2000 },
|
|
169
|
+
{ "metric": "largest-contentful-paint", "budget": 2000 }
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Note: `resourceSizes` budgets are in KB (kilobytes). Timing budgets are in milliseconds.
|
|
176
|
+
|
|
177
|
+
3. Create `.lighthouserc.js`:
|
|
178
|
+
|
|
179
|
+
```javascript
|
|
180
|
+
module.exports = {
|
|
181
|
+
ci: {
|
|
182
|
+
collect: {
|
|
183
|
+
url: [
|
|
184
|
+
'http://localhost:3000/',
|
|
185
|
+
'http://localhost:3000/products',
|
|
186
|
+
'http://localhost:3000/checkout',
|
|
187
|
+
],
|
|
188
|
+
numberOfRuns: 3,
|
|
189
|
+
settings: {
|
|
190
|
+
budgetPath: './budget.json',
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
assert: {
|
|
194
|
+
assertions: {
|
|
195
|
+
'performance-budget': 'error',
|
|
196
|
+
'categories:performance': ['error', { minScore: 0.9 }],
|
|
197
|
+
'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
|
|
198
|
+
'total-blocking-time': ['error', { maxNumericValue: 300 }],
|
|
199
|
+
'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
upload: {
|
|
203
|
+
target: 'temporary-public-storage',
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
4. Create GitHub Actions workflow (`.github/workflows/lighthouse.yml`):
|
|
210
|
+
|
|
211
|
+
```yaml
|
|
212
|
+
name: Lighthouse CI
|
|
213
|
+
on:
|
|
214
|
+
pull_request:
|
|
215
|
+
branches: [main]
|
|
216
|
+
|
|
217
|
+
jobs:
|
|
218
|
+
lighthouse:
|
|
219
|
+
runs-on: ubuntu-latest
|
|
220
|
+
steps:
|
|
221
|
+
- uses: actions/checkout@v4
|
|
222
|
+
|
|
223
|
+
- name: Setup Node
|
|
224
|
+
uses: actions/setup-node@v4
|
|
225
|
+
with:
|
|
226
|
+
node-version: 20
|
|
227
|
+
|
|
228
|
+
- name: Install and Build
|
|
229
|
+
run: |
|
|
230
|
+
npm ci
|
|
231
|
+
npm run build
|
|
232
|
+
|
|
233
|
+
- name: Start server
|
|
234
|
+
run: npm run start &
|
|
235
|
+
|
|
236
|
+
- name: Audit URLs using Lighthouse
|
|
237
|
+
uses: treosh/lighthouse-ci-action@v12
|
|
238
|
+
with:
|
|
239
|
+
urls: |
|
|
240
|
+
http://localhost:3000/
|
|
241
|
+
http://localhost:3000/products
|
|
242
|
+
budgetPath: ./budget.json
|
|
243
|
+
uploadArtifacts: true
|
|
244
|
+
temporaryPublicStorage: true
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Bundle Size Monitoring with bundlesize
|
|
248
|
+
|
|
249
|
+
```json
|
|
250
|
+
// package.json
|
|
251
|
+
{
|
|
252
|
+
"bundlesize": [
|
|
253
|
+
{
|
|
254
|
+
"path": "./dist/main.*.js",
|
|
255
|
+
"maxSize": "170 kB",
|
|
256
|
+
"compression": "gzip"
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
"path": "./dist/vendor.*.js",
|
|
260
|
+
"maxSize": "250 kB",
|
|
261
|
+
"compression": "gzip"
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"path": "./dist/*.css",
|
|
265
|
+
"maxSize": "50 kB",
|
|
266
|
+
"compression": "gzip"
|
|
267
|
+
}
|
|
268
|
+
]
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Run in CI: `npx bundlesize`
|
|
273
|
+
|
|
274
|
+
### webpack-bundle-analyzer
|
|
275
|
+
|
|
276
|
+
Three size metrics to monitor:
|
|
277
|
+
|
|
278
|
+
| Metric | Meaning | Typical ratio |
|
|
279
|
+
|--------|---------|---------------|
|
|
280
|
+
| Stat size | Raw source before processing | Baseline (e.g., 556 KB) |
|
|
281
|
+
| Parsed size | After minification | ~43% of stat (e.g., 242 KB) |
|
|
282
|
+
| Gzipped size | After compression | ~14% of stat (e.g., 80 KB) |
|
|
283
|
+
|
|
284
|
+
```javascript
|
|
285
|
+
// webpack.config.js
|
|
286
|
+
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
|
287
|
+
|
|
288
|
+
module.exports = {
|
|
289
|
+
plugins: [
|
|
290
|
+
new BundleAnalyzerPlugin({
|
|
291
|
+
analyzerMode: 'static', // generates HTML report
|
|
292
|
+
reportFilename: 'bundle-report.html',
|
|
293
|
+
openAnalyzer: false, // do not auto-open in CI
|
|
294
|
+
generateStatsFile: true,
|
|
295
|
+
statsFilename: 'bundle-stats.json',
|
|
296
|
+
}),
|
|
297
|
+
],
|
|
298
|
+
};
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Common Bottlenecks
|
|
304
|
+
|
|
305
|
+
The following are the most frequent causes of budget violations, ranked by how often they occur in real codebases.
|
|
306
|
+
|
|
307
|
+
### 1. Unoptimized Images (frequency: very high)
|
|
308
|
+
|
|
309
|
+
- **Cause:** Serving JPEG/PNG when WebP/AVIF would be 30-50% smaller. No responsive sizing.
|
|
310
|
+
- **Detection:** Lighthouse "Serve images in next-gen formats" audit. Check total image weight in DevTools Network tab.
|
|
311
|
+
- **Fix:** Convert to WebP (30% smaller than JPEG) or AVIF (50% smaller than JPEG). Use `<picture>` with `srcset`. Lazy-load below-fold images. Example: a 337 KB JPEG becomes 122 KB as WebP -- instant 64% reduction.
|
|
312
|
+
- **Trade-off:** AVIF encoding is slower (2-5x vs WebP). AVIF browser support is ~93% vs WebP at ~97%.
|
|
313
|
+
|
|
314
|
+
### 2. Oversized JavaScript Bundles (frequency: very high)
|
|
315
|
+
|
|
316
|
+
- **Cause:** No code splitting. Importing entire libraries (e.g., all of lodash for one function). No tree shaking.
|
|
317
|
+
- **Detection:** webpack-bundle-analyzer treemap. `import-cost` VS Code extension. Bundlesize CI check.
|
|
318
|
+
- **Fix:** Dynamic imports, tree-shakeable imports, lighter alternatives. See Optimization Patterns below.
|
|
319
|
+
- **Trade-off:** Code splitting adds complexity and waterfall requests. Balance chunk count vs chunk size.
|
|
320
|
+
|
|
321
|
+
### 3. Render-Blocking Resources (frequency: high)
|
|
322
|
+
|
|
323
|
+
- **Cause:** Large CSS files in `<head>` without `media` attributes. Synchronous `<script>` tags without `defer` or `async`.
|
|
324
|
+
- **Detection:** Lighthouse "Eliminate render-blocking resources" audit. FCP and LCP correlation.
|
|
325
|
+
- **Fix:** Inline critical CSS (<14 KB). Load non-critical CSS asynchronously. Add `defer` to scripts.
|
|
326
|
+
- **Trade-off:** Inlining CSS increases HTML size and loses caching benefits.
|
|
327
|
+
|
|
328
|
+
### 4. Too Many Third-Party Scripts (frequency: high)
|
|
329
|
+
|
|
330
|
+
- **Cause:** Analytics, tag managers, chat widgets, A/B testing tools. Each adds 20-100 KB and often blocks main thread.
|
|
331
|
+
- **Detection:** Lighthouse "Reduce the impact of third-party code" audit. Chrome DevTools Third-Party Web.
|
|
332
|
+
- **Fix:** Audit necessity. Load non-critical scripts after `load` event. Use `async` or `defer`. Set a dedicated third-party budget of <100 KB.
|
|
333
|
+
- **Trade-off:** Removing analytics may reduce business visibility. Negotiate with stakeholders.
|
|
334
|
+
|
|
335
|
+
### 5. Uncompressed Font Files (frequency: high)
|
|
336
|
+
|
|
337
|
+
- **Cause:** Using TTF/OTF instead of WOFF2. Loading full character sets for single-language sites.
|
|
338
|
+
- **Detection:** Check font file sizes in Network tab. Lighthouse "Ensure text remains visible during webfont load."
|
|
339
|
+
- **Fix:** Convert to WOFF2 (30% smaller than WOFF via Brotli compression). Subset fonts (70-79% reduction for single-language sites). A 173 KB WOFF font becomes 99 KB as WOFF2, then 21 KB after subsetting -- 88% total reduction.
|
|
340
|
+
- **Trade-off:** Subsetting removes characters needed if you add language support later.
|
|
341
|
+
|
|
342
|
+
### 6. Unnecessary Polyfills (frequency: medium-high)
|
|
343
|
+
|
|
344
|
+
- **Cause:** Libraries shipping polyfills for features supported since IE9. One project reduced 97 dependencies to 15 -- 82 were unnecessary polyfills.
|
|
345
|
+
- **Detection:** Bundle analyzer showing `core-js`, `es6-promise`, `object-assign` in modern builds. Research shows 50.6% of npm dependencies are bloated.
|
|
346
|
+
- **Fix:** Set `browserslist` to target only supported browsers. Use `useBuiltIns: 'usage'` in Babel. Remove polyfills for features in your browser matrix.
|
|
347
|
+
- **Trade-off:** Dropping old browser support may exclude a small user segment. Check your analytics.
|
|
348
|
+
|
|
349
|
+
### 7. Large Monolithic CSS (frequency: medium)
|
|
350
|
+
|
|
351
|
+
- **Cause:** Single CSS file with every style for every page. No purging of unused rules.
|
|
352
|
+
- **Detection:** Chrome DevTools Coverage tab. Lighthouse "Reduce unused CSS."
|
|
353
|
+
- **Fix:** PurgeCSS or Tailwind's built-in purge. CSS code splitting per route. Typical reduction: 50-90% of CSS eliminated.
|
|
354
|
+
- **Trade-off:** Aggressive purging can remove dynamically-applied classes. Requires safelisting.
|
|
355
|
+
|
|
356
|
+
### 8. Unoptimized Database Queries (frequency: medium)
|
|
357
|
+
|
|
358
|
+
- **Cause:** N+1 queries. Missing indexes. Full table scans on large tables.
|
|
359
|
+
- **Detection:** Slow query log (PostgreSQL `log_min_duration_statement = 200`). APM tools showing p95 > 200ms.
|
|
360
|
+
- **Fix:** Add indexes. Use eager loading. Enable query plan caching. Start slow query threshold at 1000ms, fix top offenders, lower to 500ms, repeat.
|
|
361
|
+
- **Trade-off:** Indexes speed reads but slow writes and consume storage.
|
|
362
|
+
|
|
363
|
+
### 9. No CDN or Poor Caching (frequency: medium)
|
|
364
|
+
|
|
365
|
+
- **Cause:** Serving static assets from origin server. Short or missing `Cache-Control` headers.
|
|
366
|
+
- **Detection:** TTFB > 600ms. Repeat visit performance same as first visit. Check response headers.
|
|
367
|
+
- **Fix:** CDN for static assets. `Cache-Control: public, max-age=31536000, immutable` for hashed assets. Short TTL for HTML.
|
|
368
|
+
- **Trade-off:** Cache invalidation complexity. Stale content risk for non-hashed assets.
|
|
369
|
+
|
|
370
|
+
### 10. Layout Thrashing and Forced Reflows (frequency: medium)
|
|
371
|
+
|
|
372
|
+
- **Cause:** Reading layout properties (offsetHeight) then writing (style changes) in a loop. Missing `width`/`height` on images and iframes.
|
|
373
|
+
- **Detection:** Chrome DevTools Performance tab showing long "Layout" tasks. CLS > 0.1.
|
|
374
|
+
- **Fix:** Batch DOM reads before writes. Always set explicit dimensions on media elements. Use `aspect-ratio` CSS.
|
|
375
|
+
- **Trade-off:** Setting explicit dimensions requires knowing sizes upfront; responsive designs need additional CSS.
|
|
376
|
+
|
|
377
|
+
### 11. Synchronous API Waterfalls (frequency: medium)
|
|
378
|
+
|
|
379
|
+
- **Cause:** Sequential API calls where parallel requests would work. Component tree causing request chains.
|
|
380
|
+
- **Detection:** DevTools Network tab showing staircase pattern. Time between TTFB and LCP > 1s.
|
|
381
|
+
- **Fix:** `Promise.all()` for independent requests. Server-side data aggregation. GraphQL to reduce round trips.
|
|
382
|
+
- **Trade-off:** Parallel requests increase peak server load. Error handling becomes more complex.
|
|
383
|
+
|
|
384
|
+
### 12. Memory Leaks Causing Jank (frequency: low-medium)
|
|
385
|
+
|
|
386
|
+
- **Cause:** Event listeners not removed on unmount. Detached DOM nodes. Growing closures.
|
|
387
|
+
- **Detection:** Chrome DevTools Memory tab. Increasing heap size over session. INP degradation over time.
|
|
388
|
+
- **Fix:** Proper cleanup in `useEffect` return. WeakRef for caches. Regular heap snapshot comparison.
|
|
389
|
+
- **Trade-off:** Aggressive garbage collection can cause brief pauses.
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## Optimization Patterns
|
|
394
|
+
|
|
395
|
+
### 1. Code Splitting and Lazy Loading
|
|
396
|
+
|
|
397
|
+
**Before:**
|
|
398
|
+
```javascript
|
|
399
|
+
// Imports everything upfront -- 556 KB stat / 242 KB parsed / 80 KB gzip
|
|
400
|
+
import { Dashboard } from './Dashboard';
|
|
401
|
+
import { Settings } from './Settings';
|
|
402
|
+
import { Analytics } from './Analytics';
|
|
403
|
+
import { AdminPanel } from './AdminPanel';
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
**After:**
|
|
407
|
+
```javascript
|
|
408
|
+
// Route-based splitting -- initial bundle drops to 72 KB gzip
|
|
409
|
+
import { lazy, Suspense } from 'react';
|
|
410
|
+
|
|
411
|
+
const Dashboard = lazy(() => import('./Dashboard'));
|
|
412
|
+
const Settings = lazy(() => import('./Settings'));
|
|
413
|
+
const Analytics = lazy(() => import('./Analytics'));
|
|
414
|
+
const AdminPanel = lazy(() => import('./AdminPanel'));
|
|
415
|
+
|
|
416
|
+
// Usage
|
|
417
|
+
<Suspense fallback={<Skeleton />}>
|
|
418
|
+
<Dashboard />
|
|
419
|
+
</Suspense>
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
**Measured impact:** Initial bundle reduced from 80 KB to 72 KB gzipped. Each route loaded on demand. Total JS downloaded for typical user session reduced by 40-60% since most users never visit all routes.
|
|
423
|
+
|
|
424
|
+
**Trade-off:** Additional HTTP requests per route. First render of lazy component includes network delay. Mitigate with `<link rel="prefetch">` for likely-next routes.
|
|
425
|
+
|
|
426
|
+
### 2. Tree-Shakeable Imports
|
|
427
|
+
|
|
428
|
+
**Before:**
|
|
429
|
+
```javascript
|
|
430
|
+
// Imports entire lodash -- adds ~70 KB gzipped
|
|
431
|
+
import _ from 'lodash';
|
|
432
|
+
const result = _.debounce(fn, 300);
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
**After:**
|
|
436
|
+
```javascript
|
|
437
|
+
// Named import with tree shaking -- adds ~1 KB gzipped
|
|
438
|
+
import debounce from 'lodash/debounce';
|
|
439
|
+
const result = debounce(fn, 300);
|
|
440
|
+
|
|
441
|
+
// Or use a lighter alternative -- adds ~0.3 KB gzipped
|
|
442
|
+
import { debounce } from 'lodash-es';
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
**Measured impact:** 70 KB reduced to 1 KB or less. MomentJS (64.8% of one team's total bundle) replaced by date-fns (tree-shakeable, use only what you import -- typical savings: 50-65 KB).
|
|
446
|
+
|
|
447
|
+
**Trade-off:** Named imports are more verbose. Some libraries (moment, jQuery) are not tree-shakeable and require replacement.
|
|
448
|
+
|
|
449
|
+
### 3. Image Optimization Pipeline
|
|
450
|
+
|
|
451
|
+
**Before:**
|
|
452
|
+
```html
|
|
453
|
+
<!-- Unoptimized: 337 KB JPEG, no responsive sizing -->
|
|
454
|
+
<img src="/hero.jpg" alt="Hero image">
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
**After:**
|
|
458
|
+
```html
|
|
459
|
+
<!-- Optimized: AVIF/WebP with fallback, responsive, lazy -->
|
|
460
|
+
<picture>
|
|
461
|
+
<source
|
|
462
|
+
type="image/avif"
|
|
463
|
+
srcset="/hero-400.avif 400w, /hero-800.avif 800w, /hero-1200.avif 1200w"
|
|
464
|
+
sizes="(max-width: 768px) 100vw, 50vw"
|
|
465
|
+
>
|
|
466
|
+
<source
|
|
467
|
+
type="image/webp"
|
|
468
|
+
srcset="/hero-400.webp 400w, /hero-800.webp 800w, /hero-1200.webp 1200w"
|
|
469
|
+
sizes="(max-width: 768px) 100vw, 50vw"
|
|
470
|
+
>
|
|
471
|
+
<img
|
|
472
|
+
src="/hero-800.jpg"
|
|
473
|
+
alt="Hero image"
|
|
474
|
+
width="1200"
|
|
475
|
+
height="600"
|
|
476
|
+
loading="lazy"
|
|
477
|
+
decoding="async"
|
|
478
|
+
>
|
|
479
|
+
</picture>
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
**Measured impact:** 337 KB JPEG becomes 122 KB WebP (64% reduction) or ~100 KB AVIF (70% reduction). Responsive sizing means mobile users load 400w variant (~40 KB) instead of 1200w.
|
|
483
|
+
|
|
484
|
+
**Trade-off:** Build pipeline complexity. AVIF encoding is 2-5x slower than WebP. AVIF browser support at ~93% (as of 2025) vs WebP at ~97%.
|
|
485
|
+
|
|
486
|
+
### 4. Font Optimization
|
|
487
|
+
|
|
488
|
+
**Before:**
|
|
489
|
+
```css
|
|
490
|
+
/* Full Latin + Cyrillic + Greek: 173 KB per weight */
|
|
491
|
+
@font-face {
|
|
492
|
+
font-family: 'CustomFont';
|
|
493
|
+
src: url('/fonts/custom.woff') format('woff');
|
|
494
|
+
font-weight: 400;
|
|
495
|
+
}
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
**After:**
|
|
499
|
+
```css
|
|
500
|
+
/* Subsetted Latin-only WOFF2: 21 KB per weight */
|
|
501
|
+
@font-face {
|
|
502
|
+
font-family: 'CustomFont';
|
|
503
|
+
src: url('/fonts/custom-latin.woff2') format('woff2');
|
|
504
|
+
font-weight: 400;
|
|
505
|
+
font-display: swap;
|
|
506
|
+
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F;
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
**Measured impact:** 173 KB WOFF becomes 99 KB WOFF2 (43% reduction from Brotli compression), then 21 KB after subsetting (88% total reduction). `font-display: swap` ensures text is visible within 100ms even before font loads.
|
|
511
|
+
|
|
512
|
+
**Trade-off:** Subsetting removes characters. If you later need Cyrillic support, you must re-generate. `swap` causes a flash of unstyled text (FOUT), which some designs find unacceptable.
|
|
513
|
+
|
|
514
|
+
### 5. Critical CSS Inlining
|
|
515
|
+
|
|
516
|
+
**Before:**
|
|
517
|
+
```html
|
|
518
|
+
<head>
|
|
519
|
+
<!-- 150 KB CSS blocks rendering -->
|
|
520
|
+
<link rel="stylesheet" href="/styles.css">
|
|
521
|
+
</head>
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
**After:**
|
|
525
|
+
```html
|
|
526
|
+
<head>
|
|
527
|
+
<!-- 8 KB critical CSS inlined, rest loaded async -->
|
|
528
|
+
<style>
|
|
529
|
+
/* Critical above-fold styles only */
|
|
530
|
+
body { margin: 0; font-family: system-ui; }
|
|
531
|
+
.header { background: #fff; height: 64px; }
|
|
532
|
+
.hero { min-height: 400px; }
|
|
533
|
+
/* ... above-fold styles ... */
|
|
534
|
+
</style>
|
|
535
|
+
<link rel="preload" href="/styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
|
536
|
+
<noscript><link rel="stylesheet" href="/styles.css"></noscript>
|
|
537
|
+
</head>
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
**Measured impact:** FCP improves by 0.5-1.5s depending on connection speed. Critical CSS should be <14 KB (fits in first TCP round trip after TLS handshake).
|
|
541
|
+
|
|
542
|
+
**Trade-off:** Inlined CSS cannot be cached separately. Must be regenerated when styles change. Tools like `critical` npm package automate extraction.
|
|
543
|
+
|
|
544
|
+
### 6. API Response Optimization
|
|
545
|
+
|
|
546
|
+
**Before:**
|
|
547
|
+
```javascript
|
|
548
|
+
// Returns 250 KB JSON with nested relations
|
|
549
|
+
app.get('/api/products', async (req, res) => {
|
|
550
|
+
const products = await Product.findAll({
|
|
551
|
+
include: [Category, Reviews, Seller, RelatedProducts],
|
|
552
|
+
});
|
|
553
|
+
res.json(products); // p95: 1200ms
|
|
554
|
+
});
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
**After:**
|
|
558
|
+
```javascript
|
|
559
|
+
// Sparse fields, pagination, compression -- 15 KB response
|
|
560
|
+
app.get('/api/products', async (req, res) => {
|
|
561
|
+
const { page = 1, limit = 20, fields } = req.query;
|
|
562
|
+
const products = await Product.findAll({
|
|
563
|
+
attributes: fields ? fields.split(',') : ['id', 'name', 'price', 'thumbnail'],
|
|
564
|
+
limit: Math.min(limit, 100),
|
|
565
|
+
offset: (page - 1) * limit,
|
|
566
|
+
});
|
|
567
|
+
res.json({ data: products, meta: { page, limit, total: await Product.count() } });
|
|
568
|
+
// p95: 45ms
|
|
569
|
+
});
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
**Measured impact:** Response size from 250 KB to 15 KB (94% reduction). p95 latency from 1200ms to 45ms (96% reduction). Key technique: only return fields the client needs.
|
|
573
|
+
|
|
574
|
+
**Trade-off:** Clients must specify fields or accept defaults. Pagination adds complexity for "load all" use cases. Consider GraphQL if field selection needs are highly variable.
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
|
|
578
|
+
## Anti-Patterns
|
|
579
|
+
|
|
580
|
+
### 1. Measuring Only Averages
|
|
581
|
+
|
|
582
|
+
**Why it seems helpful:** Average latency looks good at 150ms.
|
|
583
|
+
**Why it hurts:** The p95 is 2000ms, meaning 5% of users (often your most engaged) have a terrible experience. Always measure p50, p95, and p99.
|
|
584
|
+
|
|
585
|
+
### 2. Testing Only on Fast Devices and Networks
|
|
586
|
+
|
|
587
|
+
**Why it seems helpful:** "Works fine on my MacBook with fiber."
|
|
588
|
+
**Why it hurts:** Your median user is on a $200 Android phone with 4G. A 170 KB JS bundle parses in 200ms on a MacBook but 2-4 seconds on a Moto G. Test on representative hardware.
|
|
589
|
+
|
|
590
|
+
### 3. Over-Polyfilling
|
|
591
|
+
|
|
592
|
+
**Why it seems helpful:** "We support all browsers."
|
|
593
|
+
**Why it hurts:** 50.6% of npm dependencies are bloated. One team found 82 of their 97 dependencies were unnecessary polyfills for features supported since IE9. Ship modern code with differential serving (`type="module"` / `nomodule`).
|
|
594
|
+
|
|
595
|
+
### 4. Adding Dependencies Without Budget Check
|
|
596
|
+
|
|
597
|
+
**Why it seems helpful:** "This library saves us 2 hours of development."
|
|
598
|
+
**Why it hurts:** A single `npm install` can add 50-200 KB to your bundle. MomentJS alone was 64.8% of one team's bundle. Always check `bundlephobia.com` before adding a dependency.
|
|
599
|
+
|
|
600
|
+
### 5. Premature Optimization Without Measurement
|
|
601
|
+
|
|
602
|
+
**Why it seems helpful:** "I memoized everything for performance."
|
|
603
|
+
**Why it hurts:** `useMemo` and `React.memo` have overhead. If the computation is cheap or the component rarely re-renders, memoization adds complexity and memory usage for zero benefit. Measure first with React DevTools Profiler.
|
|
604
|
+
|
|
605
|
+
### 6. Caching Everything Aggressively
|
|
606
|
+
|
|
607
|
+
**Why it seems helpful:** "Cache all API responses for 1 hour."
|
|
608
|
+
**Why it hurts:** Stale data causes bugs that are worse than slow data. Cache static assets aggressively (1 year with immutable). Cache API responses carefully with appropriate TTLs and invalidation strategies.
|
|
609
|
+
|
|
610
|
+
### 7. Lazy Loading Above-the-Fold Content
|
|
611
|
+
|
|
612
|
+
**Why it seems helpful:** "Lazy load all images for performance."
|
|
613
|
+
**Why it hurts:** Lazy loading the hero image or LCP element delays the most important visual. The LCP image should be eagerly loaded with `fetchpriority="high"`. Only lazy-load below-fold content.
|
|
614
|
+
|
|
615
|
+
### 8. Inlining Everything
|
|
616
|
+
|
|
617
|
+
**Why it seems helpful:** "Zero HTTP requests means faster loading."
|
|
618
|
+
**Why it hurts:** Inlined resources cannot be cached. If your HTML is 500 KB because you inlined all CSS, JS, and SVGs, every page navigation downloads it all again. Inline only critical CSS (<14 KB). Cache the rest.
|
|
619
|
+
|
|
620
|
+
### 9. Using a CDN Without Measuring
|
|
621
|
+
|
|
622
|
+
**Why it seems helpful:** "We put it on CloudFront so it is fast."
|
|
623
|
+
**Why it hurts:** CDN misconfiguration is common. Wrong cache headers, origin shield not configured, or CDN edge not serving your target geography. Verify with real user monitoring that TTFB actually improved.
|
|
624
|
+
|
|
625
|
+
### 10. Optimizing Build Size But Ignoring Runtime
|
|
626
|
+
|
|
627
|
+
**Why it seems helpful:** "Our bundle is only 120 KB gzipped."
|
|
628
|
+
**Why it hurts:** A 120 KB bundle that spawns 50ms main-thread tasks every 100ms will still have terrible INP. Bundle size is necessary but not sufficient. Monitor runtime performance (long tasks, layout thrashing, forced reflows).
|
|
629
|
+
|
|
630
|
+
### 11. Splitting Into Too Many Chunks
|
|
631
|
+
|
|
632
|
+
**Why it seems helpful:** "Maximum code splitting for minimum initial load."
|
|
633
|
+
**Why it hurts:** HTTP/2 multiplexing helps, but each chunk still has overhead (DNS, TLS, headers). 50 tiny chunks create waterfall delays and scheduling overhead. Target 5-15 chunks for typical SPAs.
|
|
634
|
+
|
|
635
|
+
### 12. Ignoring Third-Party Script Growth
|
|
636
|
+
|
|
637
|
+
**Why it seems helpful:** "Marketing just needs one more tracking pixel."
|
|
638
|
+
**Why it hurts:** Third-party scripts are the leading cause of performance regression. Each analytics/chat/A/B tool adds 20-100 KB and main-thread work. Set a hard third-party budget and enforce it.
|
|
639
|
+
|
|
640
|
+
---
|
|
641
|
+
|
|
642
|
+
## Architecture-Level Decisions
|
|
643
|
+
|
|
644
|
+
The rendering strategy you choose at the start of a project determines your performance ceiling. Changing later is expensive.
|
|
645
|
+
|
|
646
|
+
### Rendering Strategy Comparison
|
|
647
|
+
|
|
648
|
+
| Strategy | TTFB | FCP | LCP | TTI | JS Bundle | Monthly Cost (mid-size) |
|
|
649
|
+
|----------|------|-----|-----|-----|-----------|------------------------|
|
|
650
|
+
| SSG (Static) | Excellent (<100ms) | Excellent | Excellent | Excellent (minimal JS) | Minimal | <$100 |
|
|
651
|
+
| ISR (Incremental Static) | Excellent (cached) | Excellent | Excellent | Good | Moderate | <$500 |
|
|
652
|
+
| SSR (Server-Side) | Good (200-500ms) | Good | Good | Moderate (hydration) | Large | >$5,000 |
|
|
653
|
+
| CSR (Client-Side) | Excellent (static shell) | Poor (blank until JS) | Poor | Poor (all JS upfront) | Largest | <$100 |
|
|
654
|
+
|
|
655
|
+
**Decision guidance:**
|
|
656
|
+
|
|
657
|
+
- **Content sites, blogs, docs:** SSG. Near-zero JS budget is trivially achievable.
|
|
658
|
+
- **E-commerce, news:** ISR or SSR. Fresh data with good performance. ISR is 10x cheaper than full SSR.
|
|
659
|
+
- **Dashboards, admin panels:** CSR acceptable if behind auth (no SEO need). Strict JS budget still matters for productivity.
|
|
660
|
+
- **Hybrid apps:** Use SSR/SSG for marketing pages, CSR for authenticated app shell. Different budgets per section.
|
|
661
|
+
|
|
662
|
+
### Hydration Cost
|
|
663
|
+
|
|
664
|
+
SSR pages look ready but are not interactive until JavaScript downloads and hydrates. This creates a "uncanny valley" where users click buttons that do not respond. Mitigation strategies:
|
|
665
|
+
|
|
666
|
+
- **Partial hydration / Islands (Astro):** Only hydrate interactive components. Reduces JS by 50-90%.
|
|
667
|
+
- **React Server Components:** Move data fetching to server. Ship less JS to browser. Hydrate only interactive parts.
|
|
668
|
+
- **Progressive hydration:** Hydrate visible components first, defer off-screen. Reduces TBT.
|
|
669
|
+
|
|
670
|
+
### API Design for Latency Budgets
|
|
671
|
+
|
|
672
|
+
| Pattern | Latency Impact | When to Use |
|
|
673
|
+
|---------|---------------|-------------|
|
|
674
|
+
| REST with sparse fields | Low (single request, minimal data) | Most CRUD operations |
|
|
675
|
+
| GraphQL | Low-medium (flexible queries, single request) | Complex data requirements with varying field needs |
|
|
676
|
+
| BFF (Backend for Frontend) | Low (optimized per client) | Mobile vs desktop need different data shapes |
|
|
677
|
+
| gRPC | Very low (binary, multiplexed) | Service-to-service communication |
|
|
678
|
+
| REST without field selection | High (over-fetching) | Avoid in latency-sensitive paths |
|
|
679
|
+
|
|
680
|
+
### Monolith vs Micro-Frontends
|
|
681
|
+
|
|
682
|
+
| Aspect | Monolith | Micro-Frontends |
|
|
683
|
+
|--------|----------|-----------------|
|
|
684
|
+
| Initial bundle | Single optimized bundle | Multiple bundles with shared runtime overhead |
|
|
685
|
+
| Shared dependencies | Natural deduplication | Risk of duplicate React/framework copies (adds 40-100 KB each) |
|
|
686
|
+
| Deployment | All-or-nothing, simpler caching | Independent deploys, complex caching |
|
|
687
|
+
| Budget enforcement | Single budget for entire app | Per-team budgets (easier ownership, harder total control) |
|
|
688
|
+
| Recommendation | Default choice for teams < 50 engineers | Consider only if organizational scaling demands it |
|
|
689
|
+
|
|
690
|
+
---
|
|
691
|
+
|
|
692
|
+
## Testing and Regression Prevention
|
|
693
|
+
|
|
694
|
+
### CI Pipeline Integration
|
|
695
|
+
|
|
696
|
+
A complete performance testing pipeline has three layers:
|
|
697
|
+
|
|
698
|
+
**Layer 1 -- Build-time checks (every commit)**
|
|
699
|
+
```json
|
|
700
|
+
// package.json
|
|
701
|
+
{
|
|
702
|
+
"scripts": {
|
|
703
|
+
"build": "webpack --mode production",
|
|
704
|
+
"postbuild": "bundlesize",
|
|
705
|
+
"perf:budget": "lighthouse-ci autorun"
|
|
706
|
+
},
|
|
707
|
+
"bundlesize": [
|
|
708
|
+
{ "path": "./dist/main.*.js", "maxSize": "170 kB", "compression": "gzip" },
|
|
709
|
+
{ "path": "./dist/vendor.*.js", "maxSize": "250 kB", "compression": "gzip" },
|
|
710
|
+
{ "path": "./dist/*.css", "maxSize": "50 kB", "compression": "gzip" }
|
|
711
|
+
]
|
|
712
|
+
}
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
**Layer 2 -- Lighthouse CI assertions (every PR)**
|
|
716
|
+
```javascript
|
|
717
|
+
// lighthouserc.js
|
|
718
|
+
module.exports = {
|
|
719
|
+
ci: {
|
|
720
|
+
collect: {
|
|
721
|
+
url: ['http://localhost:3000/', 'http://localhost:3000/products'],
|
|
722
|
+
numberOfRuns: 3, // median of 3 runs reduces noise
|
|
723
|
+
},
|
|
724
|
+
assert: {
|
|
725
|
+
preset: 'lighthouse:recommended',
|
|
726
|
+
assertions: {
|
|
727
|
+
'categories:performance': ['error', { minScore: 0.9 }],
|
|
728
|
+
'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
|
|
729
|
+
'total-blocking-time': ['error', { maxNumericValue: 300 }],
|
|
730
|
+
'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
|
|
731
|
+
'performance-budget': 'error',
|
|
732
|
+
// Warn but don't fail for these
|
|
733
|
+
'uses-responsive-images': 'warn',
|
|
734
|
+
'unused-javascript': 'warn',
|
|
735
|
+
},
|
|
736
|
+
},
|
|
737
|
+
},
|
|
738
|
+
};
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
**Layer 3 -- Real User Monitoring (continuous)**
|
|
742
|
+
|
|
743
|
+
```javascript
|
|
744
|
+
// Report Core Web Vitals to your analytics
|
|
745
|
+
import { onLCP, onINP, onCLS } from 'web-vitals';
|
|
746
|
+
|
|
747
|
+
function sendToAnalytics({ name, delta, id, rating }) {
|
|
748
|
+
// rating is 'good', 'needs-improvement', or 'poor'
|
|
749
|
+
fetch('/api/vitals', {
|
|
750
|
+
method: 'POST',
|
|
751
|
+
body: JSON.stringify({ name, delta, id, rating, url: location.href }),
|
|
752
|
+
headers: { 'Content-Type': 'application/json' },
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
onLCP(sendToAnalytics);
|
|
757
|
+
onINP(sendToAnalytics);
|
|
758
|
+
onCLS(sendToAnalytics);
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
### Automated Alerts
|
|
762
|
+
|
|
763
|
+
Set up alerts when budgets are exceeded in production:
|
|
764
|
+
|
|
765
|
+
| Metric | Warning Threshold | Critical Threshold | Alert Channel |
|
|
766
|
+
|--------|-------------------|--------------------| --------------|
|
|
767
|
+
| LCP p75 | >2.5s | >4.0s | Slack + PagerDuty |
|
|
768
|
+
| INP p75 | >200ms | >500ms | Slack |
|
|
769
|
+
| CLS p75 | >0.1 | >0.25 | Slack |
|
|
770
|
+
| JS bundle size | >150 KB gzip | >170 KB gzip | PR comment |
|
|
771
|
+
| API p95 | >300ms | >800ms | Slack + PagerDuty |
|
|
772
|
+
| API p99 | >1000ms | >2000ms | PagerDuty |
|
|
773
|
+
| Error rate | >1% | >5% | PagerDuty |
|
|
774
|
+
|
|
775
|
+
### webpack Performance Hints
|
|
776
|
+
|
|
777
|
+
```javascript
|
|
778
|
+
// webpack.config.js
|
|
779
|
+
module.exports = {
|
|
780
|
+
performance: {
|
|
781
|
+
hints: 'error', // fail build if exceeded
|
|
782
|
+
maxAssetSize: 250000, // 250 KB per asset
|
|
783
|
+
maxEntrypointSize: 500000, // 500 KB total entry
|
|
784
|
+
assetFilter: (assetFilename) => {
|
|
785
|
+
return assetFilename.endsWith('.js') || assetFilename.endsWith('.css');
|
|
786
|
+
},
|
|
787
|
+
},
|
|
788
|
+
};
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
### Budget Review Cadence
|
|
792
|
+
|
|
793
|
+
- **Weekly:** Review RUM dashboard. Check p75 trends for LCP, INP, CLS.
|
|
794
|
+
- **Every 2-4 weeks:** Revisit budget thresholds. Tighten if consistently passing. Investigate if consistently failing.
|
|
795
|
+
- **Quarterly:** Full performance audit. Run WebPageTest on top 10 pages. Compare against competitors. Adjust budgets based on industry shifts.
|
|
796
|
+
|
|
797
|
+
---
|
|
798
|
+
|
|
799
|
+
## Decision Trees
|
|
800
|
+
|
|
801
|
+
### Decision Tree 1: "My Bundle Is Over Budget"
|
|
802
|
+
|
|
803
|
+
```
|
|
804
|
+
Bundle exceeds budget
|
|
805
|
+
|
|
|
806
|
+
+-- Is it first-party code or third-party?
|
|
807
|
+
|
|
|
808
|
+
+-- THIRD-PARTY
|
|
809
|
+
| |
|
|
810
|
+
| +-- Is the library essential?
|
|
811
|
+
| |
|
|
812
|
+
| +-- NO --> Remove it. Check bundlephobia.com for lighter alternatives.
|
|
813
|
+
| +-- YES --> Can you lazy-load it?
|
|
814
|
+
| |
|
|
815
|
+
| +-- YES --> Dynamic import: import('lib').then(...)
|
|
816
|
+
| +-- NO --> Can you use a lighter alternative?
|
|
817
|
+
| |
|
|
818
|
+
| +-- moment (330KB) --> date-fns (tree-shakeable, ~3KB per function)
|
|
819
|
+
| +-- lodash (70KB) --> lodash-es or native JS methods
|
|
820
|
+
| +-- chart.js (200KB) --> lightweight-charts or canvas API
|
|
821
|
+
| +-- NO lighter alternative --> Accept and budget elsewhere
|
|
822
|
+
|
|
|
823
|
+
+-- FIRST-PARTY
|
|
824
|
+
|
|
|
825
|
+
+-- Run webpack-bundle-analyzer. Identify largest modules.
|
|
826
|
+
|
|
|
827
|
+
+-- Is code route-specific?
|
|
828
|
+
| |
|
|
829
|
+
| +-- YES --> Code split by route with React.lazy or dynamic import()
|
|
830
|
+
| +-- NO --> Is it feature-specific?
|
|
831
|
+
| |
|
|
832
|
+
| +-- YES --> Feature-flag gated lazy loading
|
|
833
|
+
| +-- NO --> Review for dead code. Check Coverage tab in DevTools.
|
|
834
|
+
|
|
|
835
|
+
+-- After splitting, still over budget?
|
|
836
|
+
|
|
|
837
|
+
+-- Check for duplicate dependencies (npm ls --all | grep <pkg>)
|
|
838
|
+
+-- Enable tree shaking (sideEffects: false in package.json)
|
|
839
|
+
+-- Review tsconfig: ensure "module": "esnext" for tree shaking
|
|
840
|
+
+-- Consider moving logic to server (API route, Server Component)
|
|
841
|
+
```
|
|
842
|
+
|
|
843
|
+
### Decision Tree 2: "Should I Add This Dependency?"
|
|
844
|
+
|
|
845
|
+
```
|
|
846
|
+
Proposed new dependency
|
|
847
|
+
|
|
|
848
|
+
+-- Check bundlephobia.com for size
|
|
849
|
+
|
|
|
850
|
+
+-- Size > 50 KB gzipped?
|
|
851
|
+
| |
|
|
852
|
+
| +-- STOP. Do you really need it?
|
|
853
|
+
| +-- Can you implement the needed feature in < 200 lines?
|
|
854
|
+
| | +-- YES --> Write it yourself. Less risk, smaller bundle.
|
|
855
|
+
| | +-- NO --> Is there a lighter alternative?
|
|
856
|
+
| | +-- YES --> Use the lighter alternative.
|
|
857
|
+
| | +-- NO --> Continue evaluation below.
|
|
858
|
+
| |
|
|
859
|
+
| +-- Can it be lazy-loaded (not needed at startup)?
|
|
860
|
+
| +-- YES --> Add with dynamic import. Document the budget impact.
|
|
861
|
+
| +-- NO --> Will it push total bundle over budget?
|
|
862
|
+
| +-- YES --> Find something else to cut first, or reject.
|
|
863
|
+
| +-- NO --> Add with monitoring. Set bundlesize check.
|
|
864
|
+
|
|
|
865
|
+
+-- Size < 50 KB gzipped?
|
|
866
|
+
| |
|
|
867
|
+
| +-- Is it tree-shakeable?
|
|
868
|
+
| | +-- YES --> Safe to add. Monitor with bundlesize.
|
|
869
|
+
| | +-- NO --> Will you use > 50% of its API?
|
|
870
|
+
| | +-- YES --> Acceptable. Add with monitoring.
|
|
871
|
+
| | +-- NO --> Find a tree-shakeable alternative.
|
|
872
|
+
| |
|
|
873
|
+
| +-- How many transitive dependencies?
|
|
874
|
+
| +-- > 20 --> High risk of bloat. Check for alternatives.
|
|
875
|
+
| +-- < 20 --> Acceptable. Proceed.
|
|
876
|
+
|
|
|
877
|
+
+-- Size < 5 KB gzipped?
|
|
878
|
+
+-- Low risk. Add with standard review.
|
|
879
|
+
```
|
|
880
|
+
|
|
881
|
+
### Decision Tree 3: "Which Rendering Strategy for My Page?"
|
|
882
|
+
|
|
883
|
+
```
|
|
884
|
+
New page or feature
|
|
885
|
+
|
|
|
886
|
+
+-- Does the content change frequently?
|
|
887
|
+
|
|
|
888
|
+
+-- RARELY (docs, blog, marketing)
|
|
889
|
+
| --> SSG (Static Site Generation)
|
|
890
|
+
| Budget: <50 KB JS, LCP < 1.5s
|
|
891
|
+
|
|
|
892
|
+
+-- PERIODICALLY (product pages, news)
|
|
893
|
+
| |
|
|
894
|
+
| +-- Can stale data be shown for 60-3600s?
|
|
895
|
+
| +-- YES --> ISR (Incremental Static Regeneration)
|
|
896
|
+
| | Budget: <100 KB JS, LCP < 2.0s
|
|
897
|
+
| +-- NO --> SSR (Server-Side Rendering)
|
|
898
|
+
| Budget: <200 KB JS, LCP < 2.5s
|
|
899
|
+
| Watch: hydration cost on mobile
|
|
900
|
+
|
|
|
901
|
+
+-- REAL-TIME (dashboards, chat, live data)
|
|
902
|
+
|
|
|
903
|
+
+-- Is SEO required?
|
|
904
|
+
+-- YES --> SSR + client hydration + WebSocket
|
|
905
|
+
| Budget: <200 KB JS initial, LCP < 2.5s
|
|
906
|
+
+-- NO --> CSR (Client-Side Rendering)
|
|
907
|
+
Budget: <300 KB JS, TTI < 3.0s on mobile
|
|
908
|
+
Acceptable for authenticated apps
|
|
909
|
+
```
|
|
910
|
+
|
|
911
|
+
---
|
|
912
|
+
|
|
913
|
+
## Code Examples
|
|
914
|
+
|
|
915
|
+
### Example 1: Lighthouse CI budget.json -- Complete Configuration
|
|
916
|
+
|
|
917
|
+
```json
|
|
918
|
+
[
|
|
919
|
+
{
|
|
920
|
+
"path": "/*",
|
|
921
|
+
"resourceSizes": [
|
|
922
|
+
{ "resourceType": "document", "budget": 18 },
|
|
923
|
+
{ "resourceType": "script", "budget": 170 },
|
|
924
|
+
{ "resourceType": "stylesheet", "budget": 50 },
|
|
925
|
+
{ "resourceType": "image", "budget": 500 },
|
|
926
|
+
{ "resourceType": "font", "budget": 100 },
|
|
927
|
+
{ "resourceType": "third-party", "budget": 100 },
|
|
928
|
+
{ "resourceType": "total", "budget": 500 }
|
|
929
|
+
],
|
|
930
|
+
"resourceCounts": [
|
|
931
|
+
{ "resourceType": "script", "budget": 15 },
|
|
932
|
+
{ "resourceType": "stylesheet", "budget": 5 },
|
|
933
|
+
{ "resourceType": "image", "budget": 25 },
|
|
934
|
+
{ "resourceType": "font", "budget": 4 },
|
|
935
|
+
{ "resourceType": "third-party", "budget": 5 },
|
|
936
|
+
{ "resourceType": "total", "budget": 50 }
|
|
937
|
+
],
|
|
938
|
+
"timings": [
|
|
939
|
+
{ "metric": "first-contentful-paint", "budget": 1500 },
|
|
940
|
+
{ "metric": "interactive", "budget": 3000 },
|
|
941
|
+
{ "metric": "largest-contentful-paint", "budget": 2500 },
|
|
942
|
+
{ "metric": "cumulative-layout-shift", "budget": 0.1 },
|
|
943
|
+
{ "metric": "total-blocking-time", "budget": 300 }
|
|
944
|
+
]
|
|
945
|
+
},
|
|
946
|
+
{
|
|
947
|
+
"path": "/checkout/*",
|
|
948
|
+
"resourceSizes": [
|
|
949
|
+
{ "resourceType": "script", "budget": 120 },
|
|
950
|
+
{ "resourceType": "total", "budget": 300 }
|
|
951
|
+
],
|
|
952
|
+
"timings": [
|
|
953
|
+
{ "metric": "interactive", "budget": 2000 },
|
|
954
|
+
{ "metric": "largest-contentful-paint", "budget": 2000 },
|
|
955
|
+
{ "metric": "total-blocking-time", "budget": 200 }
|
|
956
|
+
]
|
|
957
|
+
}
|
|
958
|
+
]
|
|
959
|
+
```
|
|
960
|
+
|
|
961
|
+
### Example 2: webpack Code Splitting Configuration
|
|
962
|
+
|
|
963
|
+
```javascript
|
|
964
|
+
// webpack.config.js
|
|
965
|
+
const path = require('path');
|
|
966
|
+
|
|
967
|
+
module.exports = {
|
|
968
|
+
entry: './src/index.js',
|
|
969
|
+
output: {
|
|
970
|
+
filename: '[name].[contenthash].js',
|
|
971
|
+
chunkFilename: '[name].[contenthash].chunk.js',
|
|
972
|
+
path: path.resolve(__dirname, 'dist'),
|
|
973
|
+
clean: true,
|
|
974
|
+
},
|
|
975
|
+
optimization: {
|
|
976
|
+
splitChunks: {
|
|
977
|
+
chunks: 'all',
|
|
978
|
+
maxInitialRequests: 10,
|
|
979
|
+
minSize: 20000, // 20 KB minimum chunk size
|
|
980
|
+
maxSize: 244000, // 244 KB max -- triggers further splitting
|
|
981
|
+
cacheGroups: {
|
|
982
|
+
vendor: {
|
|
983
|
+
test: /[\\/]node_modules[\\/]/,
|
|
984
|
+
name(module) {
|
|
985
|
+
// Create separate chunks for large vendors
|
|
986
|
+
const packageName = module.context.match(
|
|
987
|
+
/[\\/]node_modules[\\/](.*?)([\\/]|$)/
|
|
988
|
+
)[1];
|
|
989
|
+
return `vendor.${packageName.replace('@', '')}`;
|
|
990
|
+
},
|
|
991
|
+
priority: 10,
|
|
992
|
+
},
|
|
993
|
+
common: {
|
|
994
|
+
minChunks: 2,
|
|
995
|
+
priority: 5,
|
|
996
|
+
reuseExistingChunk: true,
|
|
997
|
+
},
|
|
998
|
+
},
|
|
999
|
+
},
|
|
1000
|
+
runtimeChunk: 'single',
|
|
1001
|
+
},
|
|
1002
|
+
performance: {
|
|
1003
|
+
hints: 'error',
|
|
1004
|
+
maxAssetSize: 250000,
|
|
1005
|
+
maxEntrypointSize: 500000,
|
|
1006
|
+
},
|
|
1007
|
+
};
|
|
1008
|
+
```
|
|
1009
|
+
|
|
1010
|
+
### Example 3: Next.js Bundle Analysis Script
|
|
1011
|
+
|
|
1012
|
+
```javascript
|
|
1013
|
+
// next.config.js
|
|
1014
|
+
const withBundleAnalyzer = require('@next/bundle-analyzer')({
|
|
1015
|
+
enabled: process.env.ANALYZE === 'true',
|
|
1016
|
+
});
|
|
1017
|
+
|
|
1018
|
+
/** @type {import('next').NextConfig} */
|
|
1019
|
+
const nextConfig = {
|
|
1020
|
+
experimental: {
|
|
1021
|
+
optimizePackageImports: [
|
|
1022
|
+
'lodash-es',
|
|
1023
|
+
'@mui/material',
|
|
1024
|
+
'@mui/icons-material',
|
|
1025
|
+
'date-fns',
|
|
1026
|
+
'react-icons',
|
|
1027
|
+
],
|
|
1028
|
+
},
|
|
1029
|
+
images: {
|
|
1030
|
+
formats: ['image/avif', 'image/webp'],
|
|
1031
|
+
deviceSizes: [640, 750, 828, 1080, 1200],
|
|
1032
|
+
minimumCacheTTL: 31536000,
|
|
1033
|
+
},
|
|
1034
|
+
};
|
|
1035
|
+
|
|
1036
|
+
module.exports = withBundleAnalyzer(nextConfig);
|
|
1037
|
+
```
|
|
1038
|
+
|
|
1039
|
+
```bash
|
|
1040
|
+
# Run analysis
|
|
1041
|
+
ANALYZE=true npm run build
|
|
1042
|
+
# Opens interactive treemap showing all chunks and their sizes
|
|
1043
|
+
```
|
|
1044
|
+
|
|
1045
|
+
### Example 4: GitHub Actions -- Complete Performance CI
|
|
1046
|
+
|
|
1047
|
+
```yaml
|
|
1048
|
+
name: Performance Budget CI
|
|
1049
|
+
on:
|
|
1050
|
+
pull_request:
|
|
1051
|
+
branches: [main]
|
|
1052
|
+
|
|
1053
|
+
jobs:
|
|
1054
|
+
bundle-size:
|
|
1055
|
+
runs-on: ubuntu-latest
|
|
1056
|
+
steps:
|
|
1057
|
+
- uses: actions/checkout@v4
|
|
1058
|
+
- uses: actions/setup-node@v4
|
|
1059
|
+
with:
|
|
1060
|
+
node-version: 20
|
|
1061
|
+
cache: 'npm'
|
|
1062
|
+
- run: npm ci
|
|
1063
|
+
- run: npm run build
|
|
1064
|
+
- name: Check bundle sizes
|
|
1065
|
+
run: npx bundlesize
|
|
1066
|
+
- name: Comment bundle size on PR
|
|
1067
|
+
uses: preactjs/compressed-size-action@v2
|
|
1068
|
+
with:
|
|
1069
|
+
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
1070
|
+
build-script: 'build'
|
|
1071
|
+
pattern: './dist/**/*.{js,css}'
|
|
1072
|
+
|
|
1073
|
+
lighthouse:
|
|
1074
|
+
runs-on: ubuntu-latest
|
|
1075
|
+
needs: bundle-size
|
|
1076
|
+
steps:
|
|
1077
|
+
- uses: actions/checkout@v4
|
|
1078
|
+
- uses: actions/setup-node@v4
|
|
1079
|
+
with:
|
|
1080
|
+
node-version: 20
|
|
1081
|
+
cache: 'npm'
|
|
1082
|
+
- run: npm ci && npm run build
|
|
1083
|
+
- name: Start server
|
|
1084
|
+
run: npm run start &
|
|
1085
|
+
- name: Wait for server
|
|
1086
|
+
run: npx wait-on http://localhost:3000 --timeout 30000
|
|
1087
|
+
- name: Lighthouse CI
|
|
1088
|
+
uses: treosh/lighthouse-ci-action@v12
|
|
1089
|
+
with:
|
|
1090
|
+
urls: |
|
|
1091
|
+
http://localhost:3000/
|
|
1092
|
+
http://localhost:3000/products
|
|
1093
|
+
http://localhost:3000/checkout
|
|
1094
|
+
budgetPath: ./budget.json
|
|
1095
|
+
uploadArtifacts: true
|
|
1096
|
+
temporaryPublicStorage: true
|
|
1097
|
+
```
|
|
1098
|
+
|
|
1099
|
+
### Example 5: Backend API Latency Budget Monitoring
|
|
1100
|
+
|
|
1101
|
+
```javascript
|
|
1102
|
+
// middleware/latency-budget.js
|
|
1103
|
+
const BUDGETS = {
|
|
1104
|
+
'/api/products': { p50: 50, p95: 200, p99: 500 },
|
|
1105
|
+
'/api/checkout': { p50: 100, p95: 300, p99: 1000 },
|
|
1106
|
+
'/api/search': { p50: 100, p95: 500, p99: 1500 },
|
|
1107
|
+
'/api/user': { p50: 30, p95: 100, p99: 300 },
|
|
1108
|
+
};
|
|
1109
|
+
|
|
1110
|
+
// In-memory percentile tracker (use proper APM in production)
|
|
1111
|
+
const latencies = {};
|
|
1112
|
+
|
|
1113
|
+
function trackLatency(route, durationMs) {
|
|
1114
|
+
if (!latencies[route]) latencies[route] = [];
|
|
1115
|
+
latencies[route].push(durationMs);
|
|
1116
|
+
|
|
1117
|
+
// Keep last 1000 measurements
|
|
1118
|
+
if (latencies[route].length > 1000) {
|
|
1119
|
+
latencies[route] = latencies[route].slice(-1000);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
function getPercentile(route, percentile) {
|
|
1124
|
+
const sorted = [...(latencies[route] || [])].sort((a, b) => a - b);
|
|
1125
|
+
if (sorted.length === 0) return 0;
|
|
1126
|
+
const index = Math.ceil((percentile / 100) * sorted.length) - 1;
|
|
1127
|
+
return sorted[index];
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
// Express middleware
|
|
1131
|
+
function latencyBudgetMiddleware(req, res, next) {
|
|
1132
|
+
const start = performance.now();
|
|
1133
|
+
const route = req.route?.path || req.path;
|
|
1134
|
+
|
|
1135
|
+
res.on('finish', () => {
|
|
1136
|
+
const duration = performance.now() - start;
|
|
1137
|
+
trackLatency(route, duration);
|
|
1138
|
+
|
|
1139
|
+
const budget = BUDGETS[route];
|
|
1140
|
+
if (budget) {
|
|
1141
|
+
const p95 = getPercentile(route, 95);
|
|
1142
|
+
if (p95 > budget.p95) {
|
|
1143
|
+
console.warn(
|
|
1144
|
+
`BUDGET EXCEEDED: ${route} p95=${p95.toFixed(0)}ms (budget: ${budget.p95}ms)`
|
|
1145
|
+
);
|
|
1146
|
+
// Send alert to monitoring system
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
});
|
|
1150
|
+
|
|
1151
|
+
next();
|
|
1152
|
+
}
|
|
1153
|
+
```
|
|
1154
|
+
|
|
1155
|
+
### Example 6: Database Query Budget with PostgreSQL
|
|
1156
|
+
|
|
1157
|
+
```sql
|
|
1158
|
+
-- Enable slow query logging at 200ms threshold
|
|
1159
|
+
ALTER SYSTEM SET log_min_duration_statement = 200;
|
|
1160
|
+
SELECT pg_reload_conf();
|
|
1161
|
+
|
|
1162
|
+
-- Find top slow queries using pg_stat_statements
|
|
1163
|
+
SELECT
|
|
1164
|
+
query,
|
|
1165
|
+
calls,
|
|
1166
|
+
round(mean_exec_time::numeric, 2) AS avg_ms,
|
|
1167
|
+
round(max_exec_time::numeric, 2) AS max_ms,
|
|
1168
|
+
round(total_exec_time::numeric, 2) AS total_ms,
|
|
1169
|
+
rows
|
|
1170
|
+
FROM pg_stat_statements
|
|
1171
|
+
WHERE mean_exec_time > 50 -- queries averaging over 50ms
|
|
1172
|
+
ORDER BY total_exec_time DESC
|
|
1173
|
+
LIMIT 20;
|
|
1174
|
+
|
|
1175
|
+
-- Calculate p95 for a specific query pattern
|
|
1176
|
+
SELECT
|
|
1177
|
+
percentile_cont(0.95) WITHIN GROUP (ORDER BY duration) AS p95_ms
|
|
1178
|
+
FROM query_log
|
|
1179
|
+
WHERE query_pattern = 'SELECT * FROM products WHERE ...'
|
|
1180
|
+
AND logged_at > now() - interval '1 hour';
|
|
1181
|
+
```
|
|
1182
|
+
|
|
1183
|
+
### Example 7: Import Cost Awareness -- Before and After
|
|
1184
|
+
|
|
1185
|
+
```javascript
|
|
1186
|
+
// BEFORE: Common import mistakes and their costs
|
|
1187
|
+
import moment from 'moment'; // +330 KB (67 KB gzip)
|
|
1188
|
+
import _ from 'lodash'; // +71 KB (25 KB gzip)
|
|
1189
|
+
import { Chart } from 'chart.js'; // +200 KB (65 KB gzip)
|
|
1190
|
+
import * as Icons from '@mui/icons-material'; // +5 MB (1.2 MB gzip)
|
|
1191
|
+
// Total: ~5.6 MB stat, ~1.36 MB gzip
|
|
1192
|
+
|
|
1193
|
+
// AFTER: Right-sized imports
|
|
1194
|
+
import { format, parseISO } from 'date-fns'; // +3 KB gzip (per function)
|
|
1195
|
+
import debounce from 'lodash-es/debounce'; // +1 KB gzip
|
|
1196
|
+
import { Line } from 'react-chartjs-2/lazy'; // lazy-loaded
|
|
1197
|
+
import SearchIcon from '@mui/icons-material/Search'; // +1 KB gzip (single icon)
|
|
1198
|
+
// Total: ~10 KB gzip initial, chart lazy-loaded on demand
|
|
1199
|
+
```
|
|
1200
|
+
|
|
1201
|
+
### Example 8: Responsive Image Generation Script
|
|
1202
|
+
|
|
1203
|
+
```javascript
|
|
1204
|
+
// scripts/optimize-images.js
|
|
1205
|
+
const sharp = require('sharp');
|
|
1206
|
+
const glob = require('glob');
|
|
1207
|
+
const path = require('path');
|
|
1208
|
+
const fs = require('fs');
|
|
1209
|
+
|
|
1210
|
+
const WIDTHS = [400, 800, 1200, 1920];
|
|
1211
|
+
const FORMATS = ['avif', 'webp'];
|
|
1212
|
+
const QUALITY = { avif: 50, webp: 75 }; // AVIF achieves same visual quality at lower setting
|
|
1213
|
+
|
|
1214
|
+
async function optimizeImages(inputDir, outputDir) {
|
|
1215
|
+
const images = glob.sync(`${inputDir}/**/*.{jpg,jpeg,png}`);
|
|
1216
|
+
let totalSaved = 0;
|
|
1217
|
+
|
|
1218
|
+
for (const imagePath of images) {
|
|
1219
|
+
const basename = path.basename(imagePath, path.extname(imagePath));
|
|
1220
|
+
const originalSize = fs.statSync(imagePath).size;
|
|
1221
|
+
|
|
1222
|
+
for (const width of WIDTHS) {
|
|
1223
|
+
for (const format of FORMATS) {
|
|
1224
|
+
const outputPath = path.join(outputDir, `${basename}-${width}.${format}`);
|
|
1225
|
+
await sharp(imagePath)
|
|
1226
|
+
.resize(width, null, { withoutEnlargement: true })
|
|
1227
|
+
.toFormat(format, { quality: QUALITY[format] })
|
|
1228
|
+
.toFile(outputPath);
|
|
1229
|
+
|
|
1230
|
+
const newSize = fs.statSync(outputPath).size;
|
|
1231
|
+
const saving = ((1 - newSize / originalSize) * 100).toFixed(1);
|
|
1232
|
+
totalSaved += originalSize - newSize;
|
|
1233
|
+
console.log(`${basename}-${width}.${format}: ${saving}% smaller`);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
console.log(`\nTotal saved: ${(totalSaved / 1024 / 1024).toFixed(1)} MB`);
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
optimizeImages('./src/images', './public/images');
|
|
1242
|
+
// Typical output: hero-400.avif: 89% smaller, hero-800.webp: 72% smaller
|
|
1243
|
+
```
|
|
1244
|
+
|
|
1245
|
+
---
|
|
1246
|
+
|
|
1247
|
+
## Quick Reference
|
|
1248
|
+
|
|
1249
|
+
### Frontend Budgets
|
|
1250
|
+
|
|
1251
|
+
| Metric | Good | Acceptable | Needs Work |
|
|
1252
|
+
|--------|------|------------|------------|
|
|
1253
|
+
| LCP (p75) | <=2.0s | <=2.5s | >2.5s |
|
|
1254
|
+
| INP (p75) | <=150ms | <=200ms | >200ms |
|
|
1255
|
+
| CLS (p75) | <=0.05 | <=0.1 | >0.1 |
|
|
1256
|
+
| FCP | <=1.5s | <=2.0s | >2.0s |
|
|
1257
|
+
| TTFB | <=600ms | <=800ms | >1.0s |
|
|
1258
|
+
| TBT | <=200ms | <=300ms | >500ms |
|
|
1259
|
+
| JS bundle (gzip) | <=130 KB | <=170 KB | >400 KB |
|
|
1260
|
+
| CSS (gzip) | <=30 KB | <=50 KB | >100 KB |
|
|
1261
|
+
| Total page weight (gzip) | <=500 KB | <=1 MB | >2 MB |
|
|
1262
|
+
| Image weight (per page) | <=300 KB | <=500 KB | >1 MB |
|
|
1263
|
+
| Font files (total) | <=50 KB | <=100 KB | >200 KB |
|
|
1264
|
+
| Third-party JS (gzip) | <=50 KB | <=100 KB | >250 KB |
|
|
1265
|
+
| HTTP requests | <=30 | <=50 | >80 |
|
|
1266
|
+
|
|
1267
|
+
### Backend Budgets
|
|
1268
|
+
|
|
1269
|
+
| Metric | Good | Acceptable | Needs Work |
|
|
1270
|
+
|--------|------|------------|------------|
|
|
1271
|
+
| API p50 latency | <=50ms | <=100ms | >200ms |
|
|
1272
|
+
| API p95 latency | <=200ms | <=300ms | >800ms |
|
|
1273
|
+
| API p99 latency | <=500ms | <=1000ms | >2000ms |
|
|
1274
|
+
| DB query p50 | <=5ms | <=10ms | >50ms |
|
|
1275
|
+
| DB query p95 | <=50ms | <=100ms | >200ms |
|
|
1276
|
+
| Slow query threshold | 200ms | 500ms | 1000ms |
|
|
1277
|
+
| Error rate | <0.1% | <1% | >5% |
|
|
1278
|
+
| Availability | >99.9% | >99.5% | <99% |
|
|
1279
|
+
|
|
1280
|
+
### Optimization Quick Wins (by impact)
|
|
1281
|
+
|
|
1282
|
+
| Optimization | Effort | Typical Impact | Risk |
|
|
1283
|
+
|--------------|--------|----------------|------|
|
|
1284
|
+
| Serve images as WebP/AVIF | Low | 30-70% image size reduction | Low |
|
|
1285
|
+
| Add `loading="lazy"` to below-fold images | Low | 20-40% reduction in initial page weight | Low |
|
|
1286
|
+
| Font subsetting + WOFF2 | Low | 70-88% font size reduction | Low |
|
|
1287
|
+
| Enable text compression (Brotli/gzip) | Low | 60-80% text resource reduction | Low |
|
|
1288
|
+
| Tree-shake imports | Medium | 20-65 KB per large library | Low |
|
|
1289
|
+
| Route-based code splitting | Medium | 40-60% initial JS reduction | Medium |
|
|
1290
|
+
| Critical CSS inlining | Medium | 0.5-1.5s FCP improvement | Medium |
|
|
1291
|
+
| Remove unused CSS (PurgeCSS) | Medium | 50-90% CSS reduction | Medium |
|
|
1292
|
+
| API response field selection | Medium | 50-94% response size reduction | Low |
|
|
1293
|
+
| Switch rendering strategy (CSR to SSR/ISR) | High | 1-3s LCP improvement | High |
|
|
1294
|
+
|
|
1295
|
+
### Tools Reference
|
|
1296
|
+
|
|
1297
|
+
| Tool | Purpose | Integration |
|
|
1298
|
+
|------|---------|-------------|
|
|
1299
|
+
| Lighthouse CI | Automated performance auditing with budgets | GitHub Actions, GitLab CI |
|
|
1300
|
+
| bundlesize | JS/CSS bundle size enforcement | CI, GitHub status check |
|
|
1301
|
+
| webpack-bundle-analyzer | Visual bundle composition analysis | Build step |
|
|
1302
|
+
| compressed-size-action | PR comment with size delta | GitHub Actions |
|
|
1303
|
+
| SpeedCurve | Continuous RUM + synthetic monitoring | Dashboard, Slack alerts |
|
|
1304
|
+
| DebugBear | Performance monitoring with budget tracking | Dashboard, CI |
|
|
1305
|
+
| Calibre | Performance monitoring and budgets | Dashboard, Slack, CI |
|
|
1306
|
+
| web-vitals (npm) | Report Core Web Vitals from real users | Client-side JS |
|
|
1307
|
+
| Chrome DevTools Coverage | Find unused JS/CSS | Manual profiling |
|
|
1308
|
+
| bundlephobia.com | Check npm package size before installing | Manual pre-install check |
|
|
1309
|
+
| WebPageTest | Deep synthetic testing with filmstrip | Manual, API |
|
|
1310
|
+
| CrUX Dashboard | Google's real user experience data | Looker Studio |
|
|
1311
|
+
|
|
1312
|
+
---
|
|
1313
|
+
|
|
1314
|
+
*Researched: 2026-03-08 | Sources: [web.dev Core Web Vitals](https://web.dev/articles/defining-core-web-vitals-thresholds), [web.dev Vitals Business Impact](https://web.dev/case-studies/vitals-business-impact), [Google Lighthouse CI](https://github.com/GoogleChrome/lighthouse-ci), [MDN Performance Budgets](https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/Performance_budgets), [SpeedCurve Performance Budgets Guide](https://www.speedcurve.com/blog/performance-budgets/), [Addy Osmani - Start Performance Budgeting](https://addyosmani.com/blog/performance-budgets/), [Alex Russell - Can You Afford It?](https://infrequently.org/2017/10/can-you-afford-it-real-world-web-performance-budgets/), [Smashing Magazine - Code Splitting](https://www.smashingmagazine.com/2022/02/javascript-bundle-performance-code-splitting/), [Smashing Magazine - AVIF and WebP](https://www.smashingmagazine.com/2021/09/modern-image-formats-avif-webp/), [WPO Stats](https://wpostats.com/), [Conductor Page Speed Studies](https://www.conductor.com/academy/page-speed-resources/), [Sia Karamalegos - 14 Web Perf Tips 2025](https://sia.codes/posts/web-perf-tips-2025/), [DebugBear - Working With Performance Budgets](https://www.debugbear.com/blog/working-with-performance-budgets), [Calibre - Bundle Size Optimization](https://calibreapp.com/blog/bundle-size-optimization), [web.dev - Optimize Web Fonts](https://web.dev/learn/performance/optimize-web-fonts), [Marvin Hagemeister - Polyfills Gone Rogue](https://marvinh.dev/blog/speeding-up-javascript-ecosystem-part-6/)*
|