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

perf: improve performance of forks pool #5592

Merged
merged 10 commits into from
May 1, 2024
Prev Previous commit
Next Next commit
perf: improve performance of forks pool
  • Loading branch information
sheremet-va committed May 1, 2024
commit 1adaf88ede3e8dc05c539ff11e4762a85221f322
8 changes: 7 additions & 1 deletion packages/vitest/src/integrations/env/loader.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { readFileSync } from 'node:fs'
import { normalize, resolve } from 'pathe'
import { ViteNodeRunner } from 'vite-node/client'
import type { ViteNodeRunnerOptions } from 'vite-node'
Expand Down Expand Up @@ -26,7 +27,12 @@ export async function loadEnvironment(ctx: ContextRPC, rpc: WorkerRPC): Promise<
return environments[name]
const loader = await createEnvironmentLoader({
root: ctx.config.root,
fetchModule: id => rpc.fetch(id, 'ssr'),
fetchModule: async (id) => {
const result = await rpc.fetch(id, 'ssr')
if (result.id)
return { code: readFileSync(result.id, 'utf-8') }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why using sync IO in async context? 🤔

Copy link
Member Author

@sheremet-va sheremet-va May 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because it’s faster. we rarely import multiple modules at the same time, so nothing is executed in parallel most of the time

return result
},
resolveId: (id, importer) => rpc.resolveId(id, importer, 'ssr'),
})
const root = loader.root
Expand Down
35 changes: 33 additions & 2 deletions packages/vitest/src/node/pools/rpc.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { mkdir, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import type { RawSourceMap } from 'vite-node'
import { join } from 'pathe'
import type { RuntimeRPC } from '../../types'
import type { WorkspaceProject } from '../workspace'

const created = new Set()
const promises = new Map<string, Promise<void>>()

export function createMethodsRPC(project: WorkspaceProject): RuntimeRPC {
const ctx = project.ctx
return {
Expand All @@ -20,8 +26,33 @@ export function createMethodsRPC(project: WorkspaceProject): RuntimeRPC {
const r = await project.vitenode.transformRequest(id)
return r?.map as RawSourceMap | undefined
},
fetch(id, transformMode) {
return project.vitenode.fetchModule(id, transformMode)
async fetch(id, transformMode) {
AriPerkkio marked this conversation as resolved.
Show resolved Hide resolved
const result = await project.vitenode.fetchModule(id, transformMode)
if (result.externalize)
return result
if (!result.code && 'id' in result)
return result

if (!result.code) {
console.error(result)
return { code: `throw new Error('What is going on?')` }
}
const code = result.code
const dir = join(tmpdir(), transformMode)
sheremet-va marked this conversation as resolved.
Show resolved Hide resolved
const tmp = join(dir, id.replace(/[\s/\\]/g, '_'))
if (promises.has(tmp)) {
await promises.get(tmp)
return { id: tmp }
}
if (!created.has(dir)) {
await mkdir(dir, { recursive: true })
created.add(dir)
}
promises.set(tmp, writeFile(tmp, code, 'utf-8').finally(() => promises.delete(tmp)))
await promises.get(tmp)
result.code = undefined
Object.assign(result, { id: tmp })
return { id: tmp }
AriPerkkio marked this conversation as resolved.
Show resolved Hide resolved
},
resolveId(id, importer, transformMode) {
return project.vitenode.resolveId(id, importer, transformMode)
Expand Down
8 changes: 7 additions & 1 deletion packages/vitest/src/runtime/execute.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import vm from 'node:vm'
import { pathToFileURL } from 'node:url'
import { readFileSync } from 'node:fs'
import type { ModuleCacheMap } from 'vite-node/client'
import { DEFAULT_REQUEST_STUBS, ViteNodeRunner } from 'vite-node/client'
import { isInternalRequest, isNodeBuiltin, isPrimitive, toFilePath } from 'vite-node/utils'
Expand Down Expand Up @@ -104,7 +105,12 @@ export async function startVitestExecutor(options: ContextExecutorOptions) {
return { externalize: id }
}

return rpc().fetch(id, getTransformMode())
const result = await rpc().fetch(id, getTransformMode())
if (result.id && !result.externalize) {
const code = readFileSync(result.id, 'utf-8')
return { code }
}
return result
},
resolveId(id, importer) {
return rpc().resolveId(id, importer, getTransformMode())
Expand Down
5 changes: 4 additions & 1 deletion packages/vitest/src/types/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import type { AfterSuiteRunMeta } from './worker'
type TransformMode = 'web' | 'ssr'

export interface RuntimeRPC {
fetch: (id: string, environment: TransformMode) => Promise<FetchResult>
fetch: (id: string, environment: TransformMode) => Promise<{
externalize?: string
id?: string
}>
transform: (id: string, environment: TransformMode) => Promise<FetchResult>
resolveId: (id: string, importer: string | undefined, environment: TransformMode) => Promise<ViteNodeResolveId | null>
getSourceMap: (id: string, force?: boolean) => Promise<RawSourceMap | undefined>
Expand Down