[refactor] Replace lodash with es-toolkit (#4935)

This commit is contained in:
Christian Byrne
2025-08-12 12:22:09 -07:00
committed by GitHub
parent d068b8351e
commit c42c9315f4
52 changed files with 72 additions and 68 deletions

View File

@@ -49,7 +49,7 @@ DO NOT use deprecated PrimeVue components. Use these replacements instead:
## Development Guidelines
1. Leverage VueUse functions for performance-enhancing styles
2. Use lodash for utility functions
2. Use es-toolkit for utility functions
3. Use TypeScript for type safety
4. Implement proper props and emits definitions
5. Utilize Vue 3's Teleport component when needed

View File

@@ -18,7 +18,7 @@ Use Tailwind CSS for styling
Leverage VueUse functions for performance-enhancing styles
Use lodash for utility functions
Use es-toolkit for utility functions
Use TypeScript for type safety

View File

@@ -1,5 +1,5 @@
import _ from 'es-toolkit/compat'
import fs from 'fs'
import _ from 'lodash'
import path from 'path'
import type { Request, Route } from 'playwright'
import { v4 as uuidv4 } from 'uuid'
@@ -75,7 +75,9 @@ export default class TaskHistory {
private async handleGetView(route: Route) {
const fileName = getFilenameParam(route.request())
if (!this.outputContentTypes.has(fileName)) route.continue()
if (!this.outputContentTypes.has(fileName)) {
return route.continue()
}
const asset = this.loadAsset(fileName)
return route.fulfill({

21
package-lock.json generated
View File

@@ -30,12 +30,12 @@
"axios": "^1.8.2",
"dompurify": "^3.2.5",
"dotenv": "^16.4.5",
"es-toolkit": "^1.39.9",
"extendable-media-recorder": "^9.2.27",
"extendable-media-recorder-wav-encoder": "^7.0.129",
"firebase": "^11.6.0",
"fuse.js": "^7.0.0",
"jsondiffpatch": "^0.6.0",
"lodash": "^4.17.21",
"loglevel": "^1.9.2",
"marked": "^15.0.11",
"pinia": "^2.1.7",
@@ -62,7 +62,6 @@
"@trivago/prettier-plugin-sort-imports": "^5.2.0",
"@types/dompurify": "^3.0.5",
"@types/fs-extra": "^11.0.4",
"@types/lodash": "^4.17.6",
"@types/node": "^20.14.8",
"@types/semver": "^7.7.0",
"@types/three": "^0.169.0",
@@ -4887,12 +4886,6 @@
"integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
"license": "MIT"
},
"node_modules/@types/lodash": {
"version": "4.17.6",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.6.tgz",
"integrity": "sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA==",
"dev": true
},
"node_modules/@types/markdown-it": {
"version": "14.1.2",
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
@@ -7998,6 +7991,15 @@
"node": ">= 0.4"
}
},
"node_modules/es-toolkit": {
"version": "1.39.9",
"resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.39.9.tgz",
"integrity": "sha512-9OtbkZmTA2Qc9groyA1PUNeb6knVTkvB2RSdr/LcJXDL8IdEakaxwXLHXa7VX/Wj0GmdMJPR3WhnPGhiP3E+qg==",
"workspaces": [
"docs",
"benchmarks"
]
},
"node_modules/esbuild": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
@@ -11450,7 +11452,8 @@
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"node_modules/lodash-es": {
"version": "4.17.21",

View File

@@ -40,7 +40,6 @@
"@trivago/prettier-plugin-sort-imports": "^5.2.0",
"@types/dompurify": "^3.0.5",
"@types/fs-extra": "^11.0.4",
"@types/lodash": "^4.17.6",
"@types/node": "^20.14.8",
"@types/semver": "^7.7.0",
"@types/three": "^0.169.0",
@@ -99,12 +98,12 @@
"axios": "^1.8.2",
"dompurify": "^3.2.5",
"dotenv": "^16.4.5",
"es-toolkit": "^1.39.9",
"extendable-media-recorder": "^9.2.27",
"extendable-media-recorder-wav-encoder": "^7.0.129",
"firebase": "^11.6.0",
"fuse.js": "^7.0.0",
"jsondiffpatch": "^0.6.0",
"lodash": "^4.17.21",
"loglevel": "^1.9.2",
"marked": "^15.0.11",
"pinia": "^2.1.7",

View File

@@ -51,7 +51,7 @@ const template = await fetch('/templates/default.json')
## General Guidelines
- Use lodash for utility functions
- Use es-toolkit for utility functions
- Implement proper TypeScript types
- Follow Vue 3 composition API style guide
- Use vue-i18n for ALL user-facing strings in `src/locales/en/main.json`

View File

@@ -20,7 +20,7 @@ import {
useLocalStorage,
watchDebounced
} from '@vueuse/core'
import { clamp } from 'lodash'
import { clamp } from 'es-toolkit/compat'
import Panel from 'primevue/panel'
import { Ref, computed, inject, nextTick, onMounted, ref, watch } from 'vue'

View File

@@ -42,7 +42,7 @@
</template>
<script setup lang="ts" generic="TFilter extends SearchFilter">
import { debounce } from 'lodash'
import { debounce } from 'es-toolkit/compat'
import Button from 'primevue/button'
import IconField from 'primevue/iconfield'
import InputIcon from 'primevue/inputicon'

View File

@@ -16,7 +16,7 @@
<script setup lang="ts" generic="T">
import { useElementSize, useScroll, whenever } from '@vueuse/core'
import { clamp, debounce } from 'lodash'
import { clamp, debounce } from 'es-toolkit/compat'
import { type CSSProperties, computed, onBeforeUnmount, ref, watch } from 'vue'
type GridState = {

View File

@@ -169,8 +169,8 @@ import { Form, FormField, type FormSubmitEvent } from '@primevue/forms'
import { zodResolver } from '@primevue/forms/resolvers/zod'
import type { CaptureContext, User } from '@sentry/core'
import { captureMessage } from '@sentry/core'
import _ from 'lodash'
import cloneDeep from 'lodash/cloneDeep'
import _ from 'es-toolkit/compat'
import { cloneDeep } from 'es-toolkit/compat'
import Button from 'primevue/button'
import Checkbox from 'primevue/checkbox'
import Dropdown from 'primevue/dropdown'

View File

@@ -93,7 +93,7 @@
<script setup lang="ts">
import { whenever } from '@vueuse/core'
import { merge } from 'lodash'
import { merge } from 'es-toolkit/compat'
import Button from 'primevue/button'
import {
computed,

View File

@@ -12,7 +12,7 @@ import { useComfyManagerStore } from '@/stores/comfyManagerStore'
import PackEnableToggle from './PackEnableToggle.vue'
// Mock debounce to execute immediately
vi.mock('lodash', () => ({
vi.mock('es-toolkit/compat', () => ({
debounce: <T extends (...args: any[]) => any>(fn: T) => fn
}))

View File

@@ -10,7 +10,7 @@
</template>
<script setup lang="ts">
import { debounce } from 'lodash'
import { debounce } from 'es-toolkit/compat'
import ToggleSwitch from 'primevue/toggleswitch'
import { computed, ref } from 'vue'

View File

@@ -57,7 +57,7 @@
</template>
<script setup lang="ts">
import { stubTrue } from 'lodash'
import { stubTrue } from 'es-toolkit/compat'
import AutoComplete, {
AutoCompleteOptionSelectEvent
} from 'primevue/autocomplete'

View File

@@ -82,7 +82,7 @@ https://github.com/Nuked88/ComfyUI-N-Sidebar/blob/7ae7da4a9761009fb6629bc04c6830
</template>
<script setup lang="ts">
import _ from 'lodash'
import _ from 'es-toolkit/compat'
import { computed } from 'vue'
import type { ComfyNodeDef as ComfyNodeDefV2 } from '@/schemas/nodeDef/nodeDefSchemaV2'

View File

@@ -1,7 +1,7 @@
import { FitAddon } from '@xterm/addon-fit'
import { Terminal } from '@xterm/xterm'
import '@xterm/xterm/css/xterm.css'
import { debounce } from 'lodash'
import { debounce } from 'es-toolkit/compat'
import { Ref, markRaw, onMounted, onUnmounted } from 'vue'
export function useTerminal(element: Ref<HTMLElement | undefined>) {

View File

@@ -1,5 +1,5 @@
import { useMutationObserver, useResizeObserver } from '@vueuse/core'
import { debounce } from 'lodash'
import { debounce } from 'es-toolkit/compat'
import { readonly, ref } from 'vue'
/**

View File

@@ -1,4 +1,4 @@
import _ from 'lodash'
import _ from 'es-toolkit/compat'
import { computed, onMounted, watch } from 'vue'
import { useNodePricing } from '@/composables/node/useNodePricing'

View File

@@ -1,4 +1,4 @@
import { groupBy } from 'lodash'
import { groupBy } from 'es-toolkit/compat'
import { computed, onMounted } from 'vue'
import { useWorkflowPacks } from '@/composables/nodePack/useWorkflowPacks'

View File

@@ -1,5 +1,5 @@
import { watchDebounced } from '@vueuse/core'
import { orderBy } from 'lodash'
import { orderBy } from 'es-toolkit/compat'
import { computed, ref, watch } from 'vue'
import { DEFAULT_PAGE_SIZE } from '@/constants/searchConstants'

View File

@@ -1,4 +1,4 @@
import _ from 'lodash'
import _ from 'es-toolkit/compat'
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
import type { INumericWidget } from '@/lib/litegraph/src/types/widgets'

View File

@@ -1,5 +1,5 @@
import { debounce } from 'lodash'
import _ from 'lodash'
import { debounce } from 'es-toolkit/compat'
import _ from 'es-toolkit/compat'
import { t } from '@/i18n'

View File

@@ -1,4 +1,4 @@
import { clamp } from 'lodash'
import { clamp } from 'es-toolkit/compat'
import type { Point, Rect } from './interfaces'
import { LGraphCanvas } from './litegraph'

View File

@@ -1,4 +1,4 @@
import { toString } from 'lodash'
import { toString } from 'es-toolkit/compat'
import {
SUBGRAPH_INPUT_ID,

View File

@@ -1,4 +1,4 @@
import { toString } from 'lodash'
import { toString } from 'es-toolkit/compat'
import { LinkConnector } from '@/lib/litegraph/src/canvas/LinkConnector'

View File

@@ -1,4 +1,4 @@
import { clamp } from 'lodash'
import { clamp } from 'es-toolkit/compat'
import type {
ReadOnlyRect,

View File

@@ -1,4 +1,4 @@
import { pull } from 'lodash'
import { pull } from 'es-toolkit/compat'
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
import { LLink } from '@/lib/litegraph/src/LLink'

View File

@@ -1,4 +1,4 @@
import { clamp } from 'lodash'
import { clamp } from 'es-toolkit/compat'
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
import { LiteGraph } from '@/lib/litegraph/src/litegraph'

View File

@@ -1,4 +1,4 @@
import { clamp } from 'lodash'
import { clamp } from 'es-toolkit/compat'
import type { IKnobWidget } from '@/lib/litegraph/src/types/widgets'
import { getWidgetStep } from '@/lib/litegraph/src/utils/widget'

View File

@@ -1,4 +1,4 @@
import { clamp } from 'lodash'
import { clamp } from 'es-toolkit/compat'
import type { ISliderWidget } from '@/lib/litegraph/src/types/widgets'

View File

@@ -1,4 +1,4 @@
import { clamp } from 'lodash'
import { clamp } from 'es-toolkit/compat'
import { beforeEach, describe, expect, vi } from 'vitest'
import { LiteGraphGlobal } from '@/lib/litegraph/src/LiteGraphGlobal'

View File

@@ -1,4 +1,4 @@
import _ from 'lodash'
import _ from 'es-toolkit/compat'
import type { ToastMessageOptions } from 'primevue/toast'
import { reactive } from 'vue'

View File

@@ -1,5 +1,5 @@
import _ from 'es-toolkit/compat'
import * as jsondiffpatch from 'jsondiffpatch'
import _ from 'lodash'
import log from 'loglevel'
import { LGraphCanvas, LiteGraph } from '@/lib/litegraph/src/litegraph'

View File

@@ -1,4 +1,4 @@
import _ from 'lodash'
import _ from 'es-toolkit/compat'
import { type Component, toRaw } from 'vue'
import { useChainCallback } from '@/composables/functional/useChainCallback'

View File

@@ -1,4 +1,4 @@
import _ from 'lodash'
import _ from 'es-toolkit/compat'
import {
type INodeOutputSlot,

View File

@@ -1,4 +1,4 @@
import _ from 'lodash'
import _ from 'es-toolkit/compat'
import { useNodeAnimatedImage } from '@/composables/node/useNodeAnimatedImage'
import { useNodeCanvasImagePreview } from '@/composables/node/useNodeCanvasImagePreview'

View File

@@ -4,7 +4,7 @@ import type {
SearchResponse
} from 'algoliasearch/dist/lite/browser'
import { liteClient as algoliasearch } from 'algoliasearch/dist/lite/builds/browser'
import { memoize, omit } from 'lodash'
import { memoize, omit } from 'es-toolkit/compat'
import {
MIN_CHARS_FOR_SUGGESTIONS_ALGOLIA,

View File

@@ -1,5 +1,5 @@
import QuickLRU from '@alloc/quick-lru'
import { partition } from 'lodash'
import { partition } from 'es-toolkit/compat'
import { defineStore } from 'pinia'
import { useCachedRequest } from '@/composables/useCachedRequest'

View File

@@ -1,6 +1,6 @@
// We should consider moving to https://primevue.org/dynamicdialog/ once everything is in Vue.
// Currently we need to bridge between legacy app code and Vue app with a Pinia store.
import { merge } from 'lodash'
import { merge } from 'es-toolkit/compat'
import { defineStore } from 'pinia'
import type { DialogPassThroughOptions } from 'primevue/dialog'
import { type Component, markRaw, ref } from 'vue'

View File

@@ -1,4 +1,4 @@
import _ from 'lodash'
import _ from 'es-toolkit/compat'
import { defineStore } from 'pinia'
import { Ref, computed, ref, toRaw } from 'vue'

View File

@@ -1,4 +1,4 @@
import _ from 'lodash'
import _ from 'es-toolkit/compat'
import { defineStore } from 'pinia'
import { computed } from 'vue'

View File

@@ -1,5 +1,5 @@
import axios from 'axios'
import _ from 'lodash'
import _ from 'es-toolkit/compat'
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'

View File

@@ -1,4 +1,4 @@
import _ from 'lodash'
import _ from 'es-toolkit/compat'
import { defineStore } from 'pinia'
import { computed, ref, toRaw } from 'vue'

View File

@@ -1,4 +1,4 @@
import _ from 'lodash'
import _ from 'es-toolkit/compat'
import { defineStore } from 'pinia'
import { ref } from 'vue'

View File

@@ -1,4 +1,4 @@
import _ from 'lodash'
import _ from 'es-toolkit/compat'
import { defineStore } from 'pinia'
import { type Raw, computed, markRaw, ref, shallowRef, watch } from 'vue'

View File

@@ -1,4 +1,4 @@
import { groupBy } from 'lodash'
import { groupBy } from 'es-toolkit/compat'
import { defineStore } from 'pinia'
import { computed, ref, shallowRef } from 'vue'

View File

@@ -1,4 +1,4 @@
import { memoize } from 'lodash'
import { memoize } from 'es-toolkit/compat'
type RGB = { r: number; g: number; b: number }
type HSL = { h: number; s: number; l: number }

View File

@@ -1,4 +1,4 @@
import _ from 'lodash'
import _ from 'es-toolkit/compat'
import { ColorOption, LGraph, Reroute } from '@/lib/litegraph/src/litegraph'
import {

View File

@@ -1,4 +1,4 @@
import _ from 'lodash'
import _ from 'es-toolkit/compat'
import type {
ComfyLinkObject,

View File

@@ -1,4 +1,4 @@
import _ from 'lodash'
import _ from 'es-toolkit/compat'
import type {
ComboInputSpec,

View File

@@ -15,7 +15,7 @@ interface ColorTestCase {
type ColorFormat = 'hex' | 'rgb' | 'rgba' | 'hsl' | 'hsla'
vi.mock('lodash', () => ({
vi.mock('es-toolkit/compat', () => ({
memoize: (fn: any) => fn
}))

View File

@@ -8,7 +8,7 @@ This guide covers patterns and examples for unit testing utilities, composables,
2. [Working with LiteGraph and Nodes](#working-with-litegraph-and-nodes)
3. [Working with Workflow JSON Files](#working-with-workflow-json-files)
4. [Mocking the API Object](#mocking-the-api-object)
5. [Mocking Lodash Functions](#mocking-lodash-functions)
5. [Mocking Utility Functions](#mocking-utility-functions)
6. [Testing with Debounce and Throttle](#testing-with-debounce-and-throttle)
7. [Mocking Node Definitions](#mocking-node-definitions)
@@ -147,17 +147,17 @@ it('should subscribe to logs API', () => {
## Mocking Lodash Functions
Mocking lodash functions like debounce:
Mocking utility functions like debounce:
```typescript
// Mock debounce to execute immediately
import { debounce } from 'lodash-es'
import { debounce } from 'es-toolkit/compat'
vi.mock('lodash-es', () => ({
vi.mock('es-toolkit/compat', () => ({
debounce: vi.fn((fn) => {
// Return function that calls the input function immediately
const mockDebounced = (...args: any[]) => fn(...args)
// Add cancel method that lodash debounced functions have
// Add cancel method that debounced functions have
mockDebounced.cancel = vi.fn()
return mockDebounced
})