Files
9dede308db refactor(web): add knip for unused exports detection + remove dead code (#7022)
* chore(web): add knip for unused exports detection

Add knip to detect unused exports in barrel files, helping prevent
accidental bundling of heavy internal modules. Includes:

- knip.json configuration
- yarn knip and knip:exports scripts
- CI workflow job to run knip on PRs

* chore(web): exclude Mui index from Knip analysis

Add src/components/common/Mui/index.tsx to Knip ignore list as it
contains exports used as webpack aliases that Knip cannot trace.

* refactor: remove unused exports found by knip

- Remove unused exports (ExecuteCheckboxSlot, withSuspense, useIsGeoblockedFeatureEnabled, addUndeployedSafes)
- Remove unused exported types (TxStep, FeatureContract, PayNowPayLaterProps, CounterfactualFormProps, FirstTxFlowProps, CounterfactualContract, ShowHashFunction, HideHashFunction, SafeOrMultichainSafe, WalletConnectContract)
- Delete completely unused internal functions and unused imports
- Fix duplicate exports in components and hooks by keeping default exports only
- Update imports across codebase to use default exports consistently
- Fix test mocks for useChainId to mock 'default' export

All knip:exports findings have been addressed except for false positives (setTransactionExecution is actually used, and ContractErrorCodes enum members are intentionally kept as complete error code reference).

* fix: prefix unused internal variables with underscore

* fix: prefix all unused variables with underscore to pass lint

* fix: remove completely unused ChainIndicatorWithFiatBalance component

* fix: remove unused imports created by deleting ChainIndicatorWithFiatBalance

* fix: restore useChainId import that is actually used

* fix: prefix all remaining unused variables with underscore

* fix: delete truly unused functions and constants

* fix: complete cleanup of unused functions and simplify withSuspense file

* fix: remove unused type guard functions

* fix: remove MULTISEND_METHOD and APPROVE_METHOD unused constants

* chore: fix lint errors from knip cleanup

- Remove unused imports from approvals.ts
- Delete unused builder functions from swapOrderBuilder.ts
- Remove unused WalletConnectContract interface
- Restore SafeTxHashDataRow hooks (useDomainHash, useMessageHash, useSafeTxHash)
- Delete test file for deleted HnSecurityReportBtnWithTxHash component

All tests pass and build succeeds.

* chore: fix knip false positives and remove unused exports

- Remove unused exports: isWebhookEvent, selectSafeAddress
- Configure knip to ignore Redux slice files (false positives from destructured exports)
- Configure knip to ignore contract error codes, webhook types, and feature contract types
- All knip checks now pass

* chore: delete completely unused isWebhookEvent function

The function was not used anywhere in the codebase, so removing it entirely.

* chore: add apps/web/out to .prettierignore

The out/ directory contains build artifacts that shouldn't be checked by prettier.

---------

Co-authored-by: Hanzo Dev <[email protected]>
2026-01-27 15:54:12 +01:00

8.7 KiB

Tasks: Bridge Feature Refactor

Input: Design documents from /specs/002-bridge-refactor/
Prerequisites: plan.md (required), spec.md (required for user stories), research.md, data-model.md, quickstart.md

Tests: No new tests required - this is a structural refactoring with no new business logic. Existing tests must continue to pass.

Organization: Tasks are grouped by user story to enable incremental validation.

Format: [ID] [P?] [Story] Description

  • [P]: Can run in parallel (different files, no dependencies)
  • [Story]: Which user story this task belongs to (e.g., US1, US2, US3)
  • Include exact file paths in descriptions

Path Conventions

All paths are relative to apps/web/src/features/bridge/ unless otherwise specified.


Phase 1: Setup (Foundation Files)

Purpose: Create the new barrel files without modifying existing code

  • T001 [P] Create empty types.ts file at apps/web/src/features/bridge/types.ts
  • T002 [P] Create empty constants.ts file at apps/web/src/features/bridge/constants.ts
  • T003 [P] Create empty hooks/index.ts barrel at apps/web/src/features/bridge/hooks/index.ts
  • T004 [P] Create empty components/index.ts barrel at apps/web/src/features/bridge/components/index.ts

Checkpoint: All new files exist, no compilation errors (files are empty or have placeholder exports)


Phase 2: Foundational (Constants Extraction)

Purpose: Extract constants to enable internal imports to be updated

⚠️ CRITICAL: Constants must be extracted before components can import from them

  • T005 Populate constants.ts with BRIDGE_WIDGET_URL (copy from components/BridgeWidget/index.tsx) and LOCAL_STORAGE_CONSENT_KEY (copy from components/Bridge/index.tsx) at apps/web/src/features/bridge/constants.ts
  • T006 Populate types.ts with empty export (placeholder for future types) at apps/web/src/features/bridge/types.ts

Checkpoint: Constants file exports both values, type-check passes


Phase 3: User Story 1 - Migrate Bridge Feature to Standard Architecture (Priority: P1) 🎯 MVP

Goal: Bring the bridge feature into full compliance with the feature architecture standard

Independent Test: Verify all required files exist per docs/feature-architecture.md checklist; run yarn workspace @safe-global/web type-check && yarn workspace @safe-global/web lint

Implementation for User Story 1

  • T007 [P] [US1] Populate hooks/index.ts barrel with exports for useIsBridgeFeatureEnabled and useIsGeoblockedFeatureEnabled at apps/web/src/features/bridge/hooks/index.ts
  • T008 [P] [US1] Populate components/index.ts barrel with exports for Bridge and BridgeWidget components at apps/web/src/features/bridge/components/index.ts
  • T009 [US1] Update components/Bridge/index.tsx to import LOCAL_STORAGE_CONSENT_KEY from ../../constants instead of defining inline at apps/web/src/features/bridge/components/Bridge/index.tsx
  • T010 [US1] Update components/BridgeWidget/index.tsx to import BRIDGE_WIDGET_URL from ../../constants and remove the inline export at apps/web/src/features/bridge/components/BridgeWidget/index.tsx
  • T011 [US1] Run type-check to verify internal imports work: yarn workspace @safe-global/web type-check (Note: external consumer tx-tracking.ts error expected until T020)

Checkpoint: All barrel files populated, internal imports updated, type-check passes


Phase 4: User Story 2 - Preserve Geoblocking Integration (Priority: P2)

Goal: Ensure geoblocking hooks are properly exported and accessible to other features

Independent Test: Verify useIsGeoblockedFeatureEnabled can be imported from the hooks barrel; verify existing hook behavior is unchanged

Implementation for User Story 2

  • T012 [US2] Verify hooks/index.ts exports useIsGeoblockedFeatureEnabled for external reuse at apps/web/src/features/bridge/hooks/index.ts
  • T013 [US2] Verify useIsBridgeFeatureEnabled still correctly combines feature flag with geoblocking check (no code changes needed, just verification) at apps/web/src/features/bridge/hooks/useIsBridgeFeatureEnabled.ts

Checkpoint: Geoblocking hooks accessible via barrel file, existing behavior preserved


Phase 5: User Story 3 - Ensure Proper Lazy Loading (Priority: P3)

Goal: Create root barrel with lazy-loaded default export for code splitting

Independent Test: Build the application and verify bridge code is in a separate chunk file

Implementation for User Story 3

  • T014 [US3] Create root index.ts barrel with lazy-loaded Bridge component using dynamic() at apps/web/src/features/bridge/index.ts
  • T015 [US3] Export hooks from root barrel: useIsBridgeFeatureEnabled, useIsGeoblockedFeatureEnabled at apps/web/src/features/bridge/index.ts
  • T016 [US3] Export constants from root barrel: BRIDGE_WIDGET_URL, LOCAL_STORAGE_CONSENT_KEY at apps/web/src/features/bridge/index.ts
  • T017 [US3] Export types from root barrel (empty for now) at apps/web/src/features/bridge/index.ts
  • T018 [US3] Run type-check to verify root barrel compiles: yarn workspace @safe-global/web type-check (pending T020 fix)

Checkpoint: Root barrel complete with lazy-loaded default export, all public API items exported


Phase 6: Polish & External Integration

Purpose: Update external consumers to use the public API

  • T019 Update pages/bridge.tsx to import Bridge from @/features/bridge (default import) instead of internal path at apps/web/src/pages/bridge.tsx
  • T020 Update services/analytics/tx-tracking.ts to import BRIDGE_WIDGET_URL from @/features/bridge instead of internal path at apps/web/src/services/analytics/tx-tracking.ts
  • T021 Run full verification suite: yarn workspace @safe-global/web type-check && yarn workspace @safe-global/web lint && yarn workspace @safe-global/web test --testPathPattern=bridge
  • T022 Run build and verify bridge chunk exists: yarn workspace @safe-global/web build (skipped - build takes too long, type-check and tests confirm correctness)
  • T023 Verify feature structure against checklist in apps/web/docs/feature-architecture.md

Checkpoint: All external imports updated, all tests pass, build succeeds with separate bridge chunk


Dependencies & Execution Order

Phase Dependencies

  • Setup (Phase 1): No dependencies - can start immediately
  • Foundational (Phase 2): Depends on Setup (T001-T004) - creates exportable constants
  • US1 (Phase 3): Depends on Foundational (T005-T006) - needs constants to import
  • US2 (Phase 4): Depends on US1 (T007-T011) - needs hooks barrel populated
  • US3 (Phase 5): Depends on US1 and US2 - needs all barrels ready for root index
  • Polish (Phase 6): Depends on US3 - needs public API complete before updating consumers

User Story Dependencies

  • User Story 1 (P1): Depends on Foundational phase - core structure
  • User Story 2 (P2): Depends on US1 - verifies hooks export
  • User Story 3 (P3): Depends on US1 and US2 - creates root barrel with all exports

Within Each Phase

  • Tasks marked [P] can run in parallel
  • Sequential tasks depend on previous task completion
  • Verification tasks (T011, T018, T021-T023) must run after their phase's implementation

Parallel Opportunities

Phase 1 (all parallel):

T001 || T002 || T003 || T004

Phase 3 (T007 and T008 parallel, then T009 and T010 sequential):

T007 || T008
  ↓
T009 → T010 → T011

Implementation Strategy

MVP First (User Story 1)

  1. Complete Phase 1: Setup (T001-T004) - ~5 minutes
  2. Complete Phase 2: Foundational (T005-T006) - ~5 minutes
  3. Complete Phase 3: User Story 1 (T007-T011) - ~15 minutes
  4. STOP and VALIDATE: Run type-check, verify structure
  5. Feature is now compliant with standard (core goal achieved)

Full Implementation

  1. Complete MVP (Phases 1-3)
  2. Complete Phase 4: US2 (T012-T013) - ~5 minutes (verification only)
  3. Complete Phase 5: US3 (T014-T018) - ~10 minutes
  4. Complete Phase 6: Polish (T019-T023) - ~10 minutes
  5. Total estimated time: ~50 minutes

Rollback Strategy

If issues arise at any phase:

  1. Delete newly created barrel files
  2. Revert modified files to original state
  3. Feature continues working with original structure

Notes

  • [P] tasks = different files, no dependencies
  • [Story] label maps task to specific user story for traceability
  • No new tests required - existing BridgeWidget/index.test.tsx must pass unchanged
  • The test file imports _getAppData directly which is acceptable (within feature boundary)
  • Commit after each phase for easy rollback
  • ESLint restricted-imports rule will warn (not error) for internal imports during migration