Skip to content

Commit 1088126

Browse files
authored
Replace lodash with es-toolkit (#2503)
* first part of migration * second part of migration * bump up es-toolkit version * bump up `es-toolkit` version and remove `lodash` completely * update screenshot
1 parent 2b47bbe commit 1088126

File tree

81 files changed

+222
-239
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+222
-239
lines changed

eslint.config.mjs

-5
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,9 @@ const RESTRICTED_MODULES = {
3030
importNames: [ 'Popover', 'Menu', 'PinInput', 'useToast', 'Skeleton' ],
3131
message: 'Please use corresponding component or hook from ui/shared/chakra component instead',
3232
},
33-
{
34-
name: 'lodash',
35-
message: 'Please use `import [package] from \'lodash/[package]\'` instead.',
36-
},
3733
],
3834
patterns: [
3935
'icons/*',
40-
'!lodash/*',
4136
],
4237
};
4338

icons/clock-light.svg

+1-1
Loading

lib/api/useApiFetch.tsx

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { useQueryClient } from '@tanstack/react-query';
2-
import _omit from 'lodash/omit';
3-
import _pickBy from 'lodash/pickBy';
2+
import { omit, pickBy } from 'es-toolkit';
43
import React from 'react';
54

65
import type { CsrfData } from 'types/client/account';
@@ -38,7 +37,7 @@ export default function useApiFetch() {
3837
const resource: ApiResource = RESOURCES[resourceName];
3938
const url = buildUrl(resourceName, pathParams, queryParams);
4039
const withBody = isBodyAllowed(fetchParams?.method);
41-
const headers = _pickBy({
40+
const headers = pickBy({
4241
'x-endpoint': resource.endpoint && isNeedProxy() ? resource.endpoint : undefined,
4342
Authorization: resource.endpoint && resource.needAuth ? apiToken : undefined,
4443
'x-csrf-token': withBody && csrfToken ? csrfToken : undefined,
@@ -55,7 +54,7 @@ export default function useApiFetch() {
5554
// change condition here if something is changed
5655
credentials: config.features.account.isEnabled ? 'include' : 'same-origin',
5756
headers,
58-
..._omit(fetchParams, 'headers'),
57+
...(fetchParams ? omit(fetchParams, [ 'headers' ]) : {}),
5958
},
6059
{
6160
resource: resource.path,

lib/contexts/scrollDirection.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import clamp from 'lodash/clamp';
2-
import throttle from 'lodash/throttle';
1+
import { throttle, clamp } from 'es-toolkit';
32
import React from 'react';
43

54
const ScrollDirectionContext = React.createContext<'up' | 'down' | null>(null);

lib/hooks/useClientRect.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import _debounce from 'lodash/debounce';
1+
import { debounce } from 'es-toolkit';
22
import type { LegacyRef } from 'react';
33
import React from 'react';
44

@@ -19,7 +19,7 @@ export default function useClientRect<E extends Element>(): [ DOMRect | null, Le
1919
return;
2020
}
2121

22-
const resizeHandler = _debounce(() => {
22+
const resizeHandler = debounce(() => {
2323
setRect(nodeRef.current?.getBoundingClientRect() ?? null);
2424
}, 100);
2525

lib/hooks/useIsSticky.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import throttle from 'lodash/throttle';
1+
import { throttle } from 'es-toolkit';
22
import React from 'react';
33

44
export default function useIsSticky(ref: React.RefObject<HTMLDivElement>, offset = 0, isEnabled = true) {

lib/hooks/useLazyRenderedList.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import _clamp from 'lodash/clamp';
1+
import { clamp } from 'es-toolkit';
22
import React from 'react';
33
import { useInView } from 'react-intersection-observer';
44

@@ -15,7 +15,7 @@ export default function useLazyRenderedList(list: Array<unknown>, isEnabled: boo
1515

1616
React.useEffect(() => {
1717
if (inView) {
18-
setRenderedItemsNum((prev) => _clamp(prev + STEP, 0, list.length));
18+
setRenderedItemsNum((prev) => clamp(prev + STEP, 0, list.length));
1919
}
2020
}, [ inView, list.length ]);
2121

lib/mixpanel/getTabName.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import _capitalize from 'lodash/capitalize';
1+
import { capitalize } from 'es-toolkit';
22

33
export default function getTabName(tab: string) {
4-
return tab !== '' ? _capitalize(tab.replaceAll('_', ' ')) : 'Default';
4+
return tab !== '' ? capitalize(tab.replaceAll('_', ' ')) : 'Default';
55
}

lib/mixpanel/useInit.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import _capitalize from 'lodash/capitalize';
1+
import { capitalize } from 'es-toolkit';
22
import type { Config } from 'mixpanel-browser';
33
import mixpanel from 'mixpanel-browser';
44
import { useRouter } from 'next/router';
@@ -40,12 +40,12 @@ export default function useMixpanelInit() {
4040
'Viewport width': window.innerWidth,
4141
'Viewport height': window.innerHeight,
4242
Language: window.navigator.language,
43-
'Device type': _capitalize(deviceType),
43+
'Device type': capitalize(deviceType),
4444
'User id': userId,
4545
});
4646
mixpanel.identify(userId);
4747
userProfile.set({
48-
'Device Type': _capitalize(deviceType),
48+
'Device Type': capitalize(deviceType),
4949
...(isAuth ? { 'With Account': true } : {}),
5050
});
5151
userProfile.setOnce({

lib/networks/networkExplorers.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import _compose from 'lodash/fp/compose';
2-
import _mapValues from 'lodash/mapValues';
1+
import { mapValues } from 'es-toolkit';
32

43
import type { NetworkExplorer } from 'types/networks';
54

@@ -32,7 +31,7 @@ const networkExplorers: Array<NetworkExplorer> = (() => {
3231
return config.UI.explorers.items.map((explorer) => ({
3332
...explorer,
3433
baseUrl: stripTrailingSlash(explorer.baseUrl),
35-
paths: _mapValues(explorer.paths, _compose(stripTrailingSlash, addLeadingSlash)),
34+
paths: mapValues(explorer.paths, (value) => value ? stripTrailingSlash(addLeadingSlash(value)) : value),
3635
}));
3736
})();
3837

lib/recentSearchKeywords.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import _uniq from 'lodash/uniq';
1+
import { uniq } from 'es-toolkit';
22

33
import isBrowser from './isBrowser';
44

@@ -27,7 +27,7 @@ export function saveToRecentKeywords(value: string) {
2727
}
2828

2929
const keywordsArr = getRecentSearchKeywords();
30-
const result = _uniq([ value, ...keywordsArr ]).slice(0, MAX_KEYWORDS_NUMBER - 1);
30+
const result = uniq([ value, ...keywordsArr ]).slice(0, MAX_KEYWORDS_NUMBER - 1);
3131
window.localStorage.setItem(RECENT_KEYWORDS_LS_KEY, JSON.stringify(result));
3232
}
3333

lib/token/metadata/attributesParser.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import _upperFirst from 'lodash/upperFirst';
1+
import { upperFirst } from 'es-toolkit';
22

33
import type { Metadata, MetadataAttributes } from 'types/client/token';
44

@@ -72,7 +72,7 @@ export default function attributesParser(attributes: Array<unknown>): Metadata['
7272

7373
return {
7474
...formatValue(value, display, trait),
75-
trait_type: _upperFirst(trait || 'property'),
75+
trait_type: upperFirst(trait || 'property'),
7676
};
7777
})
7878
.filter((item) => item?.value)

lib/web3/useAddOrSwitchChain.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import _get from 'lodash/get';
1+
import { get } from 'es-toolkit/compat';
22
import React from 'react';
33

44
import config from 'configs/app';
@@ -25,7 +25,7 @@ export default function useAddOrSwitchChain() {
2525

2626
const errorObj = getErrorObj(error);
2727
const code = errorObj && 'code' in errorObj ? errorObj.code : undefined;
28-
const originalErrorCode = _get(errorObj, 'data.originalError.code');
28+
const originalErrorCode = get(errorObj, 'data.originalError.code');
2929

3030
// This error code indicates that the chain has not been added to Wallet.
3131
if (code === 4902 || originalErrorCode === 4902) {

mocks/blocks/epoch.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import _padStart from 'lodash/padStart';
1+
import { padStart } from 'es-toolkit/compat';
22

33
import type { BlockEpoch, BlockEpochElectionRewardDetails, BlockEpochElectionRewardDetailsResponse } from 'types/api/block';
44

@@ -42,11 +42,11 @@ function getRewardDetailsItem(index: number): BlockEpochElectionRewardDetails {
4242
amount: `${ 100 - index }210001063118670575`,
4343
account: {
4444
...addressMock.withoutName,
45-
hash: `0x30D060F129817c4DE5fBc1366d53e19f43c8c6${ _padStart(String(index), 2, '0') }`,
45+
hash: `0x30D060F129817c4DE5fBc1366d53e19f43c8c6${ padStart(String(index), 2, '0') }`,
4646
},
4747
associated_account: {
4848
...addressMock.withoutName,
49-
hash: `0x456f41406B32c45D59E539e4BBA3D7898c3584${ _padStart(String(index), 2, '0') }`,
49+
hash: `0x456f41406B32c45D59E539e4BBA3D7898c3584${ padStart(String(index), 2, '0') }`,
5050
},
5151
};
5252
}

mocks/stats/index.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import _mapValues from 'lodash/mapValues';
1+
import { mapValues } from 'es-toolkit';
22

33
import type { HomeStats } from 'types/api/stats';
44

@@ -51,17 +51,17 @@ export const withBtcLocked: HomeStats = {
5151

5252
export const withoutFiatPrices: HomeStats = {
5353
...base,
54-
gas_prices: _mapValues(base.gas_prices, (price) => price ? ({ ...price, fiat_price: null }) : null),
54+
gas_prices: base.gas_prices ? mapValues(base.gas_prices, (price) => price ? ({ ...price, fiat_price: null }) : null) : null,
5555
};
5656

5757
export const withoutGweiPrices: HomeStats = {
5858
...base,
59-
gas_prices: _mapValues(base.gas_prices, (price) => price ? ({ ...price, price: null }) : null),
59+
gas_prices: base.gas_prices ? mapValues(base.gas_prices, (price) => price ? ({ ...price, price: null }) : null) : null,
6060
};
6161

6262
export const withoutBothPrices: HomeStats = {
6363
...base,
64-
gas_prices: _mapValues(base.gas_prices, (price) => price ? ({ ...price, price: null, fiat_price: null }) : null),
64+
gas_prices: base.gas_prices ? mapValues(base.gas_prices, (price) => price ? ({ ...price, price: null, fiat_price: null }) : null) : null,
6565
};
6666

6767
export const withoutGasInfo: HomeStats = {

nextjs/csp/utils.ts

+2-12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type CspDev from 'csp-dev';
2+
import { uniq } from 'es-toolkit';
23

34
export const KEY_WORDS = {
45
BLOB: 'blob:',
@@ -11,17 +12,6 @@ export const KEY_WORDS = {
1112
UNSAFE_EVAL: '\'unsafe-eval\'',
1213
};
1314

14-
// we cannot use lodash/uniq and lodash/mergeWith in middleware code since it calls new Set() and it'is causing an error in Next.js
15-
// "Dynamic Code Evaluation (e. g. 'eval', 'new Function', 'WebAssembly.compile') not allowed in Edge Runtime"
16-
export function unique(array: Array<string | undefined>) {
17-
const set: Record<string, boolean> = {};
18-
for (const item of array) {
19-
item && (set[item] = true);
20-
}
21-
22-
return Object.keys(set);
23-
}
24-
2515
export function mergeDescriptors(...descriptors: Array<CspDev.DirectiveDescriptor>) {
2616
return descriptors.reduce((result, item) => {
2717
for (const _key in item) {
@@ -50,7 +40,7 @@ export function makePolicyString(policyDescriptor: CspDev.DirectiveDescriptor) {
5040
return;
5141
}
5242

53-
const uniqueValues = unique(value);
43+
const uniqueValues = uniq(value);
5444
return [ key, uniqueValues.join(' ') ].join(' ');
5545
})
5646
.filter(Boolean)

nextjs/utils/fetchProxy.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import { pick } from 'es-toolkit';
12
import type { IncomingMessage } from 'http';
2-
import _pick from 'lodash/pick';
33
import type { NextApiRequest } from 'next';
44
import type { NextApiRequestCookies } from 'next/dist/server/api-utils';
55
import type { RequestInit, Response } from 'node-fetch';
@@ -21,7 +21,7 @@ export default function fetchFactory(
2121
accept: _req.headers['accept'] || 'application/json',
2222
'content-type': _req.headers['content-type'] || 'application/json',
2323
cookie: apiToken ? `${ cookies.NAMES.API_TOKEN }=${ apiToken }` : '',
24-
..._pick(_req.headers, [
24+
...pick(_req.headers, [
2525
'x-csrf-token',
2626
'Authorization', // the old value, just in case
2727
'authorization', // Node.js automatically lowercases headers

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
"dappscout-iframe": "0.2.5",
8181
"dayjs": "^1.11.5",
8282
"dom-to-image": "^2.6.0",
83+
"es-toolkit": "1.31.0",
8384
"focus-visible": "^5.2.0",
8485
"framer-motion": "^6.5.1",
8586
"getit-sdk": "^1.0.4",
@@ -88,7 +89,6 @@
8889
"graphql": "^16.8.1",
8990
"graphql-ws": "^5.11.3",
9091
"js-cookie": "^3.0.1",
91-
"lodash": "^4.0.0",
9292
"magic-bytes.js": "1.8.0",
9393
"mixpanel-browser": "^2.47.0",
9494
"monaco-editor": "^0.34.1",

pages/api/proxy.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import _pick from 'lodash/pick';
2-
import _pickBy from 'lodash/pickBy';
1+
import { pick, pickBy } from 'es-toolkit';
32
import type { NextApiRequest, NextApiResponse } from 'next';
43

54
import fetchFactory from 'nextjs/utils/fetchProxy';
@@ -18,7 +17,7 @@ const handler = async(nextReq: NextApiRequest, nextRes: NextApiResponse) => {
1817
);
1918
const apiRes = await fetchFactory(nextReq)(
2019
url.toString(),
21-
_pickBy(_pick(nextReq, [ 'body', 'method' ]), Boolean),
20+
pickBy(pick(nextReq, [ 'body', 'method' ]), Boolean),
2221
);
2322

2423
// proxy some headers from API

playwright/fixtures/mockContractReadResponse.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { TestFixture, Page } from '@playwright/test';
2-
import _isEqual from 'lodash/isEqual';
2+
import { isEqual } from 'es-toolkit';
33
import { encodeFunctionData, encodeFunctionResult, type AbiFunction } from 'viem';
44

55
import { getEnvValue } from 'configs/app/utils';
@@ -43,7 +43,7 @@ const fixture: TestFixture<MockContractReadResponseFixture, { page: Page }> = as
4343
value: params?.value,
4444
};
4545

46-
if (_isEqual(params, callParams) && id) {
46+
if (isEqual(params, callParams) && id) {
4747
return route.fulfill({
4848
status: 200,
4949
json: {

playwright/fixtures/mockRpcResponse.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { TestFixture, Page } from '@playwright/test';
2-
import _isEqual from 'lodash/isEqual';
2+
import { isEqual } from 'es-toolkit';
33
import type { PublicRpcSchema } from 'viem';
44

55
import { getEnvValue } from 'configs/app/utils';
@@ -34,7 +34,7 @@ const fixture: TestFixture<MockRpcResponseFixture, { page: Page }> = async({ pag
3434
...(rpcMock.Parameters ? { params: rpcMock.Parameters } : {}),
3535
};
3636

37-
if (_isEqual(json, payload) && id !== undefined) {
37+
if (isEqual(json, payload) && id !== undefined) {
3838
return route.fulfill({
3939
status: 200,
4040
json: {

playwright/index.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import './fonts.css';
22
import './index.css';
33
import { beforeMount } from '@playwright/experimental-ct-react/hooks';
4-
import _defaultsDeep from 'lodash/defaultsDeep';
54
import MockDate from 'mockdate';
65
import * as router from 'next/router';
76

@@ -12,12 +11,15 @@ const NEXT_ROUTER_MOCK = {
1211
replace: () => Promise.resolve(),
1312
};
1413

15-
beforeMount(async({ hooksConfig }) => {
14+
beforeMount(async({ hooksConfig }: { hooksConfig?: { router: typeof router } }) => {
1615
// Before mount, redefine useRouter to return mock value from test.
1716

1817
// @ts-ignore: I really want to redefine this property :)
1918
// eslint-disable-next-line no-import-assign
20-
router.useRouter = () => _defaultsDeep(hooksConfig?.router, NEXT_ROUTER_MOCK);
19+
router.useRouter = () => ({
20+
...NEXT_ROUTER_MOCK,
21+
...hooksConfig?.router,
22+
});
2123

2224
// set current date
2325
MockDate.set('2022-11-11T12:00:00Z');

0 commit comments

Comments
 (0)