Skip to content

Commit 80a43d5

Browse files
authored
fix(browser): inline pretty-format and replace picocolors with tinyrainbow (#6077)
1 parent 7f0cc24 commit 80a43d5

File tree

108 files changed

+2218
-415
lines changed

Some content is hidden

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

108 files changed

+2218
-415
lines changed

docs/config/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2181,7 +2181,7 @@ Path to a diff config that will be used to generate diff interface. Useful if yo
21812181
:::code-group
21822182
```ts [vitest.diff.ts]
21832183
import type { DiffOptions } from 'vitest'
2184-
import c from 'picocolors'
2184+
import c from 'tinyrainbow'
21852185

21862186
export default {
21872187
aIndicator: c.bold('--'),

packages/browser/package.json

+3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
"types": "./context.d.ts",
2929
"default": "./context.js"
3030
},
31+
"./client": {
32+
"default": "./dist/client.js"
33+
},
3134
"./matchers": {
3235
"types": "./matchers.d.ts"
3336
},

packages/browser/rollup.config.js

+15
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,21 @@ export default () =>
5757
}),
5858
],
5959
},
60+
{
61+
input: './src/client/client.ts',
62+
output: {
63+
file: 'dist/client.js',
64+
format: 'esm',
65+
},
66+
plugins: [
67+
resolve({
68+
preferBuiltins: true,
69+
}),
70+
esbuild({
71+
target: 'node18',
72+
}),
73+
],
74+
},
6075
{
6176
input: './src/client/tester/state.ts',
6277
output: {

packages/browser/src/client/client.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { getBrowserState } from './utils'
66

77
const PAGE_TYPE = getBrowserState().type
88

9-
export const PORT = import.meta.hot ? '51204' : location.port
9+
export const PORT = location.port
1010
export const HOST = [location.hostname, PORT].filter(Boolean).join(':')
1111
export const SESSION_ID
1212
= PAGE_TYPE === 'orchestrator'
@@ -136,4 +136,4 @@ function createClient() {
136136

137137
export const client = createClient()
138138

139-
export { channel, waitForChannel } from './channel'
139+
export * from './channel'

packages/browser/src/client/orchestrator.html

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
height: 100%;
2424
}
2525
</style>
26-
<script>{__VITEST_INJECTOR__}</script>
26+
{__VITEST_INJECTOR__}
27+
{__VITEST_ERROR_CATCHER__}
2728
{__VITEST_SCRIPTS__}
2829
</head>
2930
<body>

packages/browser/src/client/orchestrator.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type { ResolvedConfig } from 'vitest'
2+
import { channel, client } from '@vitest/browser/client'
23
import { generateHash } from '@vitest/runner/utils'
4+
import { type GlobalChannelIncomingEvent, type IframeChannelEvent, type IframeChannelIncomingEvent, globalChannel } from '@vitest/browser/client'
35
import { relative } from 'pathe'
4-
import { channel, client } from './client'
56
import { getBrowserState, getConfig } from './utils'
67
import { getUiAPI } from './ui'
7-
import { type GlobalChannelIncomingEvent, type IframeChannelEvent, type IframeChannelIncomingEvent, globalChannel } from './channel'
88
import { createModuleMocker } from './tester/msw'
99

1010
const url = new URL(location.href)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { channel, client } from '/@id/@vitest/browser/client'
2+
3+
function on(event, listener) {
4+
window.addEventListener(event, listener)
5+
return () => window.removeEventListener(event, listener)
6+
}
7+
8+
function serializeError(unhandledError) {
9+
if (typeof unhandledError !== 'object' || !unhandledError) {
10+
return {
11+
message: String(unhandledError),
12+
}
13+
}
14+
15+
return {
16+
name: unhandledError.name,
17+
message: unhandledError.message,
18+
stack: String(unhandledError.stack),
19+
}
20+
}
21+
22+
function catchWindowErrors(cb) {
23+
let userErrorListenerCount = 0
24+
function throwUnhandlerError(e) {
25+
if (userErrorListenerCount === 0 && e.error != null) {
26+
cb(e)
27+
}
28+
else {
29+
console.error(e.error)
30+
}
31+
}
32+
const addEventListener = window.addEventListener.bind(window)
33+
const removeEventListener = window.removeEventListener.bind(window)
34+
window.addEventListener('error', throwUnhandlerError)
35+
window.addEventListener = function (...args) {
36+
if (args[0] === 'error') {
37+
userErrorListenerCount++
38+
}
39+
return addEventListener.apply(this, args)
40+
}
41+
window.removeEventListener = function (...args) {
42+
if (args[0] === 'error' && userErrorListenerCount) {
43+
userErrorListenerCount--
44+
}
45+
return removeEventListener.apply(this, args)
46+
}
47+
return function clearErrorHandlers() {
48+
window.removeEventListener('error', throwUnhandlerError)
49+
}
50+
}
51+
52+
function registerUnexpectedErrors() {
53+
catchWindowErrors(event =>
54+
reportUnexpectedError('Error', event.error),
55+
)
56+
on('unhandledrejection', event =>
57+
reportUnexpectedError('Unhandled Rejection', event.reason))
58+
}
59+
60+
async function reportUnexpectedError(
61+
type,
62+
error,
63+
) {
64+
const processedError = serializeError(error)
65+
await client.rpc.onUnhandledError(processedError, type)
66+
const state = __vitest_browser_runner__
67+
68+
if (state.type === 'orchestrator') {
69+
return
70+
}
71+
72+
if (!state.runTests || !__vitest_worker__.current) {
73+
channel.postMessage({
74+
type: 'done',
75+
filenames: state.files,
76+
id: state.iframeId,
77+
})
78+
}
79+
}
80+
81+
registerUnexpectedErrors()

packages/browser/src/client/tester/context.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Task, WorkerGlobalState } from 'vitest'
2+
import type { BrowserRPC } from '@vitest/browser/client'
23
import type { BrowserPage, UserEvent, UserEventClickOptions, UserEventTabOptions, UserEventTypeOptions } from '../../../context'
34
import type { BrowserRunnerState } from '../utils'
4-
import type { BrowserRPC } from '../client'
55

66
// this file should not import anything directly, only types
77

packages/browser/src/client/tester/mocker.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { getType } from '@vitest/utils'
22
import { extname, join } from 'pathe'
3+
import type { IframeChannelOutgoingEvent } from '@vitest/browser/client'
4+
import { channel, waitForChannel } from '@vitest/browser/client'
35
import { getBrowserState, importId } from '../utils'
4-
import type { IframeChannelOutgoingEvent } from '../channel'
5-
import { channel, waitForChannel } from '../client'
66
import { rpc } from './rpc'
77

88
const now = Date.now

packages/browser/src/client/tester/msw.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1+
import { channel } from '@vitest/browser/client'
12
import type {
23
IframeChannelEvent,
34
IframeMockEvent,
45
IframeMockingDoneEvent,
56
IframeUnmockEvent,
6-
} from '../channel'
7-
import { channel } from '../channel'
7+
} from '@vitest/browser/client'
88

99
export function createModuleMocker() {
1010
const mocks: Map<string, string | null | undefined> = new Map()

packages/browser/src/client/tester/rpc.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { getSafeTimers } from 'vitest/utils'
2-
import type { VitestBrowserClient } from '../client'
2+
import type { VitestBrowserClient } from '@vitest/browser/client'
33

44
const { get } = Reflect
55

packages/browser/src/client/tester/runner.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { NodeBenchmarkRunner, VitestTestRunner } from 'vitest/runners'
55
import { loadDiffConfig, loadSnapshotSerializers, takeCoverageInsideWorker } from 'vitest/browser'
66
import { TraceMap, originalPositionFor } from 'vitest/utils'
77
import { page } from '@vitest/browser/context'
8+
import { globalChannel } from '@vitest/browser/client'
89
import { importFs, importId } from '../utils'
9-
import { globalChannel } from '../channel'
1010
import { VitestBrowserSnapshotEnvironment } from './snapshot'
1111
import { rpc } from './rpc'
1212
import type { VitestBrowserClientMocker } from './mocker'

packages/browser/src/client/tester/snapshot.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { SnapshotEnvironment } from 'vitest/snapshot'
22
import { type ParsedStack, TraceMap, originalPositionFor } from 'vitest/utils'
3-
import type { VitestBrowserClient } from '../client'
3+
import type { VitestBrowserClient } from '@vitest/browser/client'
44

55
export class VitestBrowserSnapshotEnvironment implements SnapshotEnvironment {
66
private sourceMaps = new Map<string, any>()

packages/browser/src/client/tester/state.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { WorkerGlobalState } from 'vitest'
22
import { parse } from 'flatted'
3+
import type { BrowserRPC } from '@vitest/browser/client'
34
import { getBrowserState } from '../utils'
4-
import type { BrowserRPC } from '../client'
55

66
const config = getBrowserState().config
77
const contextId = getBrowserState().contextId

packages/browser/src/client/tester/tester.html

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616
min-height: 100vh;
1717
}
1818
</style>
19-
<script>{__VITEST_INJECTOR__}</script>
19+
{__VITEST_INJECTOR__}
2020
<script>{__VITEST_STATE__}</script>
21+
{__VITEST_ERROR_CATCHER__}
2122
{__VITEST_SCRIPTS__}
2223
</head>
2324
<body

packages/browser/src/client/tester/tester.ts

+6-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
import { SpyModule, collectTests, setupCommonEnv, startTests } from 'vitest/browser'
2+
import { channel, client, onCancel } from '@vitest/browser/client'
23
import { getBrowserState, getConfig, getWorkerState } from '../utils'
3-
import { channel, client, onCancel } from '../client'
44
import { setupDialogsSpy } from './dialog'
5-
import {
6-
registerUnexpectedErrors,
7-
serializeError,
8-
} from './unhandled'
95
import { setupConsoleLogSpy } from './logger'
106
import { createSafeRpc } from './rpc'
117
import { browserHashMap, initiateRunner } from './runner'
@@ -59,8 +55,6 @@ async function prepareTestEnvironment(files: string[]) {
5955
runner.onCancel?.(reason)
6056
})
6157

62-
registerUnexpectedErrors(rpc)
63-
6458
return {
6559
runner,
6660
config,
@@ -92,7 +86,11 @@ async function executeTests(method: 'run' | 'collect', files: string[]) {
9286
}
9387
catch (error: any) {
9488
debug('runner cannot be loaded because it threw an error', error.stack || error.message)
95-
await client.rpc.onUnhandledError(serializeError(error), 'Preload Error')
89+
await client.rpc.onUnhandledError({
90+
name: error.name,
91+
message: error.message,
92+
stack: String(error.stack),
93+
}, 'Preload Error')
9694
done(files)
9795
return
9896
}

packages/browser/src/client/tester/unhandled.ts

+15-10
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1-
import { processError } from 'vitest/browser'
2-
import type { client } from '../client'
1+
import { client } from '@vitest/browser/client'
32

43
function on(event: string, listener: (...args: any[]) => void) {
54
window.addEventListener(event, listener)
65
return () => window.removeEventListener(event, listener)
76
}
87

9-
export function serializeError(unhandledError: any) {
8+
function serializeError(unhandledError: any) {
9+
if (typeof unhandledError !== 'object' || !unhandledError) {
10+
return {
11+
message: String(unhandledError),
12+
}
13+
}
14+
1015
return {
11-
...unhandledError,
1216
name: unhandledError.name,
1317
message: unhandledError.message,
1418
stack: String(unhandledError.stack),
@@ -49,19 +53,20 @@ function catchWindowErrors(cb: (e: ErrorEvent) => void) {
4953
}
5054
}
5155

52-
export function registerUnexpectedErrors(rpc: typeof client.rpc) {
56+
function registerUnexpectedErrors() {
5357
catchWindowErrors(event =>
54-
reportUnexpectedError(rpc, 'Error', event.error),
58+
reportUnexpectedError('Error', event.error),
5559
)
5660
on('unhandledrejection', event =>
57-
reportUnexpectedError(rpc, 'Unhandled Rejection', event.reason))
61+
reportUnexpectedError('Unhandled Rejection', event.reason))
5862
}
5963

6064
async function reportUnexpectedError(
61-
rpc: typeof client.rpc,
6265
type: string,
6366
error: any,
6467
) {
65-
const processedError = processError(error)
66-
await rpc.onUnhandledError(processedError, type)
68+
const processedError = serializeError(error)
69+
await client.rpc.onUnhandledError(processedError, type)
6770
}
71+
72+
registerUnexpectedErrors()

packages/browser/src/client/vite.config.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,13 @@ export default defineConfig({
2222
orchestrator: resolve(__dirname, './orchestrator.html'),
2323
tester: resolve(__dirname, './tester/tester.html'),
2424
},
25-
external: [/^vitest\//, 'vitest', /^msw/, '@vitest/browser/context'],
25+
external: [
26+
/^vitest\//,
27+
'vitest',
28+
/^msw/,
29+
'@vitest/browser/context',
30+
'@vitest/browser/client',
31+
],
2632
},
2733
},
2834
plugins: [

packages/browser/src/node/plugin.ts

+1-6
Original file line numberDiff line numberDiff line change
@@ -178,20 +178,15 @@ export default (browserServer: BrowserServer, base = '/'): Plugin[] => {
178178
'std-env',
179179
'tinybench',
180180
'tinyspy',
181+
'tinyrainbow',
181182
'pathe',
182183
'msw',
183184
'msw/browser',
184185
],
185186
include: [
186-
'vitest > @vitest/utils > pretty-format',
187-
'vitest > @vitest/snapshot > pretty-format',
188187
'vitest > @vitest/snapshot > magic-string',
189-
'vitest > pretty-format',
190-
'vitest > pretty-format > ansi-styles',
191-
'vitest > pretty-format > ansi-regex',
192188
'vitest > chai',
193189
'vitest > chai > loupe',
194-
'vitest > @vitest/utils > diff-sequences',
195190
'vitest > @vitest/utils > loupe',
196191
'@vitest/browser > @testing-library/user-event',
197192
'@vitest/browser > @testing-library/dom',

packages/browser/src/node/server.ts

+5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export class BrowserServer implements IBrowserServer {
2828
public testerHtml: Promise<string> | string
2929
public orchestratorHtml: Promise<string> | string
3030
public injectorJs: Promise<string> | string
31+
public errorCatcherJs: Promise<string> | string
3132
public stateJs: Promise<string> | string
3233

3334
public state: BrowserServerState
@@ -86,6 +87,10 @@ export class BrowserServer implements IBrowserServer {
8687
resolve(distRoot, 'client/esm-client-injector.js'),
8788
'utf8',
8889
).then(js => (this.injectorJs = js))
90+
this.errorCatcherJs = readFile(
91+
resolve(distRoot, 'client/error-catcher.js'),
92+
'utf8',
93+
).then(js => (this.errorCatcherJs = js))
8994
this.stateJs = readFile(
9095
resolve(distRoot, 'state.js'),
9196
'utf-8',

packages/browser/src/node/serverOrchestrator.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ export async function resolveOrchestrator(
5959
.replace(
6060
'<!-- !LOAD_METADATA! -->',
6161
[
62-
'<script>{__VITEST_INJECTOR__}</script>',
62+
'{__VITEST_INJECTOR__}',
63+
'{__VITEST_ERROR_CATCHER__}',
6364
'{__VITEST_SCRIPTS__}',
6465
`<script type="module" crossorigin src="${base}${jsEntry}"></script>`,
6566
].join('\n'),
@@ -70,7 +71,8 @@ export async function resolveOrchestrator(
7071
__VITEST_FAVICON__: server.faviconUrl,
7172
__VITEST_TITLE__: 'Vitest Browser Runner',
7273
__VITEST_SCRIPTS__: server.orchestratorScripts,
73-
__VITEST_INJECTOR__: injector,
74+
__VITEST_INJECTOR__: `<script type="module">${injector}</script>`,
75+
__VITEST_ERROR_CATCHER__: `<script type="module">${server.errorCatcherJs}</script>`,
7476
__VITEST_CONTEXT_ID__: JSON.stringify(contextId),
7577
})
7678
}

0 commit comments

Comments
 (0)