-
Notifications
You must be signed in to change notification settings - Fork 45
feat: POC - Add local evaluation (rules engine) for SSR with lazy loading #370
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
talissoncosta
wants to merge
8
commits into
main
Choose a base branch
from
feat/local-evaluation-engine
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+3,884
−67
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- Add crypto-js@^4.2.0 for isomorphic MD5 hashing - Add @types/crypto-js for TypeScript support - Add @rollup/plugin-json for bundling JSON imports These dependencies enable local flag evaluation with browser-compatible cryptographic operations required by the rules engine.
Add evaluation engine copied from flagsmith-nodejs with modifications for browser compatibility: - ES5-compatible hashing (BigInt → parseInt with 52-bit truncation) - ES5-compatible array operations (spread → manual loops) - Isomorphic crypto polyfills using crypto-js - Native crypto.randomUUID() with Math.random() fallback The engine enables local flag evaluation without API calls, supporting: - Segment rule evaluation (ALL, ANY, NONE) - Trait matching operators (EQUAL, REGEX, MODULO, etc.) - Multivariate flags with percentage splits - Identity-based targeting Engine structure: - /environments - Environment model builders - /evaluation - Core evaluation logic - /features - Feature state models - /identities - Identity and trait models - /segments - Segment evaluation - /utils - Crypto polyfills, hashing, collections
Add utilities to convert between API and engine formats: - buildEvaluationContextFromDocument() - Converts API JSON to engine context - mapEngineResultToSDKFlags() - Converts engine results to SDK format Handles: - Identity and trait mapping - Environment model building - Flag result transformation
Add new init config options: - serverAPIKey - Server-side API key for auto-fetching environment document - enableLocalEvaluation - Enable local evaluation mode - environmentDocument - Preloaded environment document (optimal for SSR) Add internal properties to IFlagsmith interface: - useLocalEvaluation - Track if local evaluation is enabled - environmentDocument - Store loaded environment document - flags - Internal flags storage
Integrate local evaluation with lazy loading to avoid cold start penalty: Changes: - Add loadEngineModules() with dynamic imports - Modify init() to lazy-load engine when enableLocalEvaluation is true - Add getLocalFlags() for local flag evaluation - Add buildEvaluationContext() to prepare engine context - Add updateEnvironmentDocument() to fetch document from API - Update getFlags() to route to local or remote evaluation Cold start optimization: - Engine modules only loaded when local evaluation is enabled - Zero overhead for users not using this feature - Addresses FoF deployment blocker for Lambda/Edge Evaluation flow: 1. Check if local evaluation enabled 2. Lazy-load engine modules if needed 3. Build evaluation context from environment document 4. Execute local evaluation via engine 5. Map engine results to SDK format
TypeScript changes (tsconfig.json): - Set target to ES5 for older browser support - Enable downlevelIteration for iterator compatibility - Allows for-of loops and Map.entries() in ES5 output Rollup changes (rollup.config.js): - Add @rollup/plugin-json for JSON imports - Set inlineDynamicImports: true to handle lazy loading - Prevents code-splitting issues with dynamic imports in UMD format
Add 8 integration tests covering: - Initialize with preloaded environment document - Evaluate flags locally without API calls - Evaluate flags for environment without identity - Handle identity context in local evaluation - Fetch environment document if not preloaded - Handle errors during local evaluation gracefully - Lazy load engine modules when enabled - Not use local evaluation when disabled Tests validate: - Zero API calls with local evaluation - Lazy loading behavior - Identity and trait mapping - Error handling and fallbacks - Remote evaluation still works when disabled
Add comprehensive documentation: LOCAL_EVALUATION.md - User-facing guide covering: - Overview and benefits - Installation and dependencies - Basic usage patterns (preloaded vs auto-fetch) - Identity-based evaluation - Next.js App Router examples - Configuration options - Troubleshooting and limitations - Migration guide - Cost savings analysis LOCAL_EVALUATION_IMPLEMENTATION.md - Technical summary covering: - Implementation approach and architecture - Key technical challenges and solutions (ES5, crypto, mapping) - Files created and modified - Usage patterns and examples - Testing strategy - Performance characteristics - Future improvements - Deployment checklist
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
Implements local evaluation using the rules engine from
flagsmith-nodejs, enabling server-side flag evaluation without per-request API calls. Addresses both Adam's SSR caching issue and Kim's cold start performance concern.Key Features
enableLocalEvaluation: true(addresses Kim's FoF deployment blocker)Changes
New Files
/flagsmith-engine/**/*- Evaluation engine (28 files, ~2,500 LOC)/utils/environment-mapper.ts- API → Engine format conversion/test/local-evaluation.test.ts- 8 integration tests/docs/LOCAL_EVALUATION.md- User documentation/docs/LOCAL_EVALUATION_IMPLEMENTATION.md- Implementation summaryModified Files
package.json- Addedcrypto-js,@types/crypto-js,@rollup/plugin-jsontsconfig.json- Addedtarget: ES5,downlevelIteration: truerollup.config.js- Added JSON plugin,inlineDynamicImports: truetypes.d.ts- Added config options (serverAPIKey,enableLocalEvaluation,environmentDocument)flagsmith-core.ts- Lazy loading + local evaluation integrationConfiguration
Option 1: Preloaded document (optimal for SSR)
Option 2: Auto-fetch document
Testing
npm run typecheckpassesnpm run buildcompletesPerformance
Why SSR Projects Can't Use flagsmith-nodejs
The Node.js SDK cannot be used in SSR because:
This PR makes the isomorphic SDK work everywhere (Node.js, browser, Edge, React Native) with local evaluation.
Next Steps
@flagsmith/enginepackageRelated Issues
Note: This is a PoC for review. The engine is currently copied locally; we can extract to a shared package in a follow-up PR based on team feedback.
Commits
The implementation is split into 8 logical conventional commits:
build: add dependencies for local evaluationfeat: add local evaluation engine with ES5 compatibilityfeat: add environment document to engine format mappersfeat: add local evaluation config typesfeat: implement lazy-loaded local evaluation in core SDKbuild: configure TypeScript and Rollup for local evaluationtest: add local evaluation integration testsdocs: add local evaluation documentation