Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

⚠️ Migrate SUI Tools to TS or add TypeDefinitions #1765

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8,804 changes: 5,255 additions & 3,549 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion packages/sui-compiler-config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"homepage": "https://github.com/SUI-Components/sui/tree/master/packages/sui-compiler-config#readme",
"dependencies": {
"@tsconfig/esm": "1.0.4",
"@tsconfig/vite-react": "2.0.0"
"@tsconfig/vite-react": "2.0.0",
"new-javascript": "^0.4.3"
}
}
3 changes: 2 additions & 1 deletion packages/sui-compiler-config/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"extends": ["@tsconfig/esm/tsconfig.json", "@tsconfig/vite-react/tsconfig.json"],
"compilerOptions": {
"allowJs": true,
"target": "ES2022"
"target": "ES2022",
"types": ["new-javascript"],
}
}

9 changes: 9 additions & 0 deletions packages/sui-react-web-vitals/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Device Memory
// Specification: https://www.w3.org/TR/device-memory/
// Repository: https://github.com/w3c/device-memory

interface NavigatorDeviceMemory {
readonly deviceMemory: number
}

interface Navigator extends NavigatorDeviceMemory {}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {useContext, useEffect, useRef} from 'react'
/* eslint @typescript-eslint/strict-boolean-expressions:0 */
/* eslint @typescript-eslint/no-non-null-assertion:0 */
import React, {useContext, useEffect, useRef} from 'react'

import PropTypes from 'prop-types'
import * as cwv from 'web-vitals/attribution'
Expand All @@ -14,7 +16,7 @@ export const METRICS = {
INP: 'INP',
LCP: 'LCP',
TTFB: 'TTFB'
}
} as const

const INP_METRICS = {
ID: 'ID',
Expand All @@ -27,14 +29,53 @@ const RATING = {
GOOD: 'good',
NEEDS_IMPROVEMENT: 'needs-improvement',
POOR: 'poor'
}
} as const

const DEFAULT_METRICS_REPORTING_ALL_CHANGES = [METRICS.CLS, METRICS.FID, METRICS.INP, METRICS.LCP]
const DEFAULT_METRICS_REPORTING_ALL_CHANGES = [METRICS.CLS, METRICS.FID, METRICS.INP, METRICS.LCP] as const

export const DEVICE_TYPES = {
DESKTOP: 'desktop',
TABLET: 'tablet',
MOBILE: 'mobile'
} as const

type DeviceType = typeof DEVICE_TYPES[keyof typeof DEVICE_TYPES]
type Metric = typeof METRICS[keyof typeof METRICS]
interface Route {
id?: string
path?: string
regexp?: RegExp
}

interface Attribution {
largestShiftTarget?: Element
element?: Element
eventTarget?: Element
loadState?: string
eventType?: string
}

interface MetricReport {
name: string
value: number
attribution: Attribution
rating: typeof RATING[keyof typeof RATING]
}

interface WebVitalsReporterProps extends React.PropsWithChildren {
reporter: typeof cwv
deviceType: DeviceType
metrics: Metric[]
metricsAllChanges: typeof DEFAULT_METRICS_REPORTING_ALL_CHANGES
onReport: (args: {
name: string
amount: number
pathname: string
routeid: string
type: string
entries: PerformanceEntry[]
}) => void
allowed: string[]
}

export default function WebVitalsReporter({
Expand All @@ -45,7 +86,7 @@ export default function WebVitalsReporter({
metricsAllChanges = DEFAULT_METRICS_REPORTING_ALL_CHANGES,
onReport,
allowed = []
}) {
}: WebVitalsReporterProps) {
const {logger, browser} = useContext(SUIContext)
const router = useRouter()
const {routes} = router
Expand All @@ -57,21 +98,25 @@ export default function WebVitalsReporter({
}, [onReport])

useMount(() => {
const {deviceMemory, connection: {effectiveType} = {}, hardwareConcurrency} = window.navigator || {}
const {
deviceMemory,
connection: {effectiveType} = {effectiveType: ''},
hardwareConcurrency
} = window.navigator ?? {}

const getRouteid = () => {
return route?.id
}

const getPathname = route => {
return route?.path || route?.regexp?.toString().replace(/[^a-z0-9]/gi, '')
const getPathname = (route: Route | undefined) => {
return route?.path ?? route?.regexp?.toString().replace(/[^a-z0-9]/gi, '')
}

const getDeviceType = () => {
return deviceType || browser?.deviceType
}

const getTarget = ({name, attribution}) => {
const getTarget = ({name, attribution}: {name: string; attribution: Attribution}) => {
switch (name) {
case METRICS.CLS:
return attribution.largestShiftTarget
Expand All @@ -82,24 +127,24 @@ export default function WebVitalsReporter({
}
}

const computeINPMetrics = entry => {
const computeINPMetrics = (entry: PerformanceEntry & {processingStart: number; processingEnd: number}) => {
// RenderTime is an estimate because duration is rounded and may get rounded down.
// In rare cases, it can be less than processingEnd and that breaks performance.measure().
// Let's ensure it's at least 4ms in those cases so you can barely see it.
const presentationTime = Math.max(entry.processingEnd + 4, entry.startTime + entry.duration)

return {
[INP_METRICS.ID]: Math.round(entry.processingStart - entry.startTime, 0),
[INP_METRICS.PT]: Math.round(entry.processingEnd - entry.processingStart, 0),
[INP_METRICS.PD]: Math.round(presentationTime - entry.processingEnd, 0)
[INP_METRICS.ID]: Math.round(entry.processingStart - entry.startTime),
[INP_METRICS.PT]: Math.round(entry.processingEnd - entry.processingStart),
[INP_METRICS.PD]: Math.round(presentationTime - entry.processingEnd)
}
}

const handleAllChanges = ({attribution, name, rating, value}) => {
const handleAllChanges = ({attribution, name, rating, value}: MetricReport) => {
const amount = name === METRICS.CLS ? value * 1000 : value
const pathname = getPathname(route)
const routeid = getRouteid()
const isAllowed = allowed.includes(pathname) || allowed.includes(routeid)
const isAllowed = allowed.includes(pathname!) || allowed.includes(routeid)
const target = getTarget({name, attribution})

if (!isAllowed || !logger?.cwv || rating === RATING.GOOD || !target) return
Expand All @@ -121,20 +166,20 @@ export default function WebVitalsReporter({
})
}

const handleChange = ({name, value, entries}) => {
const handleChange = ({name, value, entries}: {name: Metric; value: number; entries: PerformanceEntry[]}) => {
const onReport = onReportRef.current
const pathname = getPathname(route)
const routeid = getRouteid()
const type = getDeviceType()
const isAllowed = allowed.includes(pathname) || allowed.includes(routeid)
const isAllowed = allowed.includes(pathname!) || allowed.includes(routeid)

if (!isAllowed) return

if (onReport) {
onReport({
name,
amount: value,
pathname,
pathname: pathname!,
routeid,
type,
entries
Expand Down Expand Up @@ -183,7 +228,9 @@ export default function WebVitalsReporter({

if (name === METRICS.INP) {
entries.forEach(entry => {
const metrics = computeINPMetrics(entry)
const metrics = computeINPMetrics(
entry as PerformanceEntry & {processingStart: number; processingEnd: number}
)

Object.keys(metrics).forEach(name => {
logger.distribution({
Expand Down
19 changes: 3 additions & 16 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,7 @@
{
"extends": "@s-ui/bundler/tsconfig.json",
"compilerOptions": {
"declaration": true,
"jsx": "react-jsx",
"module": "es6",
"esModuleInterop": true,
"moduleResolution": "node",
"noImplicitAny": false,
"baseUrl": ".",
"outDir": "./lib",
"skipLibCheck": true,
"strict": true,
"target": "es5",
"types": ["react", "node"]
"rootDir": "."
},
"exclude": ["node_modules", "lib"],
"typeAcquisition": {
"enable": true
}
"exclude": ["node_modules", "build", "lib", "contract", "test-e2e"]
}
Loading