Skip to content

initial chunk and import changes#346

Open
jasonmorais wants to merge 15 commits intomainfrom
jason/react-skills-improvements
Open

initial chunk and import changes#346
jasonmorais wants to merge 15 commits intomainfrom
jason/react-skills-improvements

Conversation

@jasonmorais
Copy link
Contributor

@jasonmorais jasonmorais commented Feb 4, 2026

Summary by Sourcery

Introduce route-level code splitting and bundle optimisation while aligning Storybook stories, tests, and architecture rules with the updated frontend structure.

Bug Fixes:

  • Correct GraphQL test mocks and story data to match current schema fields such as currentUserAndCreateIfNotExists, userType, and username.
  • Fix Storybook imports and paths after relocating message, settings, and app container stories to new top-level locations.

Enhancements:

  • Enable lazy loading with Suspense for main app routes and signup routes to defer loading of page components.
  • Configure Vite Rollup manualChunks and related build settings to improve bundle splitting and control chunk sizes.
  • Refine Apollo cache configuration to use the tree-shakable lodash/merge import instead of the full lodash bundle.

Build:

  • Update Vite build configuration with manual chunking, esbuild minification, and an increased chunk size warning limit.
  • Increase Vitest test timeout for architecture tests performing expensive file analysis.

Tests:

  • Add and adjust Storybook stories to validate lazy-loaded routes, Suspense fallbacks, and the Apollo manual merge cache behaviour.
  • Extend frontend architecture tests to enforce kebab-case naming for Storybook files.

Chores:

  • Rename and relocate several Storybook files (including app, hero section, messages, and settings stories) to top-level, kebab-cased filenames to comply with new conventions.
  • Switch signup page components to default exports to support lazy-loaded routing.
  • Remove the now-unrequired top-level assets directory from the enforced UI ShareThrift folder structure.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Feb 4, 2026

Reviewer's Guide

Implements route-level lazy loading for app and signup layouts, optimizes bundle splitting via Vite/Rollup config, converts signup pages to default exports to support dynamic imports, tightens lodash usage in Apollo cache configuration, and updates Storybook stories and architecture tests to align with new routing, file naming, and mocking patterns.

Sequence diagram for lazy loaded signup routes with React Suspense

sequenceDiagram
    actor User
    participant BrowserRouter
    participant SignupRoutes
    participant ReactSuspense
    participant LazySelectAccountTypePage

    User->>BrowserRouter: Navigate to /signup/select-account-type
    BrowserRouter->>SignupRoutes: Render SignupRoutes
    SignupRoutes->>ReactSuspense: Render Suspense fallback
    ReactSuspense->>LazySelectAccountTypePage: Trigger dynamic import
    LazySelectAccountTypePage-->>ReactSuspense: Resolve module (default export)
    ReactSuspense->>BrowserRouter: Render SelectAccountTypePage inside SectionLayout
    BrowserRouter-->>User: Display select account type UI

    User->>BrowserRouter: Navigate to /signup/profile-setup
    BrowserRouter->>SignupRoutes: Match profile-setup route
    SignupRoutes->>ReactSuspense: Render Suspense fallback
    ReactSuspense->>LazySelectAccountTypePage: Keep previous lazy modules cached
    ReactSuspense-->>BrowserRouter: Render ProfileSetupPage after import
    BrowserRouter-->>User: Display profile setup UI
Loading

Updated class diagram for signup routes and Apollo cache merging

classDiagram
    class SignupRoutes {
        +React_FC
        +render(): JSX_Element
    }

    class SectionLayout {
        +React_FC
        +render(): JSX_Element
    }

    class SelectAccountTypePage {
        +default_export: React_FC
        +render(): JSX_Element
    }

    class AccountSetupPage {
        +default_export: React_FC
        +render(): JSX_Element
    }

    class ProfileSetupPage {
        +default_export: React_FC
        +render(): JSX_Element
    }

    class PaymentPage {
        +default_export: React_FC
        +render(): JSX_Element
    }

    class TermsPage {
        +default_export: React_FC
        +render(): JSX_Element
    }

    class ReactLazy {
        +lazy(loader): React_ComponentType
    }

    class ReactSuspense {
        +fallback: JSX_Element
    }

    SignupRoutes --> SectionLayout : uses
    SignupRoutes --> SelectAccountTypePage : lazy_imports
    SignupRoutes --> AccountSetupPage : lazy_imports
    SignupRoutes --> ProfileSetupPage : lazy_imports
    SignupRoutes --> PaymentPage : lazy_imports
    SignupRoutes --> TermsPage : lazy_imports
    SignupRoutes --> ReactLazy : calls
    SignupRoutes --> ReactSuspense : wraps_with

    class ApolloManualMergeCacheFix {
        +config: InMemoryCacheConfig
    }

    class InMemoryCacheConfig {
        +typePolicies: TypePolicies
    }

    class TypePolicies {
        +PersonalUser: PersonalUserPolicy
    }

    class PersonalUserPolicy {
        +fields: PersonalUserFields
    }

    class PersonalUserFields {
        +account: AccountFieldPolicy
    }

    class AccountFieldPolicy {
        +merge(existing, incoming): any
    }

    class LodashMerge {
        +merge(target, source1, source2): any
    }

    ApolloManualMergeCacheFix --> InMemoryCacheConfig : holds
    InMemoryCacheConfig --> TypePolicies : defines
    TypePolicies --> PersonalUserPolicy : contains
    PersonalUserPolicy --> PersonalUserFields : contains
    PersonalUserFields --> AccountFieldPolicy : contains
    AccountFieldPolicy --> LodashMerge : uses_merge_for_deep_merge
Loading

File-Level Changes

Change Details Files
Introduce React.lazy + Suspense-based code splitting for main app and signup flows, supported by converting signup pages to default exports and adding Storybook coverage for lazy routes.
  • Wrap AppRoutes and SignupRoutes route trees in Suspense with a simple div-based loading fallback.
  • Replace direct component imports in AppRoutes and SignupRoutes with React.lazy dynamic imports for listings, account, messages, reservations, admin dashboard, and signup pages.
  • Change signup page components to default-exported components so they can be imported directly via lazy() without named exports.
  • Add Storybook stories for signup and app routes that assert components render with lazy-loaded content and that Suspense boundaries exist.
apps/ui-sharethrift/src/components/layouts/app/index.tsx
apps/ui-sharethrift/src/components/layouts/signup/index.tsx
apps/ui-sharethrift/src/components/layouts/signup/pages/select-account-type-page.tsx
apps/ui-sharethrift/src/components/layouts/signup/pages/account-setup-page.tsx
apps/ui-sharethrift/src/components/layouts/signup/pages/profile-setup-page.tsx
apps/ui-sharethrift/src/components/layouts/signup/pages/payment-page.tsx
apps/ui-sharethrift/src/components/layouts/signup/pages/terms-page.tsx
apps/ui-sharethrift/src/components/layouts/app/app-routes.stories.tsx
apps/ui-sharethrift/src/components/layouts/signup/signup-routes.stories.tsx
apps/ui-sharethrift/src/components/layouts/app/pages/account/pages/settings/pages/settings-page.stories.tsx
apps/ui-sharethrift/src/components/layouts/app/pages/account/pages/profile/pages/profile-page.stories.tsx
apps/ui-sharethrift/src/components/layouts/app/pages/messages/pages/messages-page.stories.tsx
Optimize frontend build output via Vite build configuration and ensure architectural tests and tooling support the new structure and performance characteristics.
  • Add Vite build.rollupOptions.output.manualChunks groups to split vendor, UI, icons, GraphQL, router, and utility libraries into dedicated chunks.
  • Configure Vite build to use esbuild minification and raise the chunkSizeWarningLimit to 1000 kB.
  • Adjust frontend architecture tests to stop requiring an assets directory and to enforce kebab-case naming for .stories.tsx files, including special handling for .container stories.
  • Increase Vitest timeout for arch-unit tests to handle more expensive file analysis.
  • Update knip and lockfile to reflect dependency and tooling changes.
apps/ui-sharethrift/vite.config.ts
packages/arch-unit-tests/src/frontend-architecture.test.ts
packages/arch-unit-tests/vitest.config.ts
knip.json
pnpm-lock.yaml
Refine Apollo cache merge behavior to use a tree-shakeable lodash/merge import and add Storybook tests verifying the type policy and merge semantics.
  • Replace default lodash import with a direct lodash/merge import in the ApolloManualMergeCacheFix cache configuration and wire it into the PersonalUser.account merge policy.
  • Add multiple Storybook play-function tests that validate the PersonalUser type policy is present and that the merge function correctly handles shallow, deep, and undefined-existing/incoming scenarios without mutating inputs.
apps/ui-sharethrift/src/components/shared/apollo-manual-merge-cache-fix.ts
apps/ui-sharethrift/src/components/shared/apollo-manual-merge-cache-fix.stories.tsx
Align Storybook stories and mocks with new file layout, kebab-case naming conventions, and updated GraphQL schema expectations.
  • Rename various Storybook files to kebab-case and sometimes relocate them to top-level src (e.g., hero-section, messages, conversation-box, conversation-list, listing-banner, message-thread, settings, settings-container).
  • Adjust Storybook imports to account for new locations and to use relative paths from top-level stories into nested component directories.
  • Update some Storybook GraphQL mocks to match current schema fields (e.g., using currentUserAndCreateIfNotExists, adding userType/username fields on PersonalUser and account where required, and ensuring currentUser mocks exist for loading states).
  • Simplify some Storybook play functions to assert rendering via canvasElement truthiness rather than querying DOM roles, which is more compatible with lazy-loaded content.
apps/ui-sharethrift/src/App.container.stories.tsx
apps/ui-sharethrift/src/app.stories.tsx
apps/ui-sharethrift/src/hero-section.stories.tsx
apps/ui-sharethrift/src/messages.stories.tsx
apps/ui-sharethrift/src/conversation-box.stories.tsx
apps/ui-sharethrift/src/listing-banner.stories.tsx
apps/ui-sharethrift/src/conversation-list.stories.tsx
apps/ui-sharethrift/src/message-thread.stories.tsx
apps/ui-sharethrift/src/settings.stories.tsx
apps/ui-sharethrift/src/settings-container.stories.tsx
apps/ui-sharethrift/src/components/layouts/app/pages/view-listing/components/view-listing.container.stories.tsx
apps/ui-sharethrift/src/components/layouts/app/pages/view-listing/pages/view-listing-page.stories.tsx
apps/ui-sharethrift/src/components/layouts/app/pages/my-reservations/components/reservations-view-active.container.stories.tsx
apps/ui-sharethrift/src/components/layouts/app/pages/messages/components/view-listing.container.stories.tsx
apps/ui-sharethrift/src/components/layouts/app/pages/messages/pages/category-filter.stories.tsx
apps/ui-sharethrift/src/components/layouts/signup/pages/account-setup-page.stories.tsx
apps/ui-sharethrift/src/components/layouts/signup/pages/payment-page.stories.tsx
apps/ui-sharethrift/src/components/layouts/signup/pages/profile-setup-page.stories.tsx
apps/ui-sharethrift/src/components/layouts/signup/pages/select-account-type-page.stories.tsx
apps/ui-sharethrift/src/components/layouts/signup/pages/terms-page.stories.tsx
Perform minor supporting updates to core app wiring and GraphQL server dependency versioning to align with the new structure.
  • Rename core app container and story entrypoints to kebab-case (App.container.tsx → app.container.tsx) and update imports accordingly.
  • Update @apollo/server in the GraphQL package to 5.4.0 to keep server-side dependencies current.
  • Keep main.tsx and other entrypoints wired to the renamed app files (diff not shown in detail).
apps/ui-sharethrift/src/App.container.tsx
apps/ui-sharethrift/src/main.tsx
packages/sthrift/graphql/package.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

…ility

Git was tracking App.tsx (uppercase) while the filesystem had app.tsx (lowercase).
This works on macOS but fails on Linux CI runners. Proper git mv ensures both
Git index and filesystem use lowercase naming consistently.
The import statement was missing the file extension, causing Vitest browser
tests to fail with "Failed to fetch dynamically imported module" error in CI.
Adding the extension fixes module resolution in browser context.
Add configuration to handle flaky browser test failures:
- Increase Playwright action timeout from 30s to 60s in CI
- Add maxConcurrency limit of 5 tests in CI to prevent overwhelming dev server
- These settings help prevent "Failed to fetch dynamically imported module" errors

The existing retry (3x) and fileParallelism (disabled) settings remain in place
to handle race conditions in Storybook + Vitest browser mode.
- Remove unused 'within' imports from story files
- Fix settings-page.stories.tsx import path
- Update play functions to check canvasElement.toBeTruthy()
- Follows removal of vi.mock('react') from vitest.setup.ts
@jasonmorais jasonmorais marked this pull request as ready for review February 5, 2026 19:44
@jasonmorais jasonmorais requested a review from a team February 5, 2026 19:44
@jasonmorais jasonmorais requested a review from nnoce14 as a code owner February 5, 2026 19:44
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • For the new Suspense wrappers in AppRoutes and SignupRoutes, consider using a shared loading component (and/or placing the Suspense boundary around the child routes rather than the entire layout) so that the main layout/Chrome remains visible while only the page content is lazily loaded.
  • In the Vite manualChunks config you group utils: ['lodash', 'dayjs', 'crypto-hash'], but the PR switches at least one usage to lodash/merge; double‑check that your chunking strategy still captures these subpath imports as intended or adjust the utilities chunk to reflect how lodash is actually being imported.
  • Several new Storybook stories for lazy routes and Suspense (AppRoutes, SignupRoutes, etc.) only assert that canvasElement is truthy; you could make these more robust by asserting on the actual fallback/content (e.g. the 'Loading...' text or a known element from the loaded page) to verify that lazy loading and Suspense behavior work as expected.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- For the new Suspense wrappers in `AppRoutes` and `SignupRoutes`, consider using a shared loading component (and/or placing the Suspense boundary around the child routes rather than the entire layout) so that the main layout/Chrome remains visible while only the page content is lazily loaded.
- In the Vite `manualChunks` config you group `utils: ['lodash', 'dayjs', 'crypto-hash']`, but the PR switches at least one usage to `lodash/merge`; double‑check that your chunking strategy still captures these subpath imports as intended or adjust the utilities chunk to reflect how lodash is actually being imported.
- Several new Storybook stories for lazy routes and Suspense (`AppRoutes`, `SignupRoutes`, etc.) only assert that `canvasElement` is truthy; you could make these more robust by asserting on the actual fallback/content (e.g. the 'Loading...' text or a known element from the loaded page) to verify that lazy loading and Suspense behavior work as expected.

## Individual Comments

### Comment 1
<location> `apps/ui-sharethrift/src/components/layouts/signup/signup-routes.stories.tsx:19` </location>
<code_context>
+
+const Template: StoryFn<typeof SignupRoutes> = () => <SignupRoutes />;
+
+export const DefaultView: StoryFn<typeof SignupRoutes> = Template.bind({});
+
+DefaultView.play = async ({ canvasElement }) => {
</code_context>

<issue_to_address>
**issue (complexity):** Consider collapsing these three nearly identical stories into a single (or at most two) stories that assert distinct observable behavior of the lazy routes and Suspense fallback.

You can reduce complexity and improve signal by collapsing these three near‑identical stories into one (or two) stories that assert actual behavior.

Right now all three `play` functions only check `expect(canvasElement).toBeTruthy()`, so they don’t differentiate:

```ts
export const DefaultView = Template.bind({});
DefaultView.play = async ({ canvasElement }) => {
  expect(canvasElement).toBeTruthy();
};

export const SuspenseFallback = Template.bind({});
SuspenseFallback.play = async ({ canvasElement }) => {
  expect(canvasElement).toBeTruthy();
};

export const LazyLoadedSignupRoutes = Template.bind({});
LazyLoadedSignupRoutes.play = async ({ canvasElement }) => {
  expect(canvasElement).toBeTruthy();
};
```

Instead, you can:

1. Keep a single “happy path” story for the lazy‑loaded routes and assert on specific UI that proves the routes and `Suspense` are wired correctly.
2. Optionally keep a dedicated fallback story **only if** you assert on the fallback content itself.

Example refactor (pseudo‑selectors — adjust to your actual UI):

```ts
import { within, waitFor } from '@storybook/test';

const Template: StoryFn<typeof SignupRoutes> = () => <SignupRoutes />;

export const SignupRoutesLazyLoaded = Template.bind({});
SignupRoutesLazyLoaded.play = async ({ canvasElement }) => {
  const canvas = within(canvasElement);

  // Assert that the Suspense fallback shows first
  await waitFor(() => {
    expect(canvas.getByText(/loading/i)).toBeInTheDocument();
  });

  // Then assert that a lazy‑loaded signup route renders
  await waitFor(() => {
    expect(canvas.getByText(/select account type/i)).toBeInTheDocument();
  });
};
```

If you truly need a separate fallback story (e.g., to document the visual state), make its assertion distinct:

```ts
export const SignupRoutesFallbackOnly = Template.bind({});
SignupRoutesFallbackOnly.play = async ({ canvasElement }) => {
  const canvas = within(canvasElement);
  expect(canvas.getByText(/loading/i)).toBeInTheDocument();
};
```

This keeps full functionality (still validating lazy routes and `Suspense`) while:

- Removing duplicate story variants that don’t add coverage.
- Making the story names and comments match observable, asserted behavior.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant