Skip to content

feat(web): migrate from es-toolkit/compat to native es-toolkit (#30244)#30246

Merged
crazywoola merged 4 commits intomainfrom
feat/migrate-es-toolkit-compat-simple
Dec 31, 2025
Merged

feat(web): migrate from es-toolkit/compat to native es-toolkit (#30244)#30246
crazywoola merged 4 commits intomainfrom
feat/migrate-es-toolkit-compat-simple

Conversation

@lyzno1
Copy link
Member

@lyzno1 lyzno1 commented Dec 27, 2025

Migrate some files from es-toolkit/compat to native es-toolkit.

Migrated:

  • noop → es-toolkit/function
  • cloneDeep, omit, clone, pick → es-toolkit/object
  • uniq, intersection → es-toolkit/array
  • capitalize, camelCase, kebabCase, escape → es-toolkit/string
  • isEqual → es-toolkit/predicate

Kept in compat (API differences):

  • uniqueId, isEmpty
  • get, merge, flow, curry, debounce - different APIs
  • uniqBy, groupBy, intersectionBy - property string support
  • flatten - undefined handling

Benefits: 2-3x faster, smaller bundle

Another:

  • Remove lodash dependency in web/

Part of #30243
Fixes #30244

Migrate 172 files from es-toolkit/compat to native es-toolkit. Migrated: - noop → es-toolkit/function - cloneDeep, omit, clone, pick → es-toolkit/object - uniq, intersection → es-toolkit/array - capitalize, camelCase, kebabCase, escape → es-toolkit/string - isEqual → es-toolkit/predicate Kept in compat (API differences): - uniqueId, isEmpty - get, merge, flow, curry, debounce - different APIs - uniqBy, groupBy, intersectionBy - property string support - flatten - undefined handling Benefits: 2-3x faster, smaller bundle Part of #30243 Fixes #30244
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @lyzno1, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request focuses on enhancing the application's performance and optimizing its bundle size by migrating a large number of utility function imports from the compatibility layer of es-toolkit to its native, more efficient modules. This targeted refactoring ensures that commonly used functions benefit from direct imports, while a careful approach was taken to preserve functionality for utilities with differing APIs.

Highlights

  • Migration to Native es-toolkit: The pull request initiates a significant migration from the es-toolkit/compat module to more specific, native es-toolkit modules. This involves updating import paths for various utility functions across the codebase.
  • Performance and Bundle Size Improvements: By leveraging native es-toolkit modules, this migration is projected to yield substantial benefits, including a 2-3x increase in performance and a reduction in the overall bundle size, optimizing application loading and execution.
  • Strategic Partial Migration: Not all es-toolkit functions were migrated. Functions with known API differences or complex usage patterns, such as uniqueId, isEmpty, get, merge, flow, curry, debounce, uniqBy, intersectionBy, flatten, xorBy, isArray, and unionBy, were intentionally retained from es-toolkit/compat to ensure stability and prevent breaking changes.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request correctly migrates many utility functions from es-toolkit/compat to their native es-toolkit modules, which should improve performance and reduce bundle size. The changes are extensive and mostly correct. I've found a few places where some functions that could be migrated were left in es-toolkit/compat. Overall, great work on this large refactoring task.

@diffray-bot
Copy link

Changes Summary

This PR performs a systematic migration of 150+ files in the web frontend from using es-toolkit/compat imports to native es-toolkit submodule imports. Functions like noop, cloneDeep, clone, pick, omit, uniq, intersection, capitalize, camelCase, kebabCase, escape, and isEqual are moved to their respective native submodules, while keeping functions with different APIs (uniqueId, isEmpty, get, merge, etc.) in compat. This improves performance by 2-3x and reduces bundle size.

Type: refactoring

Components Affected: web/components - across modal, chat, configuration, datasets, workflow, plugins, web/app - authentication, account settings, app management pages, web/context - provider contexts, web/mocks - test mocks

Files Changed
File Summary Change Impact
/tmp/workspace/web/__mocks__/provider-context.ts Migrate noop from es-toolkit/compat to es-toolkit/function ✏️ 🟢
...pId]/overview/time-range-picker/date-picker.tsx Migrate noop import ✏️ 🟢
...rkspace/web/app/components/base/modal/modal.tsx Migrate noop import ✏️ 🟢
...pace/web/app/components/base/chat/chat/hooks.ts Migrate utility imports (likely noop or string functions) ✏️ 🟢
...ow/run/utils/format-log/iteration/index.spec.ts Test file - utility function import migration ✏️ 🟢
Architecture Impact
  • Dependencies: Migrated from es-toolkit/compat to es-toolkit submodules: function, object, array, string, predicate, No new dependencies added, no existing dependencies removed

Risk Areas: Large-scale import refactoring across 150+ files - risk of merge conflicts in concurrent PRs, Import path changes could break if someone has custom es-toolkit wrapper imports, Need to verify es-toolkit/array, es-toolkit/function, es-toolkit/string, es-toolkit/object, es-toolkit/predicate exports exist and match expected APIs

Suggestions
  • Verify that all migrated functions have identical behavior to their es-toolkit/compat counterparts (especially edge cases for cloneDeep, pick, omit, etc.)
  • Ensure bundle size reduction is actually achieved by comparing bundle size before/after
  • Consider adding an ESLint rule to prevent future accidental imports from es-toolkit/compat for the migrated functions
  • Test in all affected components, particularly: modals, chat features, workflow visualization, dataset configuration, and authentication flows

Full review in progress... | Powered by diffray

@diffray-bot
Copy link

Review Summary

Free public review - Want AI code reviews on your PRs? Check out diffray.ai

Validated 12 issues: 7 kept (context assertion, any types, type assertions), 5 filtered (false positives, low-value quality concerns)

Issues Found: 7

💬 See 1 individual line comment(s) for details.

📊 4 unique issue type(s) across 7 location(s)

📋 Full issue list (click to expand)

🟠 HIGH - Non-null assertion on context without validation

Agent: typescript

Category: bug

File: web/app/components/workflow/hooks-store/store.ts:166-168

Description: The 'useHooksStoreApi' function uses '!' assertion without null check. The sibling function 'useHooksStore' (lines 158-164) properly throws an error when context is missing, but this function does not.

Suggestion: Add a runtime check like in useHooksStore: 'const store = useContext(HooksStoreContext); if (!store) throw new Error("Missing HooksStoreContext.Provider in the tree"); return store'

Confidence: 85%

Rule: ts_non_null_assertion


🟡 MEDIUM - Multiple 'as any' assertions for accessing model data (2 occurrences)

Agent: typescript

Category: quality

📍 View all locations
File Description Suggestion Confidence
web/app/components/workflow/utils/workflow-init.ts:272-283 The code uses multiple 'as any' type assertions to access deeply nested properties for LLM, Knowledg... Define proper TypeScript interfaces for each node type with their data structure, then use proper ty... 75%
web/app/components/workflow/utils/workflow-init.ts:338-357 Multiple locations cast edge.data to 'any' to add properties without proper type definition. Define a proper TypeScript interface for edge data structure that includes all needed properties 65%

Rule: ts_type_assertion_abuse


🟡 MEDIUM - Record type with 'any' generic parameter (3 occurrences)

Agent: typescript

Category: quality

📍 View all locations
File Description Suggestion Confidence
web/app/components/workflow/hooks-store/store.ts:16 The type uses 'Record<BlockEnum, NodeDefault>' which includes 'any' as a generic parameter, byp... Replace 'any' with 'unknown' or a specific union type for node data 65%
web/app/components/workflow/hooks-store/store.ts:38 The function 'handleRestoreFromPublishedWorkflow: (...args: any[]) => void' uses 'any[]' for paramet... Define specific parameter types or use 'unknown[]' with runtime type validation 70%
web/app/components/workflow/hooks-store/store.ts:56 The function 'editInspectVarValue' accepts 'value' as 'any', which loses type safety for the value b... Replace 'value: any' with 'value: unknown' and add type validation, or define a specific union type 65%

Rule: ts_any_type_usage


🟡 MEDIUM - Potential null/undefined access on ctx.plan property

Agent: typescript

Category: bug

File: web/__mocks__/provider-context.ts:58-80

Description: In 'createMockPlanUsage', 'createMockPlanTotal', and 'createMockPlanReset' functions, 'ctx.plan' is passed to merge() without verification. Since ctx is Partial, ctx.plan could be undefined.

Suggestion: Add null coalescing: 'merge(ctx.plan ?? defaultPlan, { ... })' to ensure a valid base object

Confidence: 70%

Rule: ts_strict_null_checks


ℹ️ 6 issue(s) outside PR diff (click to expand)

These issues were found in lines not modified in this PR.

🟠 HIGH - Non-null assertion on context without validation

Agent: typescript

Category: bug

File: web/app/components/workflow/hooks-store/store.ts:166-168

Description: The 'useHooksStoreApi' function uses '!' assertion without null check. The sibling function 'useHooksStore' (lines 158-164) properly throws an error when context is missing, but this function does not.

Suggestion: Add a runtime check like in useHooksStore: 'const store = useContext(HooksStoreContext); if (!store) throw new Error("Missing HooksStoreContext.Provider in the tree"); return store'

Confidence: 85%

Rule: ts_non_null_assertion


🟡 MEDIUM - Multiple 'as any' assertions for accessing model data (2 occurrences)

Agent: typescript

Category: quality

📍 View all locations
File Description Suggestion Confidence
web/app/components/workflow/utils/workflow-init.ts:272-283 The code uses multiple 'as any' type assertions to access deeply nested properties for LLM, Knowledg... Define proper TypeScript interfaces for each node type with their data structure, then use proper ty... 75%
web/app/components/workflow/utils/workflow-init.ts:338-357 Multiple locations cast edge.data to 'any' to add properties without proper type definition. Define a proper TypeScript interface for edge data structure that includes all needed properties 65%

Rule: ts_type_assertion_abuse


🟡 MEDIUM - 'any' type parameter in function signature (2 occurrences)

Agent: typescript

Category: quality

📍 View all locations
File Description Suggestion Confidence
web/app/components/workflow/hooks-store/store.ts:38 The function 'handleRestoreFromPublishedWorkflow: (...args: any[]) => void' uses 'any[]' for paramet... Define specific parameter types or use 'unknown[]' with runtime type validation 70%
web/app/components/workflow/hooks-store/store.ts:56 The function 'editInspectVarValue' accepts 'value' as 'any', which loses type safety for the value b... Replace 'value: any' with 'value: unknown' and add type validation, or define a specific union type 65%

Rule: ts_any_type_usage


🟡 MEDIUM - Potential null/undefined access on ctx.plan property

Agent: typescript

Category: bug

File: web/__mocks__/provider-context.ts:58-80

Description: In 'createMockPlanUsage', 'createMockPlanTotal', and 'createMockPlanReset' functions, 'ctx.plan' is passed to merge() without verification. Since ctx is Partial, ctx.plan could be undefined.

Suggestion: Add null coalescing: 'merge(ctx.plan ?? defaultPlan, { ... })' to ensure a valid base object

Confidence: 70%

Rule: ts_strict_null_checks



Review ID: e85eb158-fa41-4575-91d0-b32b7400196b
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

@lyzno1 lyzno1 marked this pull request as ready for review December 29, 2025 04:09
Copilot AI review requested due to automatic review settings December 29, 2025 04:09
@dosubot dosubot bot added size:M This PR changes 30-99 lines, ignoring generated files. 💪 enhancement New feature or request labels Dec 29, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR migrates utility functions from es-toolkit/compat to native es-toolkit for improved performance (2-3x faster) and smaller bundle size. The migration strategically moves functions with compatible APIs to their respective native submodules while keeping functions with API differences in compat.

  • Migrated functions to native submodules: noop → function, cloneDeep/omit/clone/pick → object, uniq/intersection → array, capitalize/camelCase/kebabCase/escape → string, isEqual → predicate
  • Functions intentionally kept in compat: uniqueId, isEmpty, get, merge, flow, curry, debounce, uniqBy, groupBy, intersectionBy, flatten, xorBy, unionBy, isArray
  • Import statements properly separated when files use both compat and native functions

Reviewed changes

Copilot reviewed 159 out of 159 changed files in this pull request and generated no comments.

Show a summary per file
File Description
web/utils/index.ts Migrated escape from compat to string submodule
web/service/use-plugins.ts Migrated cloneDeep from compat to object submodule
web/i18n-config/i18next-config.ts Migrated camelCase and kebabCase from compat to string submodule
web/context/*.tsx Migrated noop from compat to function submodule across multiple context files
web/app/components/workflow/utils/*.ts Migrated cloneDeep from compat to object submodule for workflow utilities
web/app/components/workflow/run/utils/format-log/*.ts Migrated noop and cloneDeep from compat to their respective submodules
web/app/components/workflow/panel/**/*.tsx Migrated capitalize, noop from compat to their respective submodules, kept debounce in compat
web/app/components/workflow/nodes/**/*.tsx Migrated capitalize, noop from compat to their respective submodules across node components
web/app/components/workflow/nodes/knowledge-retrieval/*.ts Migrated uniq to array submodule, isEqual to predicate submodule, kept xorBy in compat
web/app/components/workflow/nodes/_base/components/*.tsx Migrated intersection, isEqual, noop, capitalize to their respective submodules
web/app/components/workflow/nodes/_base/components/variable/utils.ts Migrated uniq to array, kept isArray in compat
web/app/components/workflow/index.tsx Migrated isEqual from compat to predicate submodule
web/app/components/workflow/hooks/*.ts Migrated cloneDeep from compat to object submodule
web/app/components/workflow/custom-edge.tsx Migrated intersection from compat to array submodule
web/app/components/workflow/block-selector/market-place-plugin/list.tsx Migrated noop from compat to function submodule
web/app/components/plugins/**/*.tsx Migrated noop, camelCase, capitalize, isEqual to their respective submodules, kept debounce in compat
web/app/components/datasets/**/*.tsx Migrated noop to function submodule, pick/uniq to their respective submodules
web/app/components/base/**/*.tsx Migrated noop to function submodule, escape to string submodule across base components
web/app/components/base/agent-log-modal/detail.tsx Migrated uniq to array submodule, kept flatten in compat
web/app/components/base/chat/**/*.tsx Migrated noop to function submodule, kept uniqBy and debounce in compat
web/app/components/base/file-uploader/*.tsx Migrated isEqual to predicate submodule, noop to function submodule
web/app/components/app/log/*.tsx Migrated omit to object submodule, noop to function submodule, kept get in compat
web/app/components/app/configuration/**/*.tsx Migrated clone to object submodule, isEqual to predicate submodule, noop to function submodule
web/app/signin/**/*.tsx Migrated noop from compat to function submodule
web/app/signup/components/input-mail.tsx Migrated noop from compat to function submodule
web/mocks/provider-context.ts Migrated noop to function submodule, kept merge in compat

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@lyzno1
Copy link
Member Author

lyzno1 commented Dec 29, 2025

@copilot remove devDependencies: "lodash": "^4.17.21", commit and push in this branch, remember update pnpm-lock.yaml

Copy link
Contributor

Copilot AI commented Dec 29, 2025

@lyzno1 I've opened a new pull request, #30313, to work on those changes. Once the pull request is ready, I'll request review from you.

@lyzno1
Copy link
Member Author

lyzno1 commented Dec 29, 2025

@copilot resolve conflicts

Copy link
Contributor

Copilot AI commented Dec 29, 2025

@lyzno1 I've opened a new pull request, #30315, to work on those changes. Once the pull request is ready, I'll request review from you.

@dosubot dosubot bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels Dec 29, 2025
@lyzno1 lyzno1 force-pushed the feat/migrate-es-toolkit-compat-simple branch from 193101b to f05d43d Compare December 29, 2025 07:35
@dosubot dosubot bot added size:M This PR changes 30-99 lines, ignoring generated files. and removed size:XL This PR changes 500-999 lines, ignoring generated files. labels Dec 29, 2025
crazywoola
crazywoola previously approved these changes Dec 31, 2025
@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Dec 31, 2025
@crazywoola crazywoola merged commit 2aaaa4b into main Dec 31, 2025
16 checks passed
@crazywoola crazywoola deleted the feat/migrate-es-toolkit-compat-simple branch December 31, 2025 03:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💪 enhancement New feature or request lgtm This PR has been approved by a maintainer size:M This PR changes 30-99 lines, ignoring generated files.

5 participants