[www] remove lodash (#38240)

remove lodash from www
This commit is contained in:
Francesco Sansalvadore
2025-08-28 10:44:49 +02:00
committed by GitHub
parent 573ad831d2
commit 1f89c24b7a
19 changed files with 178 additions and 54 deletions

View File

@@ -1,6 +1,6 @@
import { LOCAL_STORAGE_KEYS, useBreakpoint } from 'common'
import { AnimatePresence, motion } from 'framer-motion'
import { startCase } from 'lodash'
import { startCase } from 'lib/helpers'
import { useSearchParams } from 'next/navigation'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'

View File

@@ -11,7 +11,7 @@ import {
cn,
} from 'ui'
import { ChevronDown, X as CloseIcon } from 'lucide-react'
import startCase from 'lodash/startCase'
import { startCase } from 'lib/helpers'
import { useBreakpoint } from 'common'
interface Props {

View File

@@ -1,5 +1,5 @@
import React from 'react'
import { range } from 'lodash'
import { range } from 'lib/helpers'
import { cn } from 'ui'
import { CompositionCol } from '.'

View File

@@ -1,6 +1,6 @@
import { useBreakpoint } from 'common'
import { AnimatePresence, motion } from 'framer-motion'
import { startCase } from 'lodash'
import { startCase } from 'lib/helpers'
import { useSearchParams } from 'next/navigation'
import { useRouter } from 'next/router'
import Link from 'next/link'

View File

@@ -1,7 +1,7 @@
import createGlobe from 'cobe'
import { useCallback, useEffect, useRef } from 'react'
import { useTheme } from 'next-themes'
import { debounce } from 'lodash'
import { debounce } from 'lib/helpers'
const Globe = () => {
const { resolvedTheme } = useTheme()

View File

@@ -1,6 +1,6 @@
import React from 'react'
import { cn } from 'ui'
import { range } from 'lodash'
import { range } from 'lib/helpers'
interface Props {
className?: string

View File

@@ -13,7 +13,6 @@ import { isBrowser } from 'common'
import SectionContainer from '~/components/Layouts/SectionContainer'
import { ArrowUpRight, ChevronDown } from 'lucide-react'
import { startCase } from 'lodash'
const LWXStickyNav: FC = () => {
const days = mainDays()

View File

@@ -1,6 +1,6 @@
import React from 'react'
import Image from 'next/image'
import { range } from 'lodash'
import { range } from 'lib/helpers'
import { cn } from 'ui'
interface Props {

View File

@@ -1,4 +1,4 @@
import { range } from 'lodash'
import { range } from 'lib/helpers'
import { File, Image, Video } from 'lucide-react'
import { cn } from 'ui'

View File

@@ -2,7 +2,7 @@ import Link from 'next/link'
import { useRouter } from 'next/router'
import { cn } from 'ui'
import { TweetCard } from 'ui-patterns/TweetCard'
import { range } from 'lodash'
import { range } from 'lib/helpers'
import Tweets from '~/data/tweets/Tweets.json'
import { useBreakpoint } from 'common'

View File

@@ -1,5 +1,5 @@
import { cn } from 'ui'
import { range } from 'lodash'
import { range } from 'lib/helpers'
interface Props {
showHeading?: boolean

View File

@@ -44,3 +44,162 @@ export const stripEmojis = (str: string) =>
)
.replace(/\s+/g, ' ')
.trim()
// Vanilla JavaScript implementations to replace lodash functions
/**
* Creates an array of numbers (positive and/or negative) progressing from start up to, but not including, end.
* @param start The start of the range
* @param end The end of the range
* @param step The value to increment or decrement by
* @returns Returns the range of numbers
*/
export const range = (start: number, end?: number, step: number = 1): number[] => {
if (end === undefined) {
end = start
start = 0
}
const result: number[] = []
for (let i = start; step > 0 ? i < end : i > end; i += step) {
result.push(i)
}
return result
}
/**
* Converts string to start case.
* @param string The string to convert
* @returns Returns the start cased string
*/
export const startCase = (string: string): string => {
if (!string) return string
return string
.replace(/[-_\s]+/g, ' ')
.replace(/([a-z])([A-Z])/g, '$1 $2')
.replace(/\b\w/g, (char) => char.toUpperCase())
.trim()
}
/**
* Creates a debounced function that delays invoking func until after wait milliseconds have elapsed since the last time the debounced function was invoked.
* @param func The function to debounce
* @param wait The number of milliseconds to delay
* @param options The options object
* @returns Returns the new debounced function
*/
export const debounce = <T extends (...args: any[]) => any>(
func: T,
wait: number,
options: { leading?: boolean; trailing?: boolean } = {}
): ((...args: Parameters<T>) => void) & {
cancel: () => void
flush: () => void | undefined
pending: () => boolean
} => {
let timeoutId: ReturnType<typeof setTimeout> | undefined
let lastCallTime: number | undefined
let lastInvokeTime = 0
const { leading = false, trailing = true } = options
function invokeFunc(time: number, ...args: Parameters<T>) {
lastInvokeTime = time
func.apply(null, args)
}
function startTimer(pendingFunc: () => void, wait: number) {
return setTimeout(pendingFunc, wait)
}
function cancelTimer(id: ReturnType<typeof setTimeout>) {
clearTimeout(id)
}
function leadingEdge(time: number, ...args: Parameters<T>) {
lastInvokeTime = time
timeoutId = startTimer(timerExpired, wait)
return leading ? invokeFunc(time, ...args) : undefined
}
function remainingWait(time: number) {
const timeSinceLastCall = time - (lastCallTime || 0)
const timeSinceLastInvoke = time - lastInvokeTime
const timeWaiting = wait - timeSinceLastCall
return Math.min(timeWaiting, wait - timeSinceLastInvoke)
}
function shouldInvoke(time: number) {
const timeSinceLastCall = time - (lastCallTime || 0)
const timeSinceLastInvoke = time - lastInvokeTime
return (
lastCallTime === undefined ||
timeSinceLastCall >= wait ||
timeSinceLastCall < 0 ||
timeSinceLastInvoke >= wait
)
}
function timerExpired() {
const time = Date.now()
if (shouldInvoke(time)) {
return trailingEdge(time)
}
timeoutId = startTimer(timerExpired, remainingWait(time))
}
function trailingEdge(time: number) {
timeoutId = undefined
if (trailing) {
// For trailing edge, we don't have the original arguments, so we call without them
return invokeFunc(time, ...([] as any))
}
}
function cancel() {
if (timeoutId !== undefined) {
cancelTimer(timeoutId)
}
lastInvokeTime = 0
lastCallTime = undefined
timeoutId = undefined
}
function flush() {
return timeoutId === undefined ? undefined : trailingEdge(Date.now())
}
function pending() {
return timeoutId !== undefined
}
function debounced(this: any, ...args: Parameters<T>) {
const time = Date.now()
const isInvoking = shouldInvoke(time)
lastCallTime = time
if (isInvoking) {
if (timeoutId === undefined) {
return leadingEdge(lastCallTime, ...args)
}
if (trailing) {
timeoutId = startTimer(timerExpired, wait)
return invokeFunc(lastCallTime, ...args)
}
}
if (timeoutId === undefined) {
timeoutId = startTimer(timerExpired, wait)
}
}
debounced.cancel = cancel
debounced.flush = flush
debounced.pending = pending
return debounced
}

View File

@@ -49,7 +49,6 @@
"globby": "^13.2.2",
"gray-matter": "^4.0.3",
"icons": "workspace:*",
"lodash": "^4.0.0",
"lucide-react": "*",
"markdown-toc": "^1.2.0",
"next": "catalog:",
@@ -87,7 +86,6 @@
"@types/animejs": "^3.1.12",
"@types/classnames": "^2.3.1",
"@types/common-tags": "^1.8.4",
"@types/lodash": "^4.0.0",
"@types/mdx-js__react": "^1.5.6",
"@types/parse-numeric-range": "^0.0.1",
"@types/react": "catalog:",

View File

@@ -1,7 +1,7 @@
import { NextSeo } from 'next-seo'
import { getSortedPosts, getAllCategories } from '~/lib/posts'
import Link from 'next/link'
import { startCase } from 'lodash'
import { startCase } from 'lib/helpers'
import DefaultLayout from '~/components/Layouts/Default'
import BlogGridItem from '~/components/Blog/BlogGridItem'

View File

@@ -1,7 +1,7 @@
import { NextSeo } from 'next-seo'
import { getSortedPosts, getAllTags } from '~/lib/posts'
import Link from 'next/link'
import { startCase } from 'lodash'
import { startCase } from 'lib/helpers'
import DefaultLayout from '~/components/Layouts/Default'
import BlogGridItem from '~/components/Blog/BlogGridItem'

View File

@@ -6,7 +6,6 @@ import {
} from '@heroicons/react/solid'
import dayjs from 'dayjs'
import matter from 'gray-matter'
import capitalize from 'lodash/capitalize'
import { ChevronLeft, X as XIcon } from 'lucide-react'
import { MDXRemote } from 'next-mdx-remote'
import { NextSeo } from 'next-seo'
@@ -14,7 +13,7 @@ import NextImage from 'next/image'
import Link from 'next/link'
import authors from 'lib/authors.json'
import { isNotNullOrUndefined } from '~/lib/helpers'
import { capitalize, isNotNullOrUndefined } from '~/lib/helpers'
import mdxComponents from '~/lib/mdx/mdxComponents'
import { mdxSerialize } from '~/lib/mdx/mdxSerialize'
import { getAllPostSlugs, getPostdata } from '~/lib/posts'

View File

@@ -4,7 +4,7 @@ import { useRouter } from 'next/router'
import { NextSeo } from 'next-seo'
import { motion } from 'framer-motion'
import { Search } from 'lucide-react'
import debounce from 'lodash/debounce'
import { debounce } from 'lib/helpers'
import { Button, Checkbox, cn, Input } from 'ui'
import DefaultLayout from '~/components/Layouts/Default'

View File

@@ -1,4 +1,4 @@
import { range } from 'lodash'
import { range } from 'lib/helpers'
import { NextSeo } from 'next-seo'
import Image from 'next/image'
import Link from 'next/link'

39
pnpm-lock.yaml generated
View File

@@ -1161,7 +1161,7 @@ importers:
version: 4.4.2
'@vitest/coverage-v8':
specifier: ^3.0.9
version: 3.0.9(supports-color@8.1.1)(vitest@3.0.9)
version: 3.0.9(supports-color@8.1.1)(vitest@3.0.9(@types/node@22.13.14)(jiti@2.4.2)(jsdom@20.0.3(supports-color@8.1.1))(msw@2.7.3(@types/node@22.13.14)(typescript@5.5.2))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.20.3)(yaml@2.4.5))
'@vitest/ui':
specifier: ^3.0.0
version: 3.0.4(vitest@3.0.9)
@@ -1607,9 +1607,6 @@ importers:
icons:
specifier: workspace:*
version: link:../../packages/icons
lodash:
specifier: ^4.0.0
version: 4.17.21
lucide-react:
specifier: '*'
version: 0.436.0(react@18.3.1)
@@ -1716,9 +1713,6 @@ importers:
'@types/common-tags':
specifier: ^1.8.4
version: 1.8.4
'@types/lodash':
specifier: ^4.0.0
version: 4.17.5
'@types/mdx-js__react':
specifier: ^1.5.6
version: 1.5.6
@@ -1930,7 +1924,7 @@ importers:
version: 18.3.0
'@vitest/coverage-v8':
specifier: ^3.0.9
version: 3.0.9(supports-color@8.1.1)(vitest@3.0.9)
version: 3.0.9(supports-color@8.1.1)(vitest@3.0.9(@types/node@22.13.14)(jiti@2.4.2)(jsdom@20.0.3(supports-color@8.1.1))(msw@2.7.3(@types/node@22.13.14)(typescript@5.5.2))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.20.3)(yaml@2.4.5))
'@vitest/ui':
specifier: ^3.0.0
version: 3.0.4(vitest@3.0.9)
@@ -10936,7 +10930,6 @@ packages:
resolution: {integrity: sha512-t0q23FIpvHDTtnORW+bDJziGsal5uh9RJTJ1fyH8drd4lICOoXhJ5pLMUZ5C0VQei6dNmwTzzoTRgMkO9JgHEQ==}
peerDependencies:
eslint: '>= 5'
bundledDependencies: []
eslint-plugin-import@2.31.0:
resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==}
@@ -15012,10 +15005,6 @@ packages:
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
engines: {node: '>=6'}
punycode@2.3.0:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
engines: {node: '>=6'}
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
@@ -27216,24 +27205,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@vitest/coverage-v8@3.0.9(supports-color@8.1.1)(vitest@3.0.9)':
dependencies:
'@ampproject/remapping': 2.3.0
'@bcoe/v8-coverage': 1.0.2
debug: 4.4.0(supports-color@8.1.1)
istanbul-lib-coverage: 3.2.2
istanbul-lib-report: 3.0.1
istanbul-lib-source-maps: 5.0.6(supports-color@8.1.1)
istanbul-reports: 3.1.7
magic-string: 0.30.17
magicast: 0.3.5
std-env: 3.8.1
test-exclude: 7.0.1
tinyrainbow: 2.0.0
vitest: 3.0.9(@types/node@22.13.14)(@vitest/ui@3.0.4)(jiti@2.4.2)(jsdom@20.0.3(supports-color@8.1.1))(msw@2.4.11(typescript@5.5.2))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.19.3)(yaml@2.4.5)
transitivePeerDependencies:
- supports-color
'@vitest/expect@3.0.9':
dependencies:
'@vitest/spy': 3.0.9
@@ -27300,7 +27271,7 @@ snapshots:
sirv: 3.0.0
tinyglobby: 0.2.14
tinyrainbow: 2.0.0
vitest: 3.0.9(@types/node@22.13.14)(@vitest/ui@3.0.4)(jiti@2.4.2)(jsdom@20.0.3(supports-color@8.1.1))(msw@2.4.11(typescript@5.5.2))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.19.3)(yaml@2.4.5)
vitest: 3.0.9(@types/node@22.13.14)(@vitest/ui@3.0.4)(jiti@2.4.2)(jsdom@20.0.3(supports-color@8.1.1))(msw@2.7.3(@types/node@22.13.14)(typescript@5.5.2))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.20.3)(yaml@2.4.5)
'@vitest/utils@3.0.4':
dependencies:
@@ -34867,8 +34838,6 @@ snapshots:
punycode.js@2.3.1: {}
punycode@2.3.0: {}
punycode@2.3.1: {}
qs-esm@7.0.2: {}
@@ -37838,7 +37807,7 @@ snapshots:
uri-js@4.4.1:
dependencies:
punycode: 2.3.0
punycode: 2.3.1
url-parse@1.5.10:
dependencies: