Skip to content

Commit

Permalink
feat: add time options to set loading network speed, latency and mess…
Browse files Browse the repository at this point in the history
…age (#384)

* feat(loading-time-customization): rename check time property to totalTime

* feat(loading-time-customization): add time plugin options to set network speed, latency and loading message for every check

* docs(loading-time-customization) add doc for time plugin options

* docs(loading-time-customization) format doc

---------

Co-authored-by: Andrey Sitnik <[email protected]>
  • Loading branch information
EvgenyWas and ai authored Feb 18, 2025
1 parent 6f44d9b commit edda423
Show file tree
Hide file tree
Showing 16 changed files with 298 additions and 26 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ if the cost exceeds the limit.
* Can calculate **the time** it would take a browser
to download and **execute** your JS. Time is a much more accurate
and understandable metric compared to the size in bytes.
Additionally, you can [customize time plugin] via config
for every check with network speed, latency and so on.
* Calculations include **all dependencies and polyfills**
used in your JS.

Expand Down Expand Up @@ -50,6 +52,7 @@ We are using [Statoscope] for this analysis.
[Statoscope]: https://github.com/statoscope/statoscope
[cult-img]: http://cultofmartians.com/assets/badges/badge.svg
[cult]: http://cultofmartians.com/tasks/size-limit-config.html
[customize time plugin]: https://github.com/ai/size-limit/packages/time#customize-network-speed

## Who Uses Size Limit

Expand Down
Empty file added fixtures/time-latency/index.js
Empty file.
21 changes: 21 additions & 0 deletions fixtures/time-latency/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"private": true,
"name": "time-latency",
"devDependencies": {
"@size-limit/time": ">= 0.0.0",
"size-limit": ">= 0.0.0"
},
"size-limit": [
{
"path": "index.js",
"time": {
"latency": "200 ms"
}
},
{
"time": {
"latency": "2.35 s"
}
}
]
}
Empty file.
21 changes: 21 additions & 0 deletions fixtures/time-network-speed/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"private": true,
"name": "time-network-speed",
"devDependencies": {
"@size-limit/time": ">= 0.0.0",
"size-limit": ">= 0.0.0"
},
"size-limit": [
{
"path": "index.js",
"time": {
"networkSpeed": "20 B"
}
},
{
"time": {
"networkSpeed": "20 kB"
}
}
]
}
2 changes: 1 addition & 1 deletion packages/size-limit/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default async function calc(plugins, config, createSpinner) {
check.passed = check.sizeLimit >= check.size
}
if (typeof check.timeLimit !== 'undefined') {
check.passed = check.timeLimit >= check.time
check.passed = check.timeLimit >= check.totalTime
}
if (check.files && !check.files.length && check.path) {
check.missed = true
Expand Down
6 changes: 4 additions & 2 deletions packages/size-limit/create-reporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,14 @@ function createHumanReporter(process, isSilentMode = false) {
rows.push(['Size', sizeString, sizeNote])
}
if (typeof check.loadTime !== 'undefined') {
rows.push(['Loading time', formatTime(check.loadTime), 'on slow 3G'])
let description =
(check.time && check.time.loadingMessage) || 'on slow 3G'
rows.push(['Loading time', formatTime(check.loadTime), description])
}
if (typeof check.runTime !== 'undefined') {
rows.push(
['Running time', formatTime(check.runTime), 'on Snapdragon 410'],
['Total time', formatTime(check.time)]
['Total time', formatTime(check.totalTime)]
)
}

Expand Down
26 changes: 24 additions & 2 deletions packages/size-limit/get-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ let OPTIONS = {
name: true,
path: true,
running: 'time',
time: 'time',
uiReports: 'webpack',
webpack: 'webpack'
}
Expand All @@ -42,6 +43,14 @@ function isStringsOrUndefined(value) {
return type === 'undefined' || type === 'string' || isStrings(value)
}

function endsWithMs(value) {
return / ?ms/i.test(value)
}

function endsWithS(value) {
return / ?s/i.test(value)
}

function checkChecks(plugins, checks) {
if (!Array.isArray(checks)) {
throw new SizeLimitError('noArrayConfig')
Expand Down Expand Up @@ -183,9 +192,9 @@ export default async function getConfig(plugins, process, args, pkg) {
if (!check.name) check.name = toName(check.entry || check.files, config.cwd)
if (args.limit) check.limit = args.limit
if (check.limit) {
if (/ ?ms/i.test(check.limit)) {
if (endsWithMs(check.limit)) {
check.timeLimit = parseFloat(check.limit) / 1000
} else if (/ ?s/i.test(check.limit)) {
} else if (endsWithS(check.limit)) {
check.timeLimit = parseFloat(check.limit)
} else {
check.sizeLimit = bytes.parse(check.limit)
Expand Down Expand Up @@ -217,6 +226,19 @@ export default async function getConfig(plugins, process, args, pkg) {
}
check.import = imports
}
if (check.time) {
let { latency, networkSpeed } = check.time
if (latency) {
if (endsWithMs(latency)) {
check.time.latency = parseFloat(latency) / 1000
} else {
check.time.latency = parseFloat(latency) || 0
}
}
if (networkSpeed) {
check.time.networkSpeed = bytes.parse(networkSpeed)
}
}
}

return config
Expand Down
32 changes: 32 additions & 0 deletions packages/size-limit/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,38 @@ export interface Check {
* With `false` it will disable webpack.
*/
webpack?: boolean

/**
* Options for `@size-limit/time` plugin.
*/
time?: TimeOptions
}

/**
* Represents the options for the size-limit check time property to customize `@size-limit/time` plugin.
*/
export interface TimeOptions {
/**
* A network speed to calculate loading time of files.
* It should be a string with a number and unit, separated by a space.
* Format: `100 B`, `10 kB`.
* @default "50 kB"
*/
networkSpeed?: string

/**
* Delay for calculating loading time that simulates network latency
* It should be a string with a number and unit, separated by a space.
* Format: `500 ms`, `1 s`.
* @default: "0"
*/
latency: string

/**
* A message for loading time details
* @default "on slow 3G"
*/
loadingMessage?: string
}

export type SizeLimitConfig = Check[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,22 @@ exports[`renders list of success checks in silent mode 1`] = `
"
`;

exports[`renders loading time with custom message from time options for every check 1`] = `
"
loading message 1
Size: 10 B
Loading time: 200 ms for ~1000 users per month
Running time: 400 ms on Snapdragon 410
Total time: 1.4 s
loading message 2
Loading time: 200 ms on slow 3G
Running time: 300 ms on Snapdragon 410
Total time: NaN ms
"
`;

exports[`renders result for file with gzip 1`] = `
"
Size limit: 99 B
Expand Down
2 changes: 1 addition & 1 deletion packages/size-limit/test/__snapshots__/run.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ exports[`shows debug 1`] = `
"size": 123,
"loadTime": 0.01,
"runTime": 1,
"time": 1.01,
"totalTime": 1.01,
"passed": true
}
],
Expand Down
49 changes: 37 additions & 12 deletions packages/size-limit/test/create-reporter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ it('renders results', () => {
name: 'limitless',
runTime: 0.5,
size: 10,
time: 0.6
totalTime: 0.6
},
{
loadTime: 1,
Expand All @@ -40,7 +40,7 @@ it('renders results', () => {
runTime: 2,
size: 102400,
sizeLimit: 102400,
time: 3
totalTime: 3
},
{
gzip: false,
Expand All @@ -49,8 +49,8 @@ it('renders results', () => {
passed: true,
runTime: 2,
size: 102400,
time: 3,
timeLimit: 4
timeLimit: 4,
totalTime: 3
}
]
})
Expand All @@ -69,7 +69,7 @@ it('renders list of success checks in silent mode', () => {
name: 'limitless',
runTime: 0.5,
size: 10,
time: 0.6
totalTime: 0.6
},
{
loadTime: 1,
Expand All @@ -78,7 +78,7 @@ it('renders list of success checks in silent mode', () => {
runTime: 2,
size: 102400,
sizeLimit: 102400,
time: 3
totalTime: 3
}
]
},
Expand Down Expand Up @@ -132,7 +132,7 @@ it('renders list of failed and success checks in silent mode', () => {
name: 'limitless',
runTime: 0.5,
size: 10,
time: 0.6
totalTime: 0.6
},
{
loadTime: 1,
Expand All @@ -141,7 +141,7 @@ it('renders list of failed and success checks in silent mode', () => {
runTime: 2,
size: 102400,
sizeLimit: 102400,
time: 3
totalTime: 3
},
{
name: 'big fail',
Expand Down Expand Up @@ -291,8 +291,8 @@ it('renders config-less result', () => {
passed: false,
runTime: 0.3,
size: 1000,
time: 0.5,
timeLimit: 0.5
timeLimit: 0.5,
totalTime: 0.5
}
],
failed: true
Expand All @@ -317,8 +317,8 @@ it('renders JSON results', () => {
path: '/b',
runTime: 0.3,
size: 1000,
time: 0.5,
timeLimit: 10
timeLimit: 10,
totalTime: 0.5
}
],
failed: true
Expand Down Expand Up @@ -372,3 +372,28 @@ it('renders Webpack stats help message', () => {
})
).toMatchSnapshot()
})

it('renders loading time with custom message from time options for every check', () => {
expect(
results(['time'], {
checks: [
{
loadTime: 0.2,
name: 'loading message 1',
passed: true,
runTime: 0.4,
size: 10,
time: { loadingMessage: 'for ~1000 users per month' },
totalTime: 1.4
},
{
loadTime: 0.2,
name: 'loading message 2',
passed: true,
runTime: 0.3,
time: { loadingMessage: '' }
}
]
})
).toMatchSnapshot()
})
42 changes: 42 additions & 0 deletions packages/size-limit/test/get-config.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,48 @@ it('normalizes import', async () => {
})
})

it('normalizes networkSpeed option for time plugin', async () => {
let cwd = 'time-network-speed'
expect(await check(cwd)).toEqual({
checks: [
{
files: [fixture(cwd, 'index.js')],
name: 'index.js',
path: 'index.js',
time: { networkSpeed: 20 }
},
{
files: [fixture(cwd, 'index.js')],
name: 'index.js',
time: { networkSpeed: 20000 }
}
],
configPath: 'package.json',
cwd: fixture(cwd)
})
})

it('normalizes latency option for time plugin', async () => {
let cwd = 'time-latency'
expect(await check(cwd)).toEqual({
checks: [
{
files: [fixture(cwd, 'index.js')],
name: 'index.js',
path: 'index.js',
time: { latency: 0.2 }
},
{
files: [fixture(cwd, 'index.js')],
name: 'index.js',
time: { latency: 2.35 }
}
],
configPath: 'package.json',
cwd: fixture(cwd)
})
})

it('takes config from CLI config argument', async () => {
let cwd = 'config-file-from-arg'
let configPath = 'src/configs/my-size-limit.config.js'
Expand Down
Loading

0 comments on commit edda423

Please sign in to comment.