fix: reduce toolbar bundle size by 60% (#20122)
* output analyzable build info for the toolbar * don't use code snippet it adds half a meg * Update UI snapshots for `chromium` (2) * use esbuild visualizer instead * fix * allow treeshaking and remove circular dependency from imports toolbar uses * fix * lint the mjs files at the root of frontend folder * no need to mention lemonui at all * no ned to specify metafile * don't allow posthog-js to sneak into the toolbar * simpler date picker so fewer dependencies * maybe this * like this? * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (2) * ragE * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (2) * too easy to break things this way * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (1) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `webkit` (2) * around the houses * Reset snapshots to master * explain why there's a plugin * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (1) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `webkit` (2) * Update UI snapshots for `chromium` (2) * fix * fix * Update UI snapshots for `webkit` (2) * fix * Update UI snapshots for `webkit` (2) --------- Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
4
.gitignore
vendored
@ -60,4 +60,6 @@ upgrade/
|
||||
hogvm/typescript/dist
|
||||
.wokeignore
|
||||
plugin-transpiler/dist
|
||||
.dlt
|
||||
*-esbuild-meta.json
|
||||
*-esbuild-bundle-visualization.html
|
||||
.dlt
|
||||
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
@ -51,9 +51,43 @@ await buildInParallel(
|
||||
// make sure we don't link to a global window.define
|
||||
banner: { js: 'var posthogToolbar = (function () { var define = undefined;' },
|
||||
footer: { js: 'return posthogToolbar })();' },
|
||||
// This isn't great but we load some static assets at runtime for the toolbar and we can't sub in
|
||||
// This isn't great, but we load some static assets at runtime for the toolbar, and we can't sub in
|
||||
// a variable at runtime it seems...
|
||||
publicPath: isDev ? '/static/' : 'https://app.posthog.com/static/',
|
||||
alias: {
|
||||
'posthog-js': 'posthog-js-lite',
|
||||
},
|
||||
writeMetaFile: true,
|
||||
extraPlugins: [
|
||||
{
|
||||
name: 'no-side-effects',
|
||||
setup(build) {
|
||||
// sideEffects in package.json lists files that _have_ side effects,
|
||||
// but we only want to mark lemon-ui as having no side effects,
|
||||
// so we'd have to list every other file and keep that up to date
|
||||
// no thanks!
|
||||
// a glob that negates the path doesn't seem to work
|
||||
// so based off a comment from the esbuild author here
|
||||
// https://github.com/evanw/esbuild/issues/1895#issuecomment-1003404929
|
||||
// we can add a plugin just for the toolbar build to mark lemon-ui as having no side effects
|
||||
// that will allow tree-shaking and reduce the toolbar bundle size
|
||||
// by over 40% at implementation time
|
||||
build.onResolve({ filter: /^(lib|@posthog)\/lemon-ui/ }, async (args) => {
|
||||
if (args.pluginData) {
|
||||
return
|
||||
} // Ignore this if we called ourselves
|
||||
|
||||
const { path, ...rest } = args
|
||||
rest.pluginData = true // Avoid infinite recursion
|
||||
const result = await build.resolve(path, rest)
|
||||
|
||||
result.sideEffects = false
|
||||
|
||||
return result
|
||||
})
|
||||
},
|
||||
},
|
||||
],
|
||||
...common,
|
||||
},
|
||||
],
|
||||
|
@ -4,7 +4,7 @@ import { textCardModalLogic } from 'lib/components/Cards/TextCard/textCardModalL
|
||||
import { PayGateMini } from 'lib/components/PayGateMini/PayGateMini'
|
||||
import { LemonButton } from 'lib/lemon-ui/LemonButton'
|
||||
import { LemonModal } from 'lib/lemon-ui/LemonModal'
|
||||
import { LemonTextAreaMarkdown } from 'lib/lemon-ui/LemonTextArea/LemonTextArea'
|
||||
import { LemonTextAreaMarkdown } from 'lib/lemon-ui/LemonTextArea'
|
||||
import { userLogic } from 'scenes/userLogic'
|
||||
|
||||
import { AvailableFeature, DashboardType } from '~/types'
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { useActions, useValues } from 'kea'
|
||||
import { CodeSnippet } from 'lib/components/CodeSnippet'
|
||||
import { htmlElementsDisplayLogic } from 'lib/components/HTMLElementsDisplay/htmlElementsDisplayLogic'
|
||||
import { ParsedCSSSelector } from 'lib/components/HTMLElementsDisplay/preselectWithCSS'
|
||||
import { LemonBanner } from 'lib/lemon-ui/LemonBanner'
|
||||
@ -130,8 +129,11 @@ export function HTMLElementsDisplay({
|
||||
return (
|
||||
<div className="flex flex-col gap-1">
|
||||
{editable && !!parsedElements.length && (
|
||||
<div>
|
||||
Selector: <CodeSnippet thing="chosen selector">{chosenSelector}</CodeSnippet>
|
||||
<div className="flex flex-col gap-2 mb-2">
|
||||
<div>Selector:</div>
|
||||
<div className="w-full border rounded bg-bg-3000 px-4 py-2 select-text">
|
||||
<pre className="m-0">{chosenSelector}</pre>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{checkUniqueness && (
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { Meta, StoryFn, StoryObj } from '@storybook/react'
|
||||
import { LemonTextAreaMarkdown as _LemonTextMarkdown } from 'lib/lemon-ui/LemonTextArea/LemonTextAreaMarkdown'
|
||||
import { useState } from 'react'
|
||||
|
||||
import { LemonTextArea, LemonTextAreaMarkdown as _LemonTextMarkdown, LemonTextAreaProps } from './LemonTextArea'
|
||||
import { LemonTextArea, LemonTextAreaProps } from './LemonTextArea'
|
||||
|
||||
type Story = StoryObj<typeof LemonTextArea>
|
||||
const meta: Meta<typeof LemonTextArea> = {
|
||||
|
@ -1,20 +1,8 @@
|
||||
import './LemonTextArea.scss'
|
||||
|
||||
import clsx from 'clsx'
|
||||
import { useValues } from 'kea'
|
||||
import { TextContent } from 'lib/components/Cards/TextCard/TextCard'
|
||||
import { useUploadFiles } from 'lib/hooks/useUploadFiles'
|
||||
import { IconMarkdown, IconTools } from 'lib/lemon-ui/icons'
|
||||
import { LemonFileInput } from 'lib/lemon-ui/LemonFileInput/LemonFileInput'
|
||||
import { lemonToast } from 'lib/lemon-ui/LemonToast/LemonToast'
|
||||
import { Link } from 'lib/lemon-ui/Link'
|
||||
import { Tooltip } from 'lib/lemon-ui/Tooltip'
|
||||
import posthog from 'posthog-js'
|
||||
import React, { useRef, useState } from 'react'
|
||||
import React, { useRef } from 'react'
|
||||
import TextareaAutosize from 'react-textarea-autosize'
|
||||
import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic'
|
||||
|
||||
import { LemonTabs } from '../LemonTabs'
|
||||
|
||||
export interface LemonTextAreaProps
|
||||
extends Pick<
|
||||
@ -74,84 +62,3 @@ export const LemonTextArea = React.forwardRef<HTMLTextAreaElement, LemonTextArea
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
||||
export const LemonTextAreaMarkdown = React.forwardRef<HTMLTextAreaElement, LemonTextAreaProps>(
|
||||
function _LemonTextAreaMarkdown({ value, onChange, ...editAreaProps }, ref): JSX.Element {
|
||||
const { objectStorageAvailable } = useValues(preflightLogic)
|
||||
|
||||
const [isPreviewShown, setIsPreviewShown] = useState(false)
|
||||
const dropRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const { setFilesToUpload, filesToUpload, uploading } = useUploadFiles({
|
||||
onUpload: (url, fileName) => {
|
||||
onChange?.(value + `\n\n![${fileName}](${url})`)
|
||||
posthog.capture('markdown image uploaded', { name: fileName })
|
||||
},
|
||||
onError: (detail) => {
|
||||
posthog.capture('markdown image upload failed', { error: detail })
|
||||
lemonToast.error(`Error uploading image: ${detail}`)
|
||||
},
|
||||
})
|
||||
|
||||
return (
|
||||
<LemonTabs
|
||||
activeKey={isPreviewShown ? 'preview' : 'write'}
|
||||
onChange={(key) => setIsPreviewShown(key === 'preview')}
|
||||
tabs={[
|
||||
{
|
||||
key: 'write',
|
||||
label: 'Write',
|
||||
content: (
|
||||
<div ref={dropRef} className="LemonTextMarkdown flex flex-col space-y-1 rounded">
|
||||
<LemonTextArea
|
||||
ref={ref}
|
||||
{...editAreaProps}
|
||||
autoFocus
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
<div className="text-muted inline-flex items-center space-x-1">
|
||||
<IconMarkdown className="text-2xl" />
|
||||
<span>Markdown formatting support</span>
|
||||
</div>
|
||||
{objectStorageAvailable ? (
|
||||
<LemonFileInput
|
||||
accept={'image/*'}
|
||||
multiple={false}
|
||||
alternativeDropTargetRef={dropRef}
|
||||
onChange={setFilesToUpload}
|
||||
loading={uploading}
|
||||
value={filesToUpload}
|
||||
/>
|
||||
) : (
|
||||
<div className="text-muted inline-flex items-center space-x-1">
|
||||
<Tooltip title="Enable object storage to add images by dragging and dropping.">
|
||||
<IconTools className="text-xl mr-1" />
|
||||
</Tooltip>
|
||||
<span>
|
||||
Add external images using{' '}
|
||||
<Link to="https://www.markdownguide.org/basic-syntax/#images-1">
|
||||
{' '}
|
||||
Markdown image links
|
||||
</Link>
|
||||
.
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'preview',
|
||||
label: 'Preview',
|
||||
content: value ? (
|
||||
<TextContent text={value} className="LemonTextArea--preview" />
|
||||
) : (
|
||||
<i>Nothing to preview</i>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
@ -0,0 +1,94 @@
|
||||
import { useValues } from 'kea'
|
||||
import { TextContent } from 'lib/components/Cards/TextCard/TextCard'
|
||||
import { useUploadFiles } from 'lib/hooks/useUploadFiles'
|
||||
import { IconMarkdown, IconTools } from 'lib/lemon-ui/icons'
|
||||
import { LemonFileInput } from 'lib/lemon-ui/LemonFileInput'
|
||||
import { LemonTabs } from 'lib/lemon-ui/LemonTabs'
|
||||
import { LemonTextArea, LemonTextAreaProps } from 'lib/lemon-ui/LemonTextArea/LemonTextArea'
|
||||
import { lemonToast } from 'lib/lemon-ui/LemonToast'
|
||||
import { Link } from 'lib/lemon-ui/Link'
|
||||
import { Tooltip } from 'lib/lemon-ui/Tooltip'
|
||||
import posthog from 'posthog-js'
|
||||
import React, { useRef, useState } from 'react'
|
||||
import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic'
|
||||
|
||||
export const LemonTextAreaMarkdown = React.forwardRef<HTMLTextAreaElement, LemonTextAreaProps>(
|
||||
function _LemonTextAreaMarkdown({ value, onChange, ...editAreaProps }, ref): JSX.Element {
|
||||
const { objectStorageAvailable } = useValues(preflightLogic)
|
||||
|
||||
const [isPreviewShown, setIsPreviewShown] = useState(false)
|
||||
const dropRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const { setFilesToUpload, filesToUpload, uploading } = useUploadFiles({
|
||||
onUpload: (url, fileName) => {
|
||||
onChange?.(value + `\n\n![${fileName}](${url})`)
|
||||
posthog.capture('markdown image uploaded', { name: fileName })
|
||||
},
|
||||
onError: (detail) => {
|
||||
posthog.capture('markdown image upload failed', { error: detail })
|
||||
lemonToast.error(`Error uploading image: ${detail}`)
|
||||
},
|
||||
})
|
||||
|
||||
return (
|
||||
<LemonTabs
|
||||
activeKey={isPreviewShown ? 'preview' : 'write'}
|
||||
onChange={(key) => setIsPreviewShown(key === 'preview')}
|
||||
tabs={[
|
||||
{
|
||||
key: 'write',
|
||||
label: 'Write',
|
||||
content: (
|
||||
<div ref={dropRef} className="LemonTextMarkdown flex flex-col space-y-1 rounded">
|
||||
<LemonTextArea
|
||||
ref={ref}
|
||||
{...editAreaProps}
|
||||
autoFocus
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
<div className="text-muted inline-flex items-center space-x-1">
|
||||
<IconMarkdown className="text-2xl" />
|
||||
<span>Markdown formatting support</span>
|
||||
</div>
|
||||
{objectStorageAvailable ? (
|
||||
<LemonFileInput
|
||||
accept={'image/*'}
|
||||
multiple={false}
|
||||
alternativeDropTargetRef={dropRef}
|
||||
onChange={setFilesToUpload}
|
||||
loading={uploading}
|
||||
value={filesToUpload}
|
||||
/>
|
||||
) : (
|
||||
<div className="text-muted inline-flex items-center space-x-1">
|
||||
<Tooltip title="Enable object storage to add images by dragging and dropping.">
|
||||
<IconTools className="text-xl mr-1" />
|
||||
</Tooltip>
|
||||
<span>
|
||||
Add external images using{' '}
|
||||
<Link to="https://www.markdownguide.org/basic-syntax/#images-1">
|
||||
{' '}
|
||||
Markdown image links
|
||||
</Link>
|
||||
.
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'preview',
|
||||
label: 'Preview',
|
||||
content: value ? (
|
||||
<TextContent text={value} className="LemonTextArea--preview" />
|
||||
) : (
|
||||
<i>Nothing to preview</i>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
@ -1,2 +1,3 @@
|
||||
export type { LemonTextAreaProps } from './LemonTextArea'
|
||||
export { LemonTextArea, LemonTextAreaMarkdown } from './LemonTextArea'
|
||||
export { LemonTextArea } from './LemonTextArea'
|
||||
export { LemonTextAreaMarkdown } from 'lib/lemon-ui/LemonTextArea/LemonTextAreaMarkdown'
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { LemonButton, LemonModal } from '@posthog/lemon-ui'
|
||||
import { useActions, useValues } from 'kea'
|
||||
import { capitalizeFirstLetter } from 'lib/utils'
|
||||
import { posthog } from 'posthog-js'
|
||||
import posthog from 'posthog-js'
|
||||
|
||||
import { sceneLogic } from './sceneLogic'
|
||||
import { urls } from './urls'
|
||||
|
@ -1,11 +1,13 @@
|
||||
import { useActions, useValues } from 'kea'
|
||||
import { DateFilter } from 'lib/components/DateFilter/DateFilter'
|
||||
import { CUSTOM_OPTION_KEY } from 'lib/components/DateFilter/types'
|
||||
import { IconSync } from 'lib/lemon-ui/icons'
|
||||
import { LemonButton } from 'lib/lemon-ui/LemonButton'
|
||||
import { LemonInput } from 'lib/lemon-ui/LemonInput'
|
||||
import { LemonMenu } from 'lib/lemon-ui/LemonMenu'
|
||||
import { LemonSwitch } from 'lib/lemon-ui/LemonSwitch'
|
||||
import { Spinner } from 'lib/lemon-ui/Spinner'
|
||||
import { Tooltip } from 'lib/lemon-ui/Tooltip'
|
||||
import { dateFilterToText, dateMapping } from 'lib/utils'
|
||||
|
||||
import { ToolbarMenu } from '~/toolbar/bar/ToolbarMenu'
|
||||
import { elementsLogic } from '~/toolbar/elements/elementsLogic'
|
||||
@ -21,6 +23,13 @@ export const HeatmapToolbarMenu = (): JSX.Element => {
|
||||
const { setHeatmapFilter, loadMoreElementStats, setMatchLinksByHref } = useActions(heatmapLogic)
|
||||
const { setHighlightElement, setSelectedElement } = useActions(elementsLogic)
|
||||
|
||||
const dateItems = dateMapping
|
||||
.filter((dm) => dm.key !== CUSTOM_OPTION_KEY)
|
||||
.map((dateOption) => ({
|
||||
label: dateOption.key,
|
||||
onClick: () => setHeatmapFilter({ date_from: dateOption.values[0], date_to: dateOption.values[1] }),
|
||||
}))
|
||||
|
||||
return (
|
||||
<ToolbarMenu>
|
||||
<ToolbarMenu.Header>
|
||||
@ -28,11 +37,11 @@ export const HeatmapToolbarMenu = (): JSX.Element => {
|
||||
<div className="space-y-1 border-b px-1 pb-2">
|
||||
<div className="text-muted p-1">Use * as a wildcard</div>
|
||||
<div className="flex flex-row items-center space-x-2">
|
||||
<DateFilter
|
||||
dateFrom={heatmapFilter.date_from ?? '-7d'}
|
||||
dateTo={heatmapFilter.date_to}
|
||||
onChange={(date_from, date_to) => setHeatmapFilter({ date_from, date_to })}
|
||||
/>
|
||||
<LemonMenu items={dateItems}>
|
||||
<LemonButton size="small" type="secondary">
|
||||
{dateFilterToText(heatmapFilter.date_from, heatmapFilter.date_to, 'Last 7 days')}
|
||||
</LemonButton>
|
||||
</LemonMenu>
|
||||
|
||||
<LemonButton
|
||||
icon={<IconSync />}
|
||||
|
@ -247,7 +247,7 @@ function getBuiltEntryPoints(config, result) {
|
||||
let buildsInProgress = 0
|
||||
|
||||
export async function buildOrWatch(config) {
|
||||
const { absWorkingDir, name, onBuildStart, onBuildComplete, ..._config } = config
|
||||
const { absWorkingDir, name, onBuildStart, onBuildComplete, writeMetaFile, extraPlugins, ..._config } = config
|
||||
|
||||
let buildPromise = null
|
||||
let buildAgain = false
|
||||
@ -311,7 +311,9 @@ export async function buildOrWatch(config) {
|
||||
|
||||
async function runBuild() {
|
||||
if (!esbuildContext) {
|
||||
esbuildContext = await context({ ...commonConfig, ..._config })
|
||||
const combinedConfig = { ...commonConfig, ..._config }
|
||||
combinedConfig.plugins = [...commonConfig.plugins, ...(extraPlugins || [])]
|
||||
esbuildContext = await context(combinedConfig)
|
||||
}
|
||||
|
||||
buildCount++
|
||||
@ -319,6 +321,14 @@ export async function buildOrWatch(config) {
|
||||
log({ name })
|
||||
try {
|
||||
const buildResult = await esbuildContext.rebuild()
|
||||
|
||||
if (writeMetaFile) {
|
||||
await fs.writeFile(
|
||||
`${config.name.toLowerCase().replace(' ', '-')}-esbuild-meta.json`,
|
||||
JSON.stringify(buildResult.metafile)
|
||||
)
|
||||
}
|
||||
|
||||
inputFiles = getInputFiles(buildResult)
|
||||
|
||||
log({ success: true, name, time })
|
||||
|
@ -61,7 +61,8 @@
|
||||
"prepare": "husky install",
|
||||
"mobile-replay:web:schema:build:json": "ts-json-schema-generator -f tsconfig.json --path 'node_modules/@rrweb/types/dist/index.d.ts' --type 'eventWithTime' --expose all --no-top-ref --out ee/frontend/mobile-replay/schema/web/rr-web-schema.json && prettier --write ee/frontend/mobile-replay/schema/web/rr-web-schema.json",
|
||||
"mobile-replay:mobile:schema:build:json": "ts-json-schema-generator -f tsconfig.json --path 'ee/frontend/mobile-replay/mobile.types.ts' --type 'mobileEventWithTime' --expose all --no-top-ref --out ee/frontend/mobile-replay/schema/mobile/rr-mobile-schema.json && prettier --write ee/frontend/mobile-replay/schema/mobile/rr-mobile-schema.json",
|
||||
"mobile-replay:schema:build:json": "pnpm mobile-replay:web:schema:build:json && pnpm mobile-replay:mobile:schema:build:json"
|
||||
"mobile-replay:schema:build:json": "pnpm mobile-replay:web:schema:build:json && pnpm mobile-replay:mobile:schema:build:json",
|
||||
"visualize-toolbar-bundle": "pnpm exec esbuild-visualizer --metadata ./toolbar-esbuild-meta.json --filename=toolbar-esbuild-bundle-visualization.html"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^4.7.0",
|
||||
@ -244,6 +245,7 @@
|
||||
"cypress": "^13.3.0",
|
||||
"cypress-axe": "^1.5.0",
|
||||
"cypress-terminal-report": "^5.3.7",
|
||||
"esbuild-visualizer": "^0.6.0",
|
||||
"eslint": "^8.52.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-compat": "^4.2.0",
|
||||
@ -319,6 +321,10 @@
|
||||
"eslint -c .eslintrc.js --fix",
|
||||
"prettier --write"
|
||||
],
|
||||
"frontend/*.mjs": [
|
||||
"eslint -c .eslintrc.js --fix",
|
||||
"prettier --write"
|
||||
],
|
||||
"ee/frontend/**/*.{js,jsx,mjs,ts,tsx}": [
|
||||
"eslint -c .eslintrc.js --fix",
|
||||
"prettier --write"
|
||||
|
@ -545,6 +545,9 @@ devDependencies:
|
||||
cypress-terminal-report:
|
||||
specifier: ^5.3.7
|
||||
version: 5.3.7(cypress@13.3.0)
|
||||
esbuild-visualizer:
|
||||
specifier: ^0.6.0
|
||||
version: 0.6.0
|
||||
eslint:
|
||||
specifier: ^8.52.0
|
||||
version: 8.52.0
|
||||
@ -11627,6 +11630,16 @@ packages:
|
||||
sass-embedded: 1.70.0
|
||||
dev: false
|
||||
|
||||
/esbuild-visualizer@0.6.0:
|
||||
resolution: {integrity: sha512-oNK3JAhC7+re93VTtUdWJKTDVnA2qXPAjCAoaw9OxEFUXztszw3kcaK46u1U790T8FdUBAWv6F9Xt59P8nJCVA==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
open: 8.4.2
|
||||
picomatch: 2.3.1
|
||||
yargs: 17.6.2
|
||||
dev: true
|
||||
|
||||
/esbuild@0.18.20:
|
||||
resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==}
|
||||
engines: {node: '>=12'}
|
||||
|