@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,1239 @@
|
|
|
1
|
+
# Bundle Optimization
|
|
2
|
+
|
|
3
|
+
> Performance expertise module for JavaScript bundle optimization.
|
|
4
|
+
> Covers analysis, splitting, tree shaking, compression, and anti-patterns
|
|
5
|
+
> with measured data and real-world benchmarks.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
1. [Bundle Size Budgets](#1-bundle-size-budgets)
|
|
12
|
+
2. [Bundle Analysis Tools](#2-bundle-analysis-tools)
|
|
13
|
+
3. [Code Splitting Strategies](#3-code-splitting-strategies)
|
|
14
|
+
4. [Tree Shaking and Dead Code Elimination](#4-tree-shaking-and-dead-code-elimination)
|
|
15
|
+
5. [Dynamic Imports and Lazy Loading](#5-dynamic-imports-and-lazy-loading)
|
|
16
|
+
6. [Modern vs Legacy Bundles](#6-modern-vs-legacy-bundles)
|
|
17
|
+
7. [Compression: Gzip vs Brotli](#7-compression-gzip-vs-brotli)
|
|
18
|
+
8. [ESM vs CommonJS and Bundle Size](#8-esm-vs-commonjs-and-bundle-size)
|
|
19
|
+
9. [Module Federation for Micro-Frontends](#9-module-federation-for-micro-frontends)
|
|
20
|
+
10. [Common Bottlenecks and Heavy Dependencies](#10-common-bottlenecks-and-heavy-dependencies)
|
|
21
|
+
11. [Anti-Patterns](#11-anti-patterns)
|
|
22
|
+
12. [Before/After Case Studies](#12-beforeafter-case-studies)
|
|
23
|
+
13. [Decision Tree: My Bundle Is Too Large](#13-decision-tree-my-bundle-is-too-large)
|
|
24
|
+
14. [Sources](#14-sources)
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 1. Bundle Size Budgets
|
|
29
|
+
|
|
30
|
+
### The 170 KB Rule
|
|
31
|
+
|
|
32
|
+
The widely referenced performance budget from web.dev and Google's Addy Osmani recommends
|
|
33
|
+
delivering **under 170 KB of compressed (gzip/brotli) critical-path JavaScript** for the
|
|
34
|
+
initial page load. Research places the optimal budget between **130 KB and 170 KB compressed**
|
|
35
|
+
for worst-case network scenarios (slow 3G, mid-range mobile devices).
|
|
36
|
+
|
|
37
|
+
Source: [web.dev - Incorporate performance budgets into your build process](https://web.dev/articles/incorporate-performance-budgets-into-your-build-tools)
|
|
38
|
+
|
|
39
|
+
### Why 170 KB?
|
|
40
|
+
|
|
41
|
+
The budget is derived from a Time-to-Interactive (TTI) target of **under 5 seconds on a
|
|
42
|
+
mid-range mobile device over a slow 3G connection**. JavaScript is uniquely expensive because
|
|
43
|
+
the browser must download, parse, compile, and execute it. A 170 KB compressed JS bundle
|
|
44
|
+
decompresses to roughly 500-700 KB of raw JavaScript, which takes approximately 3-4 seconds
|
|
45
|
+
to parse and execute on a median mobile device.
|
|
46
|
+
|
|
47
|
+
### Budget Tiers
|
|
48
|
+
|
|
49
|
+
| Tier | Compressed JS (initial) | Typical Use Case |
|
|
50
|
+
|---------------|------------------------|--------------------------------------|
|
|
51
|
+
| Aggressive | < 70 KB | Landing pages, static sites |
|
|
52
|
+
| Recommended | < 170 KB | SPAs, e-commerce, content sites |
|
|
53
|
+
| Maximum | < 250 KB | Complex dashboards, enterprise apps |
|
|
54
|
+
| Over budget | > 350 KB | Requires immediate investigation |
|
|
55
|
+
|
|
56
|
+
### Enforcing Budgets in CI
|
|
57
|
+
|
|
58
|
+
**bundlesize (npm package):** Tests asset sizes against a configured threshold. Tinder.com
|
|
59
|
+
uses bundlesize to enforce a main bundle budget of 170 KB and a CSS budget of 20 KB, checked
|
|
60
|
+
on every PR commit.
|
|
61
|
+
|
|
62
|
+
Source: [Addy Osmani - Start Performance Budgeting](https://addyosmani.com/blog/performance-budgets/)
|
|
63
|
+
|
|
64
|
+
**webpack performance hints:** Webpack natively supports size limits in its configuration:
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
// webpack.config.js
|
|
68
|
+
module.exports = {
|
|
69
|
+
performance: {
|
|
70
|
+
maxAssetSize: 170 * 1024, // 170 KB per asset
|
|
71
|
+
maxEntrypointSize: 250 * 1024, // 250 KB per entrypoint
|
|
72
|
+
hints: 'error' // fail the build if exceeded
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Angular CLI defaults:** Angular warns when the main bundle exceeds 170 KB and fails the
|
|
78
|
+
build at 250 KB, enforcing these budgets out of the box.
|
|
79
|
+
|
|
80
|
+
Source: [web.dev - Performance budgets with the Angular CLI](https://web.dev/articles/performance-budgets-with-the-angular-cli)
|
|
81
|
+
|
|
82
|
+
**Vite/Rollup:** Use `rollup-plugin-visualizer` combined with a CI script that parses the
|
|
83
|
+
stats output and fails if any chunk exceeds the threshold.
|
|
84
|
+
|
|
85
|
+
### Budget Tracking in Practice
|
|
86
|
+
|
|
87
|
+
```jsonc
|
|
88
|
+
// bundlesize configuration in package.json
|
|
89
|
+
{
|
|
90
|
+
"bundlesize": [
|
|
91
|
+
{ "path": "dist/main.*.js", "maxSize": "170 kB", "compression": "gzip" },
|
|
92
|
+
{ "path": "dist/vendor.*.js", "maxSize": "120 kB", "compression": "gzip" },
|
|
93
|
+
{ "path": "dist/*.css", "maxSize": "20 kB", "compression": "gzip" }
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 2. Bundle Analysis Tools
|
|
101
|
+
|
|
102
|
+
Before optimizing, you must measure. Three tools form the standard analysis toolkit.
|
|
103
|
+
|
|
104
|
+
### webpack-bundle-analyzer
|
|
105
|
+
|
|
106
|
+
The most widely used visualization tool. Generates an interactive, zoomable treemap of your
|
|
107
|
+
bundle contents showing stat size, parsed size, and gzip/brotli size for every module.
|
|
108
|
+
|
|
109
|
+
**What it reveals:**
|
|
110
|
+
- Oversized third-party dependencies
|
|
111
|
+
- Duplicate modules bundled multiple times
|
|
112
|
+
- Modules that should be lazy-loaded but are in the initial chunk
|
|
113
|
+
- Ineffective tree shaking (full library included when only one function is used)
|
|
114
|
+
|
|
115
|
+
Source: [webpack-bundle-analyzer on npm](https://www.npmjs.com/package/webpack-bundle-analyzer)
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Installation and usage
|
|
119
|
+
npm install --save-dev webpack-bundle-analyzer
|
|
120
|
+
|
|
121
|
+
# Add to webpack config
|
|
122
|
+
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
|
123
|
+
module.exports = {
|
|
124
|
+
plugins: [new BundleAnalyzerPlugin()]
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
# Or analyze an existing stats file
|
|
128
|
+
npx webpack --profile --json > stats.json
|
|
129
|
+
npx webpack-bundle-analyzer stats.json
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### source-map-explorer
|
|
133
|
+
|
|
134
|
+
Uses source maps to compute a precise byte-by-byte attribution of your bundle to the
|
|
135
|
+
original source files. Produces a treemap visualization similar to webpack-bundle-analyzer
|
|
136
|
+
but works with any bundler that generates source maps.
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
npx source-map-explorer dist/main.js
|
|
140
|
+
# or for multiple bundles
|
|
141
|
+
npx source-map-explorer dist/*.js
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Source: [DigitalOcean - How To Analyze Angular App Bundle Sizes](https://www.digitalocean.com/community/tutorials/angular-bundle-size)
|
|
145
|
+
|
|
146
|
+
### BundlePhobia
|
|
147
|
+
|
|
148
|
+
A web-based tool (bundlephobia.com) that shows the install size, bundle size (minified),
|
|
149
|
+
and bundle size (minified + gzipped) of any npm package before you add it to your project.
|
|
150
|
+
Also estimates download time and shows the composition of transitive dependencies.
|
|
151
|
+
|
|
152
|
+
**Key metrics per package:**
|
|
153
|
+
- Minified size
|
|
154
|
+
- Minified + gzipped size
|
|
155
|
+
- Download time on slow 3G
|
|
156
|
+
- Composition breakdown (dependency tree contribution)
|
|
157
|
+
- Whether the package is tree-shakeable
|
|
158
|
+
|
|
159
|
+
### rollup-plugin-visualizer (for Vite)
|
|
160
|
+
|
|
161
|
+
The equivalent of webpack-bundle-analyzer for Vite/Rollup projects. Generates sunburst,
|
|
162
|
+
treemap, or network visualizations of the production bundle.
|
|
163
|
+
|
|
164
|
+
```js
|
|
165
|
+
// vite.config.js
|
|
166
|
+
import { visualizer } from 'rollup-plugin-visualizer';
|
|
167
|
+
|
|
168
|
+
export default {
|
|
169
|
+
plugins: [
|
|
170
|
+
visualizer({
|
|
171
|
+
filename: 'dist/stats.html',
|
|
172
|
+
gzipSize: true,
|
|
173
|
+
brotliSize: true
|
|
174
|
+
})
|
|
175
|
+
]
|
|
176
|
+
};
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Analysis Workflow
|
|
180
|
+
|
|
181
|
+
1. Build production bundle with stats output enabled
|
|
182
|
+
2. Open the treemap visualization
|
|
183
|
+
3. Identify the largest chunks and modules
|
|
184
|
+
4. For each large module, determine: Is it tree-shakeable? Is there a lighter alternative? Can it be lazy-loaded?
|
|
185
|
+
5. Make changes, rebuild, compare sizes
|
|
186
|
+
6. Add CI enforcement to prevent regression
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 3. Code Splitting Strategies
|
|
191
|
+
|
|
192
|
+
Code splitting breaks a monolithic bundle into smaller chunks loaded on demand. Combined
|
|
193
|
+
with lazy loading, this technique can reduce initial load times by **40-60%**.
|
|
194
|
+
|
|
195
|
+
Source: [Smashing Magazine - Improving JavaScript Bundle Performance With Code-Splitting](https://www.smashingmagazine.com/2022/02/javascript-bundle-performance-code-splitting/)
|
|
196
|
+
|
|
197
|
+
### Route-Based Splitting
|
|
198
|
+
|
|
199
|
+
The highest-impact strategy. Each route (page) gets its own chunk, loaded only when the
|
|
200
|
+
user navigates to that route. This is almost always the best place to start code splitting
|
|
201
|
+
and where you achieve the maximum reduction in initial bundle size.
|
|
202
|
+
|
|
203
|
+
```js
|
|
204
|
+
// React with React.lazy and React Router
|
|
205
|
+
import { lazy, Suspense } from 'react';
|
|
206
|
+
import { Routes, Route } from 'react-router-dom';
|
|
207
|
+
|
|
208
|
+
const Home = lazy(() => import('./pages/Home'));
|
|
209
|
+
const Dashboard = lazy(() => import('./pages/Dashboard'));
|
|
210
|
+
const Settings = lazy(() => import('./pages/Settings'));
|
|
211
|
+
|
|
212
|
+
function App() {
|
|
213
|
+
return (
|
|
214
|
+
<Suspense fallback={<Loading />}>
|
|
215
|
+
<Routes>
|
|
216
|
+
<Route path="/" element={<Home />} />
|
|
217
|
+
<Route path="/dashboard" element={<Dashboard />} />
|
|
218
|
+
<Route path="/settings" element={<Settings />} />
|
|
219
|
+
</Routes>
|
|
220
|
+
</Suspense>
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Typical impact:** If an application has 10 routes averaging 80 KB each, the initial
|
|
226
|
+
bundle drops from 800 KB to ~80-120 KB (the active route plus shared vendor code).
|
|
227
|
+
|
|
228
|
+
### Component-Based Splitting
|
|
229
|
+
|
|
230
|
+
Split heavy components that are not visible on initial render: modals, tabs not initially
|
|
231
|
+
active, charts, rich text editors, and below-the-fold content.
|
|
232
|
+
|
|
233
|
+
```js
|
|
234
|
+
// Heavy chart component loaded only when rendered
|
|
235
|
+
const AnalyticsChart = lazy(() => import('./components/AnalyticsChart'));
|
|
236
|
+
|
|
237
|
+
function Dashboard() {
|
|
238
|
+
const [showChart, setShowChart] = useState(false);
|
|
239
|
+
return (
|
|
240
|
+
<div>
|
|
241
|
+
<button onClick={() => setShowChart(true)}>Show Analytics</button>
|
|
242
|
+
{showChart && (
|
|
243
|
+
<Suspense fallback={<ChartSkeleton />}>
|
|
244
|
+
<AnalyticsChart />
|
|
245
|
+
</Suspense>
|
|
246
|
+
)}
|
|
247
|
+
</div>
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Vendor Splitting
|
|
253
|
+
|
|
254
|
+
Separate third-party libraries from application code. Vendor code changes less frequently,
|
|
255
|
+
allowing browsers to cache it independently. Webpack's `SplitChunksPlugin` handles this
|
|
256
|
+
automatically:
|
|
257
|
+
|
|
258
|
+
```js
|
|
259
|
+
// webpack.config.js
|
|
260
|
+
module.exports = {
|
|
261
|
+
optimization: {
|
|
262
|
+
splitChunks: {
|
|
263
|
+
cacheGroups: {
|
|
264
|
+
vendor: {
|
|
265
|
+
test: /[\\/]node_modules[\\/]/,
|
|
266
|
+
name: 'vendor',
|
|
267
|
+
chunks: 'all',
|
|
268
|
+
priority: 10
|
|
269
|
+
},
|
|
270
|
+
// Separate large libraries into their own chunks
|
|
271
|
+
charts: {
|
|
272
|
+
test: /[\\/]node_modules[\\/](chart\.js|d3)[\\/]/,
|
|
273
|
+
name: 'charts-vendor',
|
|
274
|
+
chunks: 'all',
|
|
275
|
+
priority: 20
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Splitting Granularity Tradeoffs
|
|
284
|
+
|
|
285
|
+
| Strategy | Initial Load Impact | Cache Efficiency | Complexity |
|
|
286
|
+
|-----------------------|--------------------|------------------|------------|
|
|
287
|
+
| No splitting | Poor (everything loaded) | Poor (any change invalidates all) | None |
|
|
288
|
+
| Route-based only | Good (40-60% reduction) | Good | Low |
|
|
289
|
+
| Route + vendor | Better (50-70% reduction) | Better (vendor cached separately) | Medium |
|
|
290
|
+
| Route + vendor + component | Best (60-80% reduction) | Best | Higher |
|
|
291
|
+
| Over-splitting | Degraded (too many HTTP requests) | Mixed | High |
|
|
292
|
+
|
|
293
|
+
**Warning:** Over-splitting creates too many small chunks. Each chunk incurs HTTP request
|
|
294
|
+
overhead (even with HTTP/2 multiplexing). A good heuristic: no chunk smaller than 20 KB
|
|
295
|
+
compressed, no more than 20-25 parallel chunk requests for a single route.
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## 4. Tree Shaking and Dead Code Elimination
|
|
300
|
+
|
|
301
|
+
### How Tree Shaking Works
|
|
302
|
+
|
|
303
|
+
Tree shaking is a form of dead code elimination that relies on the **static structure of
|
|
304
|
+
ES module (ESM) syntax**. Because `import` and `export` statements are statically analyzable
|
|
305
|
+
(resolved at compile time, not runtime), bundlers can determine which exports from a module
|
|
306
|
+
are actually used and eliminate the rest.
|
|
307
|
+
|
|
308
|
+
Source: [webpack - Tree Shaking guide](https://webpack.js.org/guides/tree-shaking/)
|
|
309
|
+
|
|
310
|
+
The process works in two phases:
|
|
311
|
+
1. **Mark phase:** The bundler walks the dependency graph, marking each export as "used" or "unused"
|
|
312
|
+
2. **Sweep phase:** A minifier (Terser, esbuild, SWC) removes the code paths marked as unused
|
|
313
|
+
|
|
314
|
+
### What Prevents Tree Shaking
|
|
315
|
+
|
|
316
|
+
**1. CommonJS (`require()`):** CJS is dynamic -- `require()` can appear inside conditionals,
|
|
317
|
+
be computed at runtime, and use string concatenation for module paths. Bundlers cannot
|
|
318
|
+
statically analyze this, so they include the entire module.
|
|
319
|
+
|
|
320
|
+
```js
|
|
321
|
+
// CANNOT be tree-shaken -- dynamic require
|
|
322
|
+
const lib = require('lodash');
|
|
323
|
+
const fn = lib[someVariable];
|
|
324
|
+
|
|
325
|
+
// CAN be tree-shaken -- static ESM import
|
|
326
|
+
import { debounce } from 'lodash-es';
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**2. Side Effects:** Some modules execute code on import (modify globals, register polyfills,
|
|
330
|
+
attach event listeners). Bundlers must preserve these modules even if no exports are used.
|
|
331
|
+
|
|
332
|
+
```js
|
|
333
|
+
// This has a side effect (modifies Array.prototype)
|
|
334
|
+
import './polyfills';
|
|
335
|
+
|
|
336
|
+
// This has no side effect (pure function export)
|
|
337
|
+
import { formatDate } from './utils';
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**3. Default Exports:** Default exports can complicate static analysis because the bundler
|
|
341
|
+
cannot as easily determine which properties of the default-exported object are used.
|
|
342
|
+
|
|
343
|
+
```js
|
|
344
|
+
// Harder to tree-shake
|
|
345
|
+
export default { formatDate, parseDate, addDays };
|
|
346
|
+
|
|
347
|
+
// Easier to tree-shake
|
|
348
|
+
export { formatDate, parseDate, addDays };
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
**4. Class-Based Code:** Classes are harder to tree-shake because methods on a class
|
|
352
|
+
prototype are not individually removable -- the entire class is either included or excluded.
|
|
353
|
+
|
|
354
|
+
### The `sideEffects` Flag
|
|
355
|
+
|
|
356
|
+
The `sideEffects` field in `package.json` is the single most important enabler of effective
|
|
357
|
+
tree shaking for library authors. It tells the bundler which files are safe to skip entirely
|
|
358
|
+
if none of their exports are used.
|
|
359
|
+
|
|
360
|
+
Source: [webpack - Tree Shaking guide (sideEffects)](https://webpack.js.org/guides/tree-shaking/)
|
|
361
|
+
|
|
362
|
+
```jsonc
|
|
363
|
+
// package.json -- mark entire package as side-effect free
|
|
364
|
+
{
|
|
365
|
+
"name": "my-library",
|
|
366
|
+
"sideEffects": false
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// package.json -- mark specific files as having side effects
|
|
370
|
+
{
|
|
371
|
+
"name": "my-library",
|
|
372
|
+
"sideEffects": [
|
|
373
|
+
"*.css",
|
|
374
|
+
"*.scss",
|
|
375
|
+
"./src/polyfills.js"
|
|
376
|
+
]
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
**Critical warning:** Setting `"sideEffects": false` when your code does have side effects
|
|
381
|
+
(e.g., CSS imports, polyfills, global registrations) will cause those side effects to be
|
|
382
|
+
silently dropped from the production bundle. CSS imports via css-loader are a common casualty.
|
|
383
|
+
|
|
384
|
+
### Measuring Tree Shaking Effectiveness
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
# Compare bundle sizes with and without tree shaking
|
|
388
|
+
# 1. Build with tree shaking (default in production mode)
|
|
389
|
+
npx webpack --mode production --json > stats-prod.json
|
|
390
|
+
|
|
391
|
+
# 2. Build without tree shaking
|
|
392
|
+
npx webpack --mode development --json > stats-dev.json
|
|
393
|
+
|
|
394
|
+
# 3. Compare with webpack-bundle-analyzer
|
|
395
|
+
npx webpack-bundle-analyzer stats-prod.json
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### Tree Shaking Effectiveness by Library
|
|
399
|
+
|
|
400
|
+
| Library | sideEffects Flag | ESM Support | Tree-Shakeable | Notes |
|
|
401
|
+
|----------------|-----------------|-------------|----------------|---------------------------------------------|
|
|
402
|
+
| lodash | No | No (CJS) | No | Use lodash-es or individual imports |
|
|
403
|
+
| lodash-es | Yes (false) | Yes | Yes | 70% smaller when importing few functions |
|
|
404
|
+
| date-fns | Yes (false) | Yes | Yes | Individual function imports, ~2 KB per fn |
|
|
405
|
+
| moment.js | No | No | No | 232 KB min + 160 KB locales, not shakeable |
|
|
406
|
+
| rxjs | Yes (false) | Yes | Yes | v6+ fully tree-shakeable |
|
|
407
|
+
| @mui/material | Yes (array) | Yes | Partial | Use direct imports for best results |
|
|
408
|
+
| three.js | Yes (false) | Yes | Yes | Since r108 |
|
|
409
|
+
| chart.js | Partial | Yes | Partial | Register only needed components |
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
## 5. Dynamic Imports and Lazy Loading
|
|
414
|
+
|
|
415
|
+
### How Dynamic Imports Work
|
|
416
|
+
|
|
417
|
+
The `import()` expression returns a Promise that resolves to the module. Bundlers (webpack,
|
|
418
|
+
Vite, Rollup) detect `import()` calls at build time and automatically create separate chunks.
|
|
419
|
+
|
|
420
|
+
```js
|
|
421
|
+
// Static import -- included in main bundle
|
|
422
|
+
import { heavyCalculation } from './math';
|
|
423
|
+
|
|
424
|
+
// Dynamic import -- separate chunk, loaded on demand
|
|
425
|
+
const mathModule = await import('./math');
|
|
426
|
+
mathModule.heavyCalculation();
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### Performance Impact
|
|
430
|
+
|
|
431
|
+
Real-world measurements from multiple case studies show consistent improvements:
|
|
432
|
+
|
|
433
|
+
| Metric | Before Splitting | After Splitting | Improvement |
|
|
434
|
+
|------------------------|-----------------|-----------------|-------------|
|
|
435
|
+
| Initial bundle size | 2.3 MB | 875 KB | 62% |
|
|
436
|
+
| Time to Interactive | 5.2 s | 2.7 s | 48% |
|
|
437
|
+
| First Contentful Paint | 1.8 s | 1.2 s | 33% |
|
|
438
|
+
|
|
439
|
+
Source: [Coditation - Optimizing Bundle Sizes in React Applications](https://www.coditation.com/blog/optimizing-bundle-sizes-in-react-applications-a-deep-dive-into-code-splitting-and-lazy-loading)
|
|
440
|
+
|
|
441
|
+
### Lazy Loading Timing Strategies
|
|
442
|
+
|
|
443
|
+
**1. On Interaction (most common):** Load the chunk when the user performs an action
|
|
444
|
+
(click, hover, scroll) that will need the code.
|
|
445
|
+
|
|
446
|
+
```js
|
|
447
|
+
button.addEventListener('click', async () => {
|
|
448
|
+
const { openEditor } = await import('./editor');
|
|
449
|
+
openEditor();
|
|
450
|
+
});
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
**2. On Visibility (Intersection Observer):** Load when a component scrolls into or near
|
|
454
|
+
the viewport. Ideal for below-the-fold content.
|
|
455
|
+
|
|
456
|
+
```js
|
|
457
|
+
const observer = new IntersectionObserver((entries) => {
|
|
458
|
+
entries.forEach(entry => {
|
|
459
|
+
if (entry.isIntersecting) {
|
|
460
|
+
import('./heavy-component').then(module => {
|
|
461
|
+
module.render(entry.target);
|
|
462
|
+
});
|
|
463
|
+
observer.unobserve(entry.target);
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
}, { rootMargin: '200px' }); // start loading 200px before visible
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
**3. On Idle (requestIdleCallback):** Prefetch chunks during browser idle periods. The
|
|
470
|
+
user does not experience loading delay when they eventually need the module.
|
|
471
|
+
|
|
472
|
+
```js
|
|
473
|
+
// Prefetch during idle time
|
|
474
|
+
if ('requestIdleCallback' in window) {
|
|
475
|
+
requestIdleCallback(() => {
|
|
476
|
+
import('./likely-needed-soon');
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
**4. Prefetch Hints (webpack magic comments):**
|
|
482
|
+
|
|
483
|
+
```js
|
|
484
|
+
// webpackPrefetch: downloads during idle time (low priority)
|
|
485
|
+
const Settings = lazy(() => import(/* webpackPrefetch: true */ './Settings'));
|
|
486
|
+
|
|
487
|
+
// webpackPreload: downloads immediately (high priority, parallel with parent)
|
|
488
|
+
const CriticalComponent = lazy(() => import(/* webpackPreload: true */ './Critical'));
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
Prefetch uses `<link rel="prefetch">` (fetched during idle), while preload uses
|
|
492
|
+
`<link rel="preload">` (fetched immediately with higher priority).
|
|
493
|
+
|
|
494
|
+
### Framework-Specific Patterns
|
|
495
|
+
|
|
496
|
+
**React:**
|
|
497
|
+
```js
|
|
498
|
+
const LazyComponent = React.lazy(() => import('./Component'));
|
|
499
|
+
// Wrap in Suspense with a fallback
|
|
500
|
+
<Suspense fallback={<Skeleton />}><LazyComponent /></Suspense>
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
**Vue:**
|
|
504
|
+
```js
|
|
505
|
+
const LazyComponent = defineAsyncComponent(() => import('./Component.vue'));
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
**Angular:**
|
|
509
|
+
```typescript
|
|
510
|
+
// In routing module
|
|
511
|
+
{ path: 'admin', loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule) }
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
---
|
|
515
|
+
|
|
516
|
+
## 6. Modern vs Legacy Bundles (Differential Serving)
|
|
517
|
+
|
|
518
|
+
### The Module/Nomodule Pattern
|
|
519
|
+
|
|
520
|
+
Differential serving produces two bundles: a modern bundle (ES2017+) for current browsers
|
|
521
|
+
and a legacy bundle (ES5) for older browsers. The HTML uses the module/nomodule pattern
|
|
522
|
+
to serve the correct one:
|
|
523
|
+
|
|
524
|
+
```html
|
|
525
|
+
<!-- Modern browsers execute this (smaller, no polyfills) -->
|
|
526
|
+
<script type="module" src="/js/app.modern.js"></script>
|
|
527
|
+
|
|
528
|
+
<!-- Legacy browsers execute this (transpiled, polyfilled) -->
|
|
529
|
+
<script nomodule src="/js/app.legacy.js"></script>
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
Modern browsers understand `type="module"` and ignore `nomodule`. Legacy browsers ignore
|
|
533
|
+
`type="module"` and execute `nomodule`.
|
|
534
|
+
|
|
535
|
+
### Size Savings
|
|
536
|
+
|
|
537
|
+
The savings from differential serving vary by application:
|
|
538
|
+
|
|
539
|
+
| Measurement Source | Modern Bundle Size | Legacy Bundle Size | Savings |
|
|
540
|
+
|-------------------|-------------------|-------------------|----------|
|
|
541
|
+
| Angular CLI tests | 1.85 MB | 2.03 MB | ~9% |
|
|
542
|
+
| General range | varies | varies | 10-50% |
|
|
543
|
+
| Typical SPA | varies | varies | 7-20% |
|
|
544
|
+
|
|
545
|
+
Source: [Alex MacArthur - Should We All Start Implementing Differential Serving?](https://macarthur.me/posts/should-we-implement-differential-serving/)
|
|
546
|
+
|
|
547
|
+
The savings come from:
|
|
548
|
+
- No transpilation of arrow functions, async/await, destructuring, template literals, classes
|
|
549
|
+
- No regenerator-runtime (~6 KB minified)
|
|
550
|
+
- Fewer or no core-js polyfills (can save 30-90 KB compressed depending on polyfill set)
|
|
551
|
+
- Shorter variable names and optimized output from native ES module syntax
|
|
552
|
+
|
|
553
|
+
### Polyfill Budget Impact
|
|
554
|
+
|
|
555
|
+
Targeting only modern browsers (Chrome 80+, Firefox 80+, Safari 14+, Edge 80+) vs
|
|
556
|
+
supporting IE 11 can reduce the polyfill footprint by **50 KB compressed** or more.
|
|
557
|
+
With `@babel/preset-env` and `useBuiltIns: 'usage'`, the polyfill count drops from ~293
|
|
558
|
+
to ~87 when targeting only modern browsers.
|
|
559
|
+
|
|
560
|
+
Source: [DebugBear - How Does Browser Support Impact JavaScript Bundle Size?](https://www.debugbear.com/blog/how-does-browser-support-impact-bundle-size)
|
|
561
|
+
|
|
562
|
+
### Current Relevance (2025)
|
|
563
|
+
|
|
564
|
+
With IE 11 reaching end of life in 2022 and global `type="module"` browser support above
|
|
565
|
+
95%, the legacy bundle is increasingly unnecessary. Many teams now ship only ESM bundles,
|
|
566
|
+
using a browserslist configuration like:
|
|
567
|
+
|
|
568
|
+
```
|
|
569
|
+
# .browserslistrc
|
|
570
|
+
last 2 Chrome versions
|
|
571
|
+
last 2 Firefox versions
|
|
572
|
+
last 2 Safari versions
|
|
573
|
+
last 2 Edge versions
|
|
574
|
+
not dead
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
This eliminates the legacy bundle entirely, saving build time and complexity.
|
|
578
|
+
|
|
579
|
+
---
|
|
580
|
+
|
|
581
|
+
## 7. Compression: Gzip vs Brotli
|
|
582
|
+
|
|
583
|
+
### Compression Ratio Comparison
|
|
584
|
+
|
|
585
|
+
| Metric | Gzip | Brotli |
|
|
586
|
+
|-------------------------|----------------|-----------------|
|
|
587
|
+
| Average file reduction | ~65% | ~70% |
|
|
588
|
+
| JS-specific improvement | baseline | 14% smaller than gzip |
|
|
589
|
+
| General text improvement | baseline | 15-25% smaller than gzip |
|
|
590
|
+
| Browser support | ~99% | ~96% |
|
|
591
|
+
| Compression speed | Faster | Slower (2-5x at high levels) |
|
|
592
|
+
| Decompression speed | Similar | Similar to slightly slower |
|
|
593
|
+
|
|
594
|
+
Source: [DebugBear - Brotli vs. GZIP: Improve Page Speed With HTTP Compression](https://www.debugbear.com/blog/http-compression-gzip-brotli)
|
|
595
|
+
|
|
596
|
+
### Real-World Numbers
|
|
597
|
+
|
|
598
|
+
For a typical JavaScript bundle:
|
|
599
|
+
|
|
600
|
+
| Bundle (uncompressed) | Gzip Size | Brotli Size | Brotli Savings vs Gzip |
|
|
601
|
+
|----------------------|-----------|-------------|----------------------|
|
|
602
|
+
| 500 KB | ~175 KB | ~150 KB | ~14% |
|
|
603
|
+
| 1 MB | ~350 KB | ~300 KB | ~14% |
|
|
604
|
+
| 200 KB | ~70 KB | ~60 KB | ~14% |
|
|
605
|
+
|
|
606
|
+
### Usage Trends
|
|
607
|
+
|
|
608
|
+
Based on HTTP Archive data from January 2024, **Brotli is used more than gzip for
|
|
609
|
+
JavaScript and CSS** across the web. This represents a tipping point where Brotli has
|
|
610
|
+
become the default compression for static assets.
|
|
611
|
+
|
|
612
|
+
Source: [Paul Calvano - Choosing Between gzip, Brotli and zStandard Compression](https://paulcalvano.com/2024-03-19-choosing-between-gzip-brotli-and-zstandard-compression/)
|
|
613
|
+
|
|
614
|
+
### Implementation Strategy
|
|
615
|
+
|
|
616
|
+
**Static compression (build time):** Pre-compress assets during the build and serve
|
|
617
|
+
the pre-compressed files. This allows using the highest Brotli compression level (11)
|
|
618
|
+
without impacting server response time.
|
|
619
|
+
|
|
620
|
+
```bash
|
|
621
|
+
# Generate .br files alongside your bundles
|
|
622
|
+
brotli -q 11 dist/main.js -o dist/main.js.br
|
|
623
|
+
gzip -9 -k dist/main.js
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
**Dynamic compression (server-side):** The server compresses on the fly. Use lower
|
|
627
|
+
compression levels (Brotli 4-6) to balance compression ratio against CPU cost.
|
|
628
|
+
|
|
629
|
+
**Recommended approach:** Use static Brotli (level 11) for all production assets, with
|
|
630
|
+
gzip as a fallback for the ~4% of browsers that do not support Brotli. Most CDNs
|
|
631
|
+
(Cloudflare, AWS CloudFront, Fastly) support both and negotiate via `Accept-Encoding`.
|
|
632
|
+
|
|
633
|
+
### Nginx Configuration Example
|
|
634
|
+
|
|
635
|
+
```nginx
|
|
636
|
+
# Enable both Brotli and gzip
|
|
637
|
+
brotli on;
|
|
638
|
+
brotli_comp_level 6;
|
|
639
|
+
brotli_types text/plain text/css application/javascript application/json;
|
|
640
|
+
|
|
641
|
+
gzip on;
|
|
642
|
+
gzip_comp_level 6;
|
|
643
|
+
gzip_types text/plain text/css application/javascript application/json;
|
|
644
|
+
|
|
645
|
+
# Prefer pre-compressed static files
|
|
646
|
+
brotli_static on;
|
|
647
|
+
gzip_static on;
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
---
|
|
651
|
+
|
|
652
|
+
## 8. ESM vs CommonJS and Bundle Size
|
|
653
|
+
|
|
654
|
+
### Why ESM Produces Smaller Bundles
|
|
655
|
+
|
|
656
|
+
ES Modules use static `import`/`export` declarations that are resolved at compile time.
|
|
657
|
+
This allows bundlers to:
|
|
658
|
+
|
|
659
|
+
1. **Tree-shake unused exports** -- only the imported bindings are included
|
|
660
|
+
2. **Scope-hoist (concatenate) modules** -- reduce per-module wrapper overhead
|
|
661
|
+
3. **Statically analyze the entire dependency graph** -- no dynamic resolution needed
|
|
662
|
+
|
|
663
|
+
CommonJS uses `require()` which is a runtime function call. The module specifier can be
|
|
664
|
+
computed dynamically, conditionally loaded, or monkey-patched. Bundlers must include the
|
|
665
|
+
entire module because they cannot prove which parts are unused.
|
|
666
|
+
|
|
667
|
+
### Measured Differences
|
|
668
|
+
|
|
669
|
+
In benchmarks comparing bundler output sizes across eight libraries, **Rollup and Vite
|
|
670
|
+
(ESM-based) produced output 19.5% smaller** than the largest bundler outputs. This
|
|
671
|
+
difference is directly attributable to more effective tree shaking on ESM code.
|
|
672
|
+
|
|
673
|
+
Source: [Strapi - Best Webpack Alternatives: Modern JS Bundlers 2025](https://strapi.io/blog/modern-javascript-bundlers-comparison-2025)
|
|
674
|
+
|
|
675
|
+
### The Dual-Package Hazard
|
|
676
|
+
|
|
677
|
+
When a dependency ships both ESM and CJS versions, the bundler may include both if
|
|
678
|
+
different parts of the dependency graph import the package in different formats. This
|
|
679
|
+
causes the library to appear twice in the bundle, doubling its size contribution and
|
|
680
|
+
potentially breaking shared state.
|
|
681
|
+
|
|
682
|
+
Source: [codejam.info - Duplicated ESM and CJS package in bundle](https://www.codejam.info/2024/02/esm-cjs-dupe.html)
|
|
683
|
+
|
|
684
|
+
**Detection:** Use webpack-bundle-analyzer and search for duplicate package names
|
|
685
|
+
appearing in different chunks or with different paths.
|
|
686
|
+
|
|
687
|
+
**Fix:** Force resolution to a single format using the bundler's `resolve.alias`
|
|
688
|
+
configuration or the package manager's resolution overrides.
|
|
689
|
+
|
|
690
|
+
```js
|
|
691
|
+
// webpack.config.js -- force ESM version
|
|
692
|
+
module.exports = {
|
|
693
|
+
resolve: {
|
|
694
|
+
alias: {
|
|
695
|
+
'problematic-package': 'problematic-package/esm/index.js'
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
};
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
### Migration Path
|
|
702
|
+
|
|
703
|
+
For library authors, the recommended approach is to publish ESM as the primary format with
|
|
704
|
+
CJS as a compatibility fallback using the package.json `exports` field:
|
|
705
|
+
|
|
706
|
+
```jsonc
|
|
707
|
+
{
|
|
708
|
+
"exports": {
|
|
709
|
+
".": {
|
|
710
|
+
"import": "./dist/index.mjs",
|
|
711
|
+
"require": "./dist/index.cjs"
|
|
712
|
+
}
|
|
713
|
+
},
|
|
714
|
+
"type": "module",
|
|
715
|
+
"sideEffects": false
|
|
716
|
+
}
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
---
|
|
720
|
+
|
|
721
|
+
## 9. Module Federation for Micro-Frontends
|
|
722
|
+
|
|
723
|
+
### What Module Federation Solves
|
|
724
|
+
|
|
725
|
+
Module Federation (introduced in Webpack 5) allows separately compiled and deployed
|
|
726
|
+
applications to share code at **runtime** rather than build time. Each micro-frontend
|
|
727
|
+
exposes specific modules, and consumers load them dynamically without rebuilding.
|
|
728
|
+
|
|
729
|
+
Source: [webpack - Module Federation](https://webpack.js.org/concepts/module-federation/)
|
|
730
|
+
|
|
731
|
+
### Architecture
|
|
732
|
+
|
|
733
|
+
```
|
|
734
|
+
Host Application
|
|
735
|
+
|
|
|
736
|
+
+-- Remote A (Team 1): exposes <Header />, <Footer />
|
|
737
|
+
| shared: react@18, react-dom@18
|
|
738
|
+
|
|
|
739
|
+
+-- Remote B (Team 2): exposes <ProductList />, <Cart />
|
|
740
|
+
| shared: react@18, react-dom@18, lodash-es
|
|
741
|
+
|
|
|
742
|
+
+-- Remote C (Team 3): exposes <AdminPanel />
|
|
743
|
+
shared: react@18, react-dom@18
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
Shared dependencies (like React) are loaded once and reused across all remotes, preventing
|
|
747
|
+
duplication. Each remote is its own deployment unit with independent CI/CD.
|
|
748
|
+
|
|
749
|
+
### Configuration Example
|
|
750
|
+
|
|
751
|
+
```js
|
|
752
|
+
// Host webpack.config.js
|
|
753
|
+
const { ModuleFederationPlugin } = require('webpack').container;
|
|
754
|
+
|
|
755
|
+
module.exports = {
|
|
756
|
+
plugins: [
|
|
757
|
+
new ModuleFederationPlugin({
|
|
758
|
+
name: 'host',
|
|
759
|
+
remotes: {
|
|
760
|
+
teamA: 'teamA@https://team-a.example.com/remoteEntry.js',
|
|
761
|
+
teamB: 'teamB@https://team-b.example.com/remoteEntry.js'
|
|
762
|
+
},
|
|
763
|
+
shared: {
|
|
764
|
+
react: { singleton: true, requiredVersion: '^18.0.0' },
|
|
765
|
+
'react-dom': { singleton: true, requiredVersion: '^18.0.0' }
|
|
766
|
+
}
|
|
767
|
+
})
|
|
768
|
+
]
|
|
769
|
+
};
|
|
770
|
+
|
|
771
|
+
// Remote (Team A) webpack.config.js
|
|
772
|
+
module.exports = {
|
|
773
|
+
plugins: [
|
|
774
|
+
new ModuleFederationPlugin({
|
|
775
|
+
name: 'teamA',
|
|
776
|
+
filename: 'remoteEntry.js',
|
|
777
|
+
exposes: {
|
|
778
|
+
'./Header': './src/components/Header',
|
|
779
|
+
'./Footer': './src/components/Footer'
|
|
780
|
+
},
|
|
781
|
+
shared: {
|
|
782
|
+
react: { singleton: true, requiredVersion: '^18.0.0' },
|
|
783
|
+
'react-dom': { singleton: true, requiredVersion: '^18.0.0' }
|
|
784
|
+
}
|
|
785
|
+
})
|
|
786
|
+
]
|
|
787
|
+
};
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
### Bundle Size Impact
|
|
791
|
+
|
|
792
|
+
Module Federation's effect on bundle size is nuanced:
|
|
793
|
+
|
|
794
|
+
**Positive:** Shared dependencies are loaded once. Without federation, each micro-frontend
|
|
795
|
+
might bundle its own copy of React (128 KB minified), resulting in 3x duplication for 3
|
|
796
|
+
micro-frontends. With federation, React is loaded once.
|
|
797
|
+
|
|
798
|
+
**Negative:** The `remoteEntry.js` manifest files add overhead (~5-15 KB each), and runtime
|
|
799
|
+
negotiation of shared dependencies adds initialization cost. For smaller applications, this
|
|
800
|
+
overhead may exceed the savings.
|
|
801
|
+
|
|
802
|
+
**Enterprise adoption:** 85%+ of enterprise organizations with micro-frontend architectures
|
|
803
|
+
use Module Federation or similar runtime-sharing patterns as of 2025.
|
|
804
|
+
|
|
805
|
+
Source: [Zalando Engineering - Building a Modular Portal with Webpack Module Federation](https://engineering.zalando.com/posts/2024/10/building-modular-portal-with-webpack-module-federation.html)
|
|
806
|
+
|
|
807
|
+
### When to Use Module Federation
|
|
808
|
+
|
|
809
|
+
- Multiple teams own different parts of the application
|
|
810
|
+
- Independent deployment cycles are required
|
|
811
|
+
- The application is large enough that shared dependencies (React, design system) would
|
|
812
|
+
otherwise be duplicated across separately deployed bundles
|
|
813
|
+
- Build times are a bottleneck because the entire application must rebuild for any change
|
|
814
|
+
|
|
815
|
+
### When NOT to Use Module Federation
|
|
816
|
+
|
|
817
|
+
- Single-team applications
|
|
818
|
+
- Applications under 500 KB total bundle size
|
|
819
|
+
- When build-time code sharing (npm packages, monorepo) is sufficient
|
|
820
|
+
- When the runtime overhead (~50-100ms initialization) is unacceptable
|
|
821
|
+
|
|
822
|
+
---
|
|
823
|
+
|
|
824
|
+
## 10. Common Bottlenecks and Heavy Dependencies
|
|
825
|
+
|
|
826
|
+
### The Usual Suspects
|
|
827
|
+
|
|
828
|
+
| Library | Minified Size | Gzipped Size | Problem | Alternative | Alternative Size (gzipped) |
|
|
829
|
+
|-------------------|--------------|-------------|------------------------------------------------|--------------------------------|---------------------------|
|
|
830
|
+
| moment.js | 232 KB | 66 KB | Not tree-shakeable + 160 KB locales | date-fns | 2-10 KB (per function) |
|
|
831
|
+
| moment.js + locales | 392 KB | 98 KB | All locales bundled by default | dayjs (2 KB) or Temporal API | 2-7 KB |
|
|
832
|
+
| lodash (full) | 531 KB | 72 KB | Entire library imported for a few functions | lodash-es (tree-shake) or native | 1-5 KB (per function) |
|
|
833
|
+
| chart.js (full) | 200 KB | 65 KB | All chart types registered | Register only needed types | 30-50 KB |
|
|
834
|
+
| core-js (full) | 250+ KB | 75+ KB | All polyfills regardless of browser target | Targeted via browserslist | 10-30 KB |
|
|
835
|
+
| @fortawesome (all)| 1.5+ MB | 400+ KB | All icon packs imported | Import individual icons | 5-20 KB |
|
|
836
|
+
|
|
837
|
+
Source: [Medium - Reduce JavaScript Bundle Size by Replacing MomentJS with Date-fns](https://thefiend.medium.com/replacing-momentjs-with-date-fns-for-a-smaller-package-size-3365f358db4d)
|
|
838
|
+
|
|
839
|
+
### moment.js: The Classic Offender
|
|
840
|
+
|
|
841
|
+
Moment.js is officially in maintenance mode. The Moment team has stated they **discourage
|
|
842
|
+
Moment from being used in new projects**. The main issues:
|
|
843
|
+
|
|
844
|
+
1. The entire library (232 KB min) is loaded even if you use one function
|
|
845
|
+
2. All locale files (160 KB min) are bundled by default in webpack
|
|
846
|
+
3. The object-oriented API prevents tree shaking
|
|
847
|
+
|
|
848
|
+
**Webpack mitigation (if migration is not possible):**
|
|
849
|
+
```js
|
|
850
|
+
// webpack.config.js -- exclude all locales
|
|
851
|
+
const webpack = require('webpack');
|
|
852
|
+
module.exports = {
|
|
853
|
+
plugins: [
|
|
854
|
+
new webpack.IgnorePlugin({
|
|
855
|
+
resourceRegExp: /^\.\/locale$/,
|
|
856
|
+
contextRegExp: /moment$/
|
|
857
|
+
})
|
|
858
|
+
]
|
|
859
|
+
};
|
|
860
|
+
// Saves ~160 KB minified, ~40 KB gzipped
|
|
861
|
+
```
|
|
862
|
+
|
|
863
|
+
Source: [GitHub - You-Dont-Need-Momentjs](https://github.com/you-dont-need/You-Dont-Need-Momentjs)
|
|
864
|
+
|
|
865
|
+
### lodash: Import Discipline
|
|
866
|
+
|
|
867
|
+
```js
|
|
868
|
+
// BAD: imports all 531 KB
|
|
869
|
+
import _ from 'lodash';
|
|
870
|
+
_.debounce(fn, 300);
|
|
871
|
+
|
|
872
|
+
// BETTER: cherry-pick (works with CJS lodash)
|
|
873
|
+
import debounce from 'lodash/debounce';
|
|
874
|
+
|
|
875
|
+
// BEST: use lodash-es for tree shaking
|
|
876
|
+
import { debounce } from 'lodash-es';
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
Using individual imports or lodash-es typically results in only **1-5 KB per function**
|
|
880
|
+
included in the bundle, compared to 72 KB gzipped for the full library.
|
|
881
|
+
|
|
882
|
+
### Duplicate Dependencies
|
|
883
|
+
|
|
884
|
+
Duplicate dependencies occur when multiple versions of the same package exist in the
|
|
885
|
+
dependency tree because transitive dependencies request incompatible semver ranges.
|
|
886
|
+
|
|
887
|
+
**Detection:**
|
|
888
|
+
```bash
|
|
889
|
+
# Check for duplicates in yarn
|
|
890
|
+
yarn dedupe --check
|
|
891
|
+
|
|
892
|
+
# Check for duplicates in npm
|
|
893
|
+
npm ls lodash # shows all versions in the tree
|
|
894
|
+
|
|
895
|
+
# Use webpack-bundle-analyzer and search for duplicate module names
|
|
896
|
+
```
|
|
897
|
+
|
|
898
|
+
**Impact:** Atlassian's Jira team found that their webpack-deduplication-plugin reduced
|
|
899
|
+
JavaScript bundle size by approximately **10%** just by eliminating duplicate packages.
|
|
900
|
+
|
|
901
|
+
Source: [Atlassian Engineering - Performance in Jira front-end: solving bundle duplicates](https://www.atlassian.com/blog/atlassian-engineering/performance-in-jira-front-end-solving-bundle-duplicates-with-webpack-and-yarn)
|
|
902
|
+
|
|
903
|
+
**Fix:**
|
|
904
|
+
```jsonc
|
|
905
|
+
// package.json -- force a single version (yarn)
|
|
906
|
+
{
|
|
907
|
+
"resolutions": {
|
|
908
|
+
"lodash": "^4.17.21"
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
// package.json -- force a single version (npm)
|
|
913
|
+
{
|
|
914
|
+
"overrides": {
|
|
915
|
+
"lodash": "^4.17.21"
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
---
|
|
921
|
+
|
|
922
|
+
## 11. Anti-Patterns
|
|
923
|
+
|
|
924
|
+
### Anti-Pattern 1: Importing Entire Libraries
|
|
925
|
+
|
|
926
|
+
```js
|
|
927
|
+
// ANTI-PATTERN: pulls in all 500+ lodash functions
|
|
928
|
+
import _ from 'lodash';
|
|
929
|
+
const result = _.get(obj, 'a.b.c');
|
|
930
|
+
|
|
931
|
+
// FIX: import only what you use
|
|
932
|
+
import get from 'lodash/get';
|
|
933
|
+
const result = get(obj, 'a.b.c');
|
|
934
|
+
|
|
935
|
+
// BETTER FIX: use native optional chaining (0 KB)
|
|
936
|
+
const result = obj?.a?.b?.c;
|
|
937
|
+
```
|
|
938
|
+
|
|
939
|
+
**Impact:** Importing all of lodash adds ~72 KB gzipped to your bundle. Using a single
|
|
940
|
+
function via direct import adds ~1-2 KB. Using native JavaScript features adds 0 KB.
|
|
941
|
+
|
|
942
|
+
### Anti-Pattern 2: Barrel File Re-Exports
|
|
943
|
+
|
|
944
|
+
Barrel files (`index.ts` that re-export from many modules) defeat tree shaking in many
|
|
945
|
+
bundler configurations.
|
|
946
|
+
|
|
947
|
+
```typescript
|
|
948
|
+
// components/index.ts -- BARREL FILE (anti-pattern at scale)
|
|
949
|
+
export { Button } from './Button';
|
|
950
|
+
export { Modal } from './Modal';
|
|
951
|
+
export { DataGrid } from './DataGrid'; // 150 KB
|
|
952
|
+
export { RichTextEditor } from './Editor'; // 200 KB
|
|
953
|
+
export { Chart } from './Chart'; // 180 KB
|
|
954
|
+
|
|
955
|
+
// Consumer only needs Button, but may pull in everything
|
|
956
|
+
import { Button } from './components';
|
|
957
|
+
// Result: 255 KB first-load JS for a button component
|
|
958
|
+
```
|
|
959
|
+
|
|
960
|
+
Source: [DEV Community - The Barrel Trap](https://dev.to/elmay/the-barrel-trap-how-i-learned-to-stop-re-exporting-and-love-explicit-imports-3872)
|
|
961
|
+
|
|
962
|
+
**Fix:** Use direct imports to the specific module file:
|
|
963
|
+
|
|
964
|
+
```typescript
|
|
965
|
+
// Direct import -- only Button code is included
|
|
966
|
+
import { Button } from './components/Button';
|
|
967
|
+
```
|
|
968
|
+
|
|
969
|
+
**Next.js mitigation:** Next.js provides `optimizePackageImports` that rewrites barrel
|
|
970
|
+
imports to direct imports automatically at build time.
|
|
971
|
+
|
|
972
|
+
```js
|
|
973
|
+
// next.config.js
|
|
974
|
+
module.exports = {
|
|
975
|
+
experimental: {
|
|
976
|
+
optimizePackageImports: ['@mui/material', '@mui/icons-material']
|
|
977
|
+
}
|
|
978
|
+
};
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
### Anti-Pattern 3: Not Analyzing Your Bundle
|
|
982
|
+
|
|
983
|
+
A surprisingly common anti-pattern is never running bundle analysis. Teams add dependencies
|
|
984
|
+
throughout the project lifecycle without checking their size impact. By the time performance
|
|
985
|
+
degrades, the bundle is a tangled mess of oversized and duplicate dependencies.
|
|
986
|
+
|
|
987
|
+
**Rule:** Run `webpack-bundle-analyzer` or `rollup-plugin-visualizer` at least once per
|
|
988
|
+
sprint and before every major release. Add bundle size checks to CI.
|
|
989
|
+
|
|
990
|
+
### Anti-Pattern 4: Missing `sideEffects` in Library Code
|
|
991
|
+
|
|
992
|
+
Library authors who omit the `sideEffects` field from `package.json` prevent their
|
|
993
|
+
consumers' bundlers from effectively tree-shaking the library. Even fully ESM libraries
|
|
994
|
+
will not tree-shake optimally without this flag because the bundler cannot prove that
|
|
995
|
+
skipped modules have no side effects.
|
|
996
|
+
|
|
997
|
+
### Anti-Pattern 5: Excessive Polyfilling
|
|
998
|
+
|
|
999
|
+
Including `core-js/stable` or `import 'core-js'` at the application entry point pulls
|
|
1000
|
+
in **all** polyfills regardless of the browserslist target or actual feature usage. This
|
|
1001
|
+
can add 75+ KB gzipped of polyfill code that modern browsers do not need.
|
|
1002
|
+
|
|
1003
|
+
**Fix:** Use `useBuiltIns: 'usage'` in `@babel/preset-env`:
|
|
1004
|
+
|
|
1005
|
+
```json
|
|
1006
|
+
{
|
|
1007
|
+
"presets": [
|
|
1008
|
+
["@babel/preset-env", {
|
|
1009
|
+
"useBuiltIns": "usage",
|
|
1010
|
+
"corejs": 3
|
|
1011
|
+
}]
|
|
1012
|
+
]
|
|
1013
|
+
}
|
|
1014
|
+
```
|
|
1015
|
+
|
|
1016
|
+
This injects only the polyfills that are actually used in your source code, for only the
|
|
1017
|
+
browsers that need them (per your browserslist config). The reduction from ~293 polyfills
|
|
1018
|
+
to ~87 (or fewer) is common.
|
|
1019
|
+
|
|
1020
|
+
### Anti-Pattern 6: Shipping Source Maps to Production
|
|
1021
|
+
|
|
1022
|
+
Source maps do not affect runtime performance (browsers only download them when DevTools
|
|
1023
|
+
are open), but they increase deployment artifact sizes and expose source code. If you
|
|
1024
|
+
must ship source maps, use `hidden-source-map` to prevent the browser from requesting
|
|
1025
|
+
them automatically.
|
|
1026
|
+
|
|
1027
|
+
---
|
|
1028
|
+
|
|
1029
|
+
## 12. Before/After Case Studies
|
|
1030
|
+
|
|
1031
|
+
### Case Study 1: Replacing moment.js with date-fns
|
|
1032
|
+
|
|
1033
|
+
A React application replaced moment.js with date-fns for date formatting and manipulation.
|
|
1034
|
+
|
|
1035
|
+
| Metric | moment.js | date-fns | Savings |
|
|
1036
|
+
|-------------------|--------------|---------------|-------------|
|
|
1037
|
+
| Stat size | 1.19 MB | 1.09 MB | 100 KB |
|
|
1038
|
+
| Parsed size | 398.78 KB | 354.23 KB | 44.55 KB |
|
|
1039
|
+
| Gzipped size | 121.71 KB | 107.27 KB | 14.44 KB |
|
|
1040
|
+
|
|
1041
|
+
Source: [Medium - Replacing MomentJS with Date-fns for a Smaller Package Size](https://thefiend.medium.com/replacing-momentjs-with-date-fns-for-a-smaller-package-size-3365f358db4d)
|
|
1042
|
+
|
|
1043
|
+
Additionally, after removing the moment.js locale IgnorePlugin workaround (which was
|
|
1044
|
+
previously hiding 160 KB of locale data), the date-fns version included only the 3 locales
|
|
1045
|
+
actually used by the application.
|
|
1046
|
+
|
|
1047
|
+
### Case Study 2: Route-Based Code Splitting in a React SPA
|
|
1048
|
+
|
|
1049
|
+
A mid-size e-commerce application with 10 routes applied route-based code splitting.
|
|
1050
|
+
|
|
1051
|
+
| Metric | Before | After | Improvement |
|
|
1052
|
+
|--------------------------|-------------|-------------|--------------|
|
|
1053
|
+
| Initial JS bundle | 2.3 MB | 875 KB | 62% |
|
|
1054
|
+
| Time to Interactive | 5.2 s | 2.7 s | 48% |
|
|
1055
|
+
| First Contentful Paint | 1.8 s | 1.2 s | 33% |
|
|
1056
|
+
| Largest Contentful Paint | 3.4 s | 2.1 s | 38% |
|
|
1057
|
+
|
|
1058
|
+
Source: [Coditation - Optimizing Bundle Sizes in React Applications](https://www.coditation.com/blog/optimizing-bundle-sizes-in-react-applications-a-deep-dive-into-code-splitting-and-lazy-loading)
|
|
1059
|
+
|
|
1060
|
+
### Case Study 3: Jira Front-End Deduplication
|
|
1061
|
+
|
|
1062
|
+
Atlassian's Jira front-end team identified and eliminated duplicate dependencies across
|
|
1063
|
+
their webpack bundle using yarn deduplication and a custom webpack plugin.
|
|
1064
|
+
|
|
1065
|
+
| Metric | Before | After | Improvement |
|
|
1066
|
+
|------------------|----------------|----------------|-------------|
|
|
1067
|
+
| JS bundle size | baseline | -10% | 10% |
|
|
1068
|
+
| Build warnings | 200+ duplicate | 12 remaining | 94% fewer |
|
|
1069
|
+
|
|
1070
|
+
Source: [Atlassian Engineering - Performance in Jira front-end](https://www.atlassian.com/blog/atlassian-engineering/performance-in-jira-front-end-solving-bundle-duplicates-with-webpack-and-yarn)
|
|
1071
|
+
|
|
1072
|
+
### Case Study 4: Barrel File Elimination
|
|
1073
|
+
|
|
1074
|
+
A Next.js application with a shared component library barrel file that re-exported 50+
|
|
1075
|
+
components migrated to direct imports.
|
|
1076
|
+
|
|
1077
|
+
| Metric | Barrel Import | Direct Import | Improvement |
|
|
1078
|
+
|----------------------|----------------|----------------|-------------|
|
|
1079
|
+
| First-load JS (page) | 255 KB | 42 KB | 84% |
|
|
1080
|
+
| Shared chunk size | 380 KB | 95 KB | 75% |
|
|
1081
|
+
|
|
1082
|
+
Source: [joshuakgoldberg.com - Speeding Up Centered Part 3: Barrel Exports](https://www.joshuakgoldberg.com/blog/speeding-up-centered-part-3-barrel-exports/)
|
|
1083
|
+
|
|
1084
|
+
### Case Study 5: Switching from Gzip to Brotli
|
|
1085
|
+
|
|
1086
|
+
A content-heavy web application switched its CDN from gzip-only to Brotli (level 11,
|
|
1087
|
+
static compression) for all JavaScript and CSS assets.
|
|
1088
|
+
|
|
1089
|
+
| Asset Type | Gzip Size | Brotli Size | Savings |
|
|
1090
|
+
|---------------|------------|-------------|---------|
|
|
1091
|
+
| Main JS bundle | 175 KB | 150 KB | 14% |
|
|
1092
|
+
| Vendor JS | 120 KB | 103 KB | 14% |
|
|
1093
|
+
| CSS bundle | 45 KB | 38 KB | 16% |
|
|
1094
|
+
| Total | 340 KB | 291 KB | 14.4% |
|
|
1095
|
+
|
|
1096
|
+
---
|
|
1097
|
+
|
|
1098
|
+
## 13. Decision Tree: My Bundle Is Too Large
|
|
1099
|
+
|
|
1100
|
+
Follow this diagnostic flowchart when your bundle exceeds its size budget.
|
|
1101
|
+
|
|
1102
|
+
```
|
|
1103
|
+
START: Bundle exceeds size budget
|
|
1104
|
+
|
|
|
1105
|
+
v
|
|
1106
|
+
Step 1: MEASURE
|
|
1107
|
+
Run webpack-bundle-analyzer / rollup-plugin-visualizer
|
|
1108
|
+
|
|
|
1109
|
+
v
|
|
1110
|
+
What does the treemap show?
|
|
1111
|
+
|
|
|
1112
|
+
+---> One or two HUGE third-party libraries?
|
|
1113
|
+
| |
|
|
1114
|
+
| v
|
|
1115
|
+
| Are they tree-shakeable?
|
|
1116
|
+
| |
|
|
1117
|
+
| +---> YES: Check import style
|
|
1118
|
+
| | - Using barrel import? --> Switch to direct import
|
|
1119
|
+
| | - Missing sideEffects flag? --> Add to package.json
|
|
1120
|
+
| | - Using default import? --> Switch to named imports
|
|
1121
|
+
| |
|
|
1122
|
+
| +---> NO: Can you replace them?
|
|
1123
|
+
| |
|
|
1124
|
+
| +---> moment.js --> date-fns or dayjs (save ~50-60 KB gzipped)
|
|
1125
|
+
| +---> lodash --> lodash-es or native (save ~60-70 KB gzipped)
|
|
1126
|
+
| +---> Full icon libraries --> individual icon imports
|
|
1127
|
+
| +---> No replacement --> lazy-load if not needed on initial render
|
|
1128
|
+
|
|
|
1129
|
+
+---> DUPLICATE packages in the treemap?
|
|
1130
|
+
| |
|
|
1131
|
+
| v
|
|
1132
|
+
| Run: npm ls <package> or yarn why <package>
|
|
1133
|
+
| Fix: Add resolutions/overrides to force a single version
|
|
1134
|
+
| Impact: typically 5-10% reduction
|
|
1135
|
+
|
|
|
1136
|
+
+---> POLYFILL code taking significant space?
|
|
1137
|
+
| |
|
|
1138
|
+
| v
|
|
1139
|
+
| Check browserslist config --> are you targeting dead browsers?
|
|
1140
|
+
| Switch to useBuiltIns: 'usage' in @babel/preset-env
|
|
1141
|
+
| Remove manual core-js/stable import
|
|
1142
|
+
| Impact: can save 30-75 KB gzipped
|
|
1143
|
+
|
|
|
1144
|
+
+---> EVERYTHING is in ONE chunk (no splitting)?
|
|
1145
|
+
| |
|
|
1146
|
+
| v
|
|
1147
|
+
| Implement route-based code splitting (Step 1)
|
|
1148
|
+
| Add vendor splitting via SplitChunksPlugin
|
|
1149
|
+
| Lazy-load heavy components (modals, charts, editors)
|
|
1150
|
+
| Impact: 40-62% initial bundle reduction
|
|
1151
|
+
|
|
|
1152
|
+
+---> Multiple SMALL issues across many modules?
|
|
1153
|
+
|
|
|
1154
|
+
v
|
|
1155
|
+
Audit ALL dependencies:
|
|
1156
|
+
- npm ls --all | wc -l (count total packages)
|
|
1157
|
+
- Remove unused dependencies
|
|
1158
|
+
- Replace heavy packages with lighter alternatives
|
|
1159
|
+
- Check for packages that should be devDependencies
|
|
1160
|
+
- Run npx depcheck to find unused dependencies
|
|
1161
|
+
|
|
|
1162
|
+
v
|
|
1163
|
+
Still over budget?
|
|
1164
|
+
|
|
|
1165
|
+
v
|
|
1166
|
+
Apply compression improvements:
|
|
1167
|
+
- Switch from gzip to Brotli (save ~14%)
|
|
1168
|
+
- Enable static pre-compression at build time
|
|
1169
|
+
- Verify CDN serves compressed assets correctly
|
|
1170
|
+
|
|
|
1171
|
+
v
|
|
1172
|
+
Still over budget?
|
|
1173
|
+
|
|
|
1174
|
+
v
|
|
1175
|
+
Consider architecture changes:
|
|
1176
|
+
- Module Federation to share deps across micro-frontends
|
|
1177
|
+
- Server-side rendering to reduce client-side JS
|
|
1178
|
+
- Partial hydration / islands architecture
|
|
1179
|
+
- Move computation to Web Workers or server
|
|
1180
|
+
```
|
|
1181
|
+
|
|
1182
|
+
### Quick Wins Ranked by Impact
|
|
1183
|
+
|
|
1184
|
+
| Action | Typical Savings (gzipped) | Effort |
|
|
1185
|
+
|-------------------------------------------|--------------------------|---------|
|
|
1186
|
+
| Route-based code splitting | 40-60% of initial load | Medium |
|
|
1187
|
+
| Replace moment.js with date-fns/dayjs | 50-60 KB | Low |
|
|
1188
|
+
| Direct imports instead of barrel files | 20-80% per affected page | Low |
|
|
1189
|
+
| Eliminate duplicate dependencies | 5-10% total | Low |
|
|
1190
|
+
| Tree-shake lodash (lodash-es or direct) | 60-70 KB | Low |
|
|
1191
|
+
| Switch to Brotli compression | 14% of total compressed | Low |
|
|
1192
|
+
| Remove unnecessary polyfills | 30-75 KB | Medium |
|
|
1193
|
+
| Lazy-load heavy components | Varies (per component) | Medium |
|
|
1194
|
+
| Differential serving (drop legacy bundle) | 7-20% per modern bundle | High |
|
|
1195
|
+
| Module Federation | Prevents N-way duplication| High |
|
|
1196
|
+
|
|
1197
|
+
### Continuous Monitoring
|
|
1198
|
+
|
|
1199
|
+
After fixing issues, prevent regression:
|
|
1200
|
+
|
|
1201
|
+
1. Add `bundlesize` or equivalent to CI -- fail PRs that exceed the budget
|
|
1202
|
+
2. Run bundle analysis on every release candidate
|
|
1203
|
+
3. Review new dependencies before installation (check BundlePhobia first)
|
|
1204
|
+
4. Track bundle size trends over time with tools like Calibre or SpeedCurve
|
|
1205
|
+
5. Set webpack `performance.hints: 'error'` to catch regressions during development
|
|
1206
|
+
|
|
1207
|
+
---
|
|
1208
|
+
|
|
1209
|
+
## 14. Sources
|
|
1210
|
+
|
|
1211
|
+
- [web.dev - Incorporate performance budgets into your build process](https://web.dev/articles/incorporate-performance-budgets-into-your-build-tools)
|
|
1212
|
+
- [web.dev - Setting performance budgets with webpack](https://web.dev/articles/codelab-setting-performance-budgets-with-webpack)
|
|
1213
|
+
- [web.dev - Performance budgets with the Angular CLI](https://web.dev/articles/performance-budgets-with-the-angular-cli)
|
|
1214
|
+
- [Addy Osmani - Start Performance Budgeting](https://addyosmani.com/blog/performance-budgets/)
|
|
1215
|
+
- [Addy Osmani - The Cost of JavaScript in 2018](https://medium.com/@addyosmani/the-cost-of-javascript-in-2018-7d8950fbb5d4)
|
|
1216
|
+
- [webpack - Tree Shaking guide](https://webpack.js.org/guides/tree-shaking/)
|
|
1217
|
+
- [webpack - Module Federation](https://webpack.js.org/concepts/module-federation/)
|
|
1218
|
+
- [webpack-bundle-analyzer on npm](https://www.npmjs.com/package/webpack-bundle-analyzer)
|
|
1219
|
+
- [Smashing Magazine - Improving JavaScript Bundle Performance With Code-Splitting](https://www.smashingmagazine.com/2022/02/javascript-bundle-performance-code-splitting/)
|
|
1220
|
+
- [Smashing Magazine - Tree-Shaking: A Reference Guide](https://www.smashingmagazine.com/2021/05/tree-shaking-reference-guide/)
|
|
1221
|
+
- [DebugBear - Brotli vs. GZIP](https://www.debugbear.com/blog/http-compression-gzip-brotli)
|
|
1222
|
+
- [DebugBear - How Does Browser Support Impact JavaScript Bundle Size?](https://www.debugbear.com/blog/how-does-browser-support-impact-bundle-size)
|
|
1223
|
+
- [Paul Calvano - Choosing Between gzip, Brotli and zStandard Compression](https://paulcalvano.com/2024-03-19-choosing-between-gzip-brotli-and-zstandard-compression/)
|
|
1224
|
+
- [Atlassian Engineering - Solving bundle duplicates with Webpack and yarn](https://www.atlassian.com/blog/atlassian-engineering/performance-in-jira-front-end-solving-bundle-duplicates-with-webpack-and-yarn)
|
|
1225
|
+
- [Zalando Engineering - Building a Modular Portal with Webpack Module Federation](https://engineering.zalando.com/posts/2024/10/building-modular-portal-with-webpack-module-federation.html)
|
|
1226
|
+
- [Coditation - Optimizing Bundle Sizes in React Applications](https://www.coditation.com/blog/optimizing-bundle-sizes-in-react-applications-a-deep-dive-into-code-splitting-and-lazy-loading)
|
|
1227
|
+
- [Strapi - Best Webpack Alternatives: Modern JS Bundlers 2025](https://strapi.io/blog/modern-javascript-bundlers-comparison-2025)
|
|
1228
|
+
- [codejam.info - Duplicated ESM and CJS package in bundle](https://www.codejam.info/2024/02/esm-cjs-dupe.html)
|
|
1229
|
+
- [DEV Community - The Barrel Trap](https://dev.to/elmay/the-barrel-trap-how-i-learned-to-stop-re-exporting-and-love-explicit-imports-3872)
|
|
1230
|
+
- [joshuakgoldberg.com - Speeding Up Centered Part 3: Barrel Exports](https://www.joshuakgoldberg.com/blog/speeding-up-centered-part-3-barrel-exports/)
|
|
1231
|
+
- [Medium - Replacing MomentJS with Date-fns](https://thefiend.medium.com/replacing-momentjs-with-date-fns-for-a-smaller-package-size-3365f358db4d)
|
|
1232
|
+
- [GitHub - You-Dont-Need-Momentjs](https://github.com/you-dont-need/You-Dont-Need-Momentjs)
|
|
1233
|
+
- [Alex MacArthur - Should We All Start Implementing Differential Serving?](https://macarthur.me/posts/should-we-implement-differential-serving/)
|
|
1234
|
+
- [Calibre - Small Bundles, Fast Pages](https://calibreapp.com/blog/bundle-size-optimization)
|
|
1235
|
+
- [developerway.com - Bundle Size Investigation](https://www.developerway.com/posts/bundle-size-investigation)
|
|
1236
|
+
- [developerway.com - Webpack and yarn magic against duplicates](https://www.developerway.com/posts/webpack-and-yarn-magic-against-duplicates-in-bundles)
|
|
1237
|
+
- [MDN - Tree shaking glossary](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking)
|
|
1238
|
+
- [3perf.com - Polyfills guide](https://3perf.com/blog/polyfills/)
|
|
1239
|
+
- [DigitalOcean - How To Analyze Angular App Bundle Sizes](https://www.digitalocean.com/community/tutorials/angular-bundle-size)
|