Skip to content
This repository has been archived by the owner on Oct 6, 2023. It is now read-only.

Commit

Permalink
feat(server): reuse workers
Browse files Browse the repository at this point in the history
This greatly improves watch mode performance
  • Loading branch information
Akryum committed Dec 9, 2021
1 parent 53bc14a commit ac57eba
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 23 deletions.
14 changes: 11 additions & 3 deletions packages/peeky-runner/src/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ export async function setupRunner (options: RunnerOptions) {
eventHandlers.push(handler)
}

async function runTestFile (relativePath: string) {
function clearEventListeners () {
eventHandlers.length = 0
}

async function runTestFile (relativePath: string, clearDeps: string[] = []) {
const file = testFiles.files[relativePath]
if (file) {
const result = await runTestFileWorker({
Expand All @@ -92,6 +96,7 @@ export async function setupRunner (options: RunnerOptions) {
root: ctx.options.config.targetDirectory,
ignored: [...ctx.options.config.match ?? [], ...ctx.options.config.ignored ?? []],
},
clearDeps,
})

// Patch filePath
Expand All @@ -106,16 +111,19 @@ export async function setupRunner (options: RunnerOptions) {
async function close () {
await testFiles.destroy()
await pool.terminate()
eventHandlers.length = 0
clearEventListeners()
}

return {
testFiles,
runTestFile,
close,
onEvent,
clearEventListeners,
pool,
}
}

export type RunTestFileResult = Awaited<ReturnType<Awaited<ReturnType<typeof setupRunner>>['runTestFile']>>
export type Runner = Awaited<ReturnType<typeof setupRunner>>

export type RunTestFileResult = Awaited<ReturnType<Runner['runTestFile']>>
3 changes: 3 additions & 0 deletions packages/peeky-runner/src/runtime/module-cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import type { ViteExecutionResult } from './vite.js'

export const moduleCache: Map<string, Promise<ViteExecutionResult>> = new Map()
2 changes: 2 additions & 0 deletions packages/peeky-runner/src/runtime/run-test-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ import { getCoverage } from './coverage.js'
import { mockedModules } from './mocked-files.js'
import { getTestEnvironment, NodeEnvironment } from './environment.js'
import { createMockedFileSystem } from './fs.js'
import { moduleCache } from './module-cache.js'

export async function runTestFile (options: RunTestFileOptions) {
try {
const time = performance.now()
options.clearDeps.forEach(file => moduleCache.delete(file))

const source = await fs.readFile(options.entry, { encoding: 'utf8' })

Expand Down
12 changes: 6 additions & 6 deletions packages/peeky-runner/src/runtime/vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ import { isEqual } from 'lodash-es'
import match from 'anymatch'
import { ModuleFilterOption } from '@peeky/config'
import { slash } from '@peeky/utils'
import { moduleCache } from './module-cache.js'
import { mockedModules } from './mocked-files.js'
import { createPeekyGlobal } from '../index.js'

let viteServer: ViteDevServer
let initPromise: Promise<void>
const moduleCache: Map<string, Promise<ViteExecutionResult>> = new Map()

export interface InitViteServerOptions {
defaultConfig: InlineConfig
Expand Down Expand Up @@ -147,12 +147,12 @@ function cachedRequest (rawId: string, callstack: string[], deps: Set<string>, e
return import(realPath)
}

if (moduleCache.has(id)) {
return moduleCache.get(id)
if (moduleCache.has(realPath)) {
return moduleCache.get(realPath)
}

const promise = rawRequest(id, realPath, callstack, deps, executionContext, root)
moduleCache.set(id, promise)
const promise = rawRequest(realPath, realPath, callstack, deps, executionContext, root)
moduleCache.set(realPath, promise)
return promise
}

Expand All @@ -171,7 +171,7 @@ async function rawRequest (id: string, realPath: string, callstack: string[], de
callstack = [...callstack, id]
const request = async (dep: string) => {
if (callstack.includes(dep)) {
const cacheKey = toFilePath(dep, root)
const cacheKey = toFilePath(normalizeId(dep), root)
if (!moduleCache.has(cacheKey)) {
throw new Error(`${chalk.red('Circular dependency detected')}\nStack:\n${[...callstack, dep].reverse().map((i) => {
const path = relative(viteServer.config.root, toFilePath(normalizeId(i), root))
Expand Down
1 change: 1 addition & 0 deletions packages/peeky-runner/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export interface RunTestFileOptions {
entry: string
config: PeekyConfig
coverage: CoverageOptions
clearDeps?: string[]
}

export interface CoverageOptions {
Expand Down
27 changes: 13 additions & 14 deletions packages/peeky-server/src/schema/Run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { fileURLToPath } from 'url'
import { performance } from 'perf_hooks'
import { arg, extendType, idArg, inputObjectType, nonNull, objectType } from 'nexus'
import shortid from 'shortid'
import { setupRunner, getStats, EventType } from '@peeky/runner'
import { setupRunner, getStats, EventType, Runner } from '@peeky/runner'
import nameGenerator from 'project-name-generator'
import randomEmoji from 'random-emoji'
import objectInspect from 'object-inspect'
Expand Down Expand Up @@ -223,6 +223,8 @@ export async function updateRun (ctx: Context, id: string, data: Partial<Omit<Ru
return run
}

let runner: Runner

export async function startRun (ctx: Context, id: string) {
const run = await getRun(ctx, id)

Expand All @@ -232,19 +234,16 @@ export async function startRun (ctx: Context, id: string) {
}))

const time = performance.now()
const runner = await setupRunner({
config: ctx.config,
testFiles: ctx.reactiveFs,
})
if (!runner) {
runner = await setupRunner({
config: ctx.config,
testFiles: ctx.reactiveFs,
})
} else {
runner.clearEventListeners()
}
runner.onEvent(async (eventType, payload) => {
if (eventType === EventType.BUILD_COMPLETED) {
const { testFilePath, duration } = payload
const testFileId = relative(ctx.config.targetDirectory, testFilePath)
const runTestFileId = run.runTestFiles.find(rf => rf.testFile.id === testFileId)?.id
updateRunTestFile(ctx, run.id, runTestFileId, {
buildDuration: duration,
})
} else if (eventType === EventType.SUITE_START) {
if (eventType === EventType.SUITE_START) {
const { suite } = payload
const testFileId = relative(ctx.config.targetDirectory, suite.filePath)
createTestSuite(ctx, {
Expand Down Expand Up @@ -298,7 +297,7 @@ export async function startRun (ctx: Context, id: string) {

const results = await Promise.all(run.runTestFiles.map(async f => {
try {
const result = await runner.runTestFile(f.testFile.relativePath)
const result = await runner.runTestFile(f.testFile.relativePath, f.testFile.modules)
const stats = getStats([result])
const status: StatusEnum = !stats.testCount ? 'skipped' : stats.errorTestCount > 0 ? 'error' : 'success'
await updateTestFile(ctx, f.testFile.id, {
Expand Down

0 comments on commit ac57eba

Please sign in to comment.