Background
The fdm-app currently performs several computationally expensive calculations, particularly for features like Norms, Balance, and Advice. These calculations are often re-run whenever relevant components render, casuing users to wait before results are in.
To improve performance and create a more responsive UI, this task proposes implementing a client-side caching layer. This will store the results of expensive calculations in the user's browser, allowing the data to be reused across different parts of the application without repeating the computation.
What This Solves
- Performance: Reduces the time it takes to display pages that rely on calculated data.
- User Experience: Creates a faster, smoother, and more responsive UI.
- Reusability: Allows the calculated output to be easily consumed by multiple components without triggering recalculations.
Implementation Plan
1. Add Dependency to fdm-app
- Add the
object-hash library to fdm-app/package.json. This will be used to create reliable hashes of input data for cache invalidation.
2. Create the Calculation Cache Store
- Create a new file at
fdm-app/app/store/calculations.ts.
- In this file, define a new
zustand store that will manage the cached data.
- Use the
persist middleware from zustand/middleware to save the store's state to localStorage.
3. Configure Cache Persistence and Versioning
- Configure the
persist middleware with a static name (e.g., calculations).
- Implement automatic cache invalidation on application updates by passing the app's version from
fdm-app/package.json to the version option of the middleware.
- This requires updating
fdm-app/vite.config.ts to read the package.json version and expose it as a global variable (e.g., __APP_VERSION__).
4. Implement Cache Logic
-
The store's state will hold the results for norms, balance, and advice.
-
Each cached item will store the data and a hash of the inputs that generated it.
-
Create getter functions (e.g., getNorms) that contain the core caching logic:
- Generate a hash of the current input data using
object-hash.
- Compare this new hash to the one stored in the cache.
- Cache Hit: If hashes match, return the cached data.
- Cache Miss: If hashes do not match, perform the calculation, store the new result and hash, and then return the new data.
5. Implement Cache Invalidation
6. Refactor fdm-app Routes and Components
- Identify and refactor the primary routes and components responsible for the calculations.
- For Norms: The main target for refactoring is the
fdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsx route and its associated components, such as fdm-app/app/components/blocks/norms/farm-norms.tsx and fdm-app/app/components/blocks/norms/field-norms.tsx.
- For Balance and Advice: Locate the equivalent routes and components for these features and apply the same refactoring pattern.
- The refactoring will involve replacing direct calls to calculation functions with asynchronous calls to the new
zustand store's getter methods.
Background
The fdm-app currently performs several computationally expensive calculations, particularly for features like Norms, Balance, and Advice. These calculations are often re-run whenever relevant components render, casuing users to wait before results are in.
To improve performance and create a more responsive UI, this task proposes implementing a client-side caching layer. This will store the results of expensive calculations in the user's browser, allowing the data to be reused across different parts of the application without repeating the computation.
What This Solves
Implementation Plan
1. Add Dependency to
fdm-appobject-hashlibrary tofdm-app/package.json. This will be used to create reliable hashes of input data for cache invalidation.2. Create the Calculation Cache Store
fdm-app/app/store/calculations.ts.zustandstore that will manage the cached data.persistmiddleware fromzustand/middlewareto save the store's state tolocalStorage.3. Configure Cache Persistence and Versioning
persistmiddleware with a staticname(e.g.,calculations).fdm-app/package.jsonto theversionoption of the middleware.fdm-app/vite.config.tsto read thepackage.jsonversion and expose it as a global variable (e.g.,__APP_VERSION__).4. Implement Cache Logic
The store's state will hold the results for
norms,balance, andadvice.Each cached item will store the
dataand ahashof the inputs that generated it.Create getter functions (e.g.,
getNorms) that contain the core caching logic:object-hash.5. Implement Cache Invalidation
The cache must be invalidated under three conditions:
versionmiddleware option.clearCacheaction to the store. This action must be called from the application's logout logic to clear all data from the previous session.6. Refactor
fdm-appRoutes and Componentsfdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsxroute and its associated components, such asfdm-app/app/components/blocks/norms/farm-norms.tsxandfdm-app/app/components/blocks/norms/field-norms.tsx.zustandstore's getter methods.