Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170import type { Rollup, ResolvedConfig as ViteConfig, ViteDevServer } from 'vite'import type { ServerIdResolution, ServerMockResolution } from '../types'import { existsSync, readFileSync } from 'node:fs'import { isAbsolute, join, resolve } from 'pathe'import { cleanUrl } from '../utils'import { findMockRedirect } from './redirect'
export interface ServerResolverOptions { /** * @default ['/node_modules/'] */ moduleDirectories?: string[]}
const VALID_ID_PREFIX = '/@id/'
export class ServerMockResolver { constructor( private server: ViteDevServer, private options: ServerResolverOptions = {}, ) {}
async resolveMock( rawId: string, importer: string, options: { mock: 'spy' | 'factory' | 'auto' }, ): Promise<ServerMockResolution> { const { id, fsPath, external } = await this.resolveMockId(rawId, importer) const resolvedUrl = this.normalizeResolveIdToUrl({ id }).url
if (options.mock === 'factory') { const manifest = getViteDepsManifest(this.server.config) const needsInterop = manifest?.[fsPath]?.needsInterop ?? false return { mockType: 'manual', resolvedId: id, resolvedUrl, needsInterop } }
if (options.mock === 'spy') { return { mockType: 'autospy', resolvedId: id, resolvedUrl } }
const redirectUrl = findMockRedirect(this.server.config.root, fsPath, external)
return { mockType: redirectUrl === null ? 'automock' : 'redirect', redirectUrl, resolvedId: id, resolvedUrl, } }
public invalidate(ids: string[]): void { ids.forEach((id) => { const moduleGraph = this.server.moduleGraph const module = moduleGraph.getModuleById(id) if (module) { module.transformResult = null } }) }
public async resolveId(id: string, importer?: string): Promise<ServerIdResolution | null> { const resolved = await this.server.environments.client.pluginContainer.resolveId(id, importer) if (!resolved) { return null } return this.normalizeResolveIdToUrl(resolved) }
private normalizeResolveIdToUrl(resolved: { id: string }) { const isOptimized = resolved.id.startsWith(withTrailingSlash(this.server.config.cacheDir)) let url: string // normalise the URL to be acceptable by the browser // https://github.com/vitejs/vite/blob/14027b0f2a9b01c14815c38aab22baf5b29594bb/packages/vite/src/node/plugins/importAnalysis.ts#L103 const root = this.server.config.root if (resolved.id.startsWith(withTrailingSlash(root))) { url = resolved.id.slice(root.length) } else if ( resolved.id !== '/@react-refresh' && isAbsolute(resolved.id) && existsSync(cleanUrl(resolved.id)) ) { url = join('/@fs/', resolved.id) } else { url = resolved.id } if (url[0] !== '.' && url[0] !== '/') { url = resolved.id.startsWith(VALID_ID_PREFIX) ? resolved.id : VALID_ID_PREFIX + resolved.id.replace('\0', '__x00__') } return { id: resolved.id, url, optimized: isOptimized, } }
private async resolveMockId(rawId: string, importer: string) { if ( !this.server.moduleGraph.getModuleById(importer) && !importer.startsWith(this.server.config.root) ) { importer = join(this.server.config.root, importer) } const resolved = await this.server.pluginContainer.resolveId(rawId, importer, { ssr: false, }) return this.resolveModule(rawId, resolved) }
private resolveModule(rawId: string, resolved: Rollup.PartialResolvedId | null) { const id = resolved?.id || rawId const external = !isAbsolute(id) || isModuleDirectory(this.options, id) ? rawId : null return { id, fsPath: cleanUrl(id), external, } }}
function isModuleDirectory(config: ServerResolverOptions, path: string) { const moduleDirectories = config.moduleDirectories || ['/node_modules/'] return moduleDirectories.some((dir: string) => path.includes(dir))}
interface PartialManifest { [name: string]: { hash: string needsInterop: boolean }}
const metadata = new WeakMap<ViteConfig, PartialManifest>()
function getViteDepsManifest(config: ViteConfig) { if (metadata.has(config)) { return metadata.get(config)! } const cacheDirPath = getDepsCacheDir(config) const metadataPath = resolve(cacheDirPath, '_metadata.json') if (!existsSync(metadataPath)) { return null } const { optimized } = JSON.parse(readFileSync(metadataPath, 'utf-8')) const newManifest: PartialManifest = {} for (const name in optimized) { const dep = optimized[name] const file = resolve(cacheDirPath, dep.file) newManifest[file] = { hash: dep.fileHash, needsInterop: dep.needsInterop, } } metadata.set(config, newManifest) return newManifest}
function getDepsCacheDir(config: ViteConfig): string { return resolve(config.cacheDir, 'deps')}
function withTrailingSlash(path: string): string { if (path.at(-1) !== '/') { return `${path}/` }
return path}