[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
12

Configure Feed

Select the types of activity you want to include in your feed.

fix(vite-node): correctly return cached result (#4870)

authored by

Vladimir and committed by
GitHub
(Jan 4, 2024, 5:40 PM +0100) 15bbbf81 6088b372

+205 -13
+4
test/vite-node/vitest.config.ts
··· 4 4 test: { 5 5 clearMocks: true, 6 6 testTimeout: process.env.CI ? 120_000 : 5_000, 7 + onConsoleLog(log) { 8 + if (log.includes('Port is already')) 9 + return false 10 + }, 7 11 }, 8 12 })
+9 -3
packages/vite-node/src/server.ts
··· 211 211 212 212 const { path: filePath } = toFilePath(id, this.server.config.root) 213 213 214 - const module = this.server.moduleGraph.getModuleById(id) 215 - const timestamp = module ? module.lastHMRTimestamp : null 214 + const moduleNode = this.server.moduleGraph.getModuleById(id) || this.server.moduleGraph.getModuleById(filePath) 216 215 const cache = this.fetchCaches[transformMode].get(filePath) 217 - if (timestamp && cache && cache.timestamp >= timestamp) 216 + 217 + // lastUpdateTimestamp is the timestamp that marks the last time the module was changed 218 + // if lastUpdateTimestamp is 0, then the module was not changed since the server started 219 + // we test "timestamp === 0" for expressiveness, but it's not necessary 220 + const timestamp = moduleNode 221 + ? Math.max(moduleNode.lastHMRTimestamp, moduleNode.lastInvalidationTimestamp) 222 + : 0 223 + if (cache && (timestamp === 0 || cache.timestamp >= timestamp)) 218 224 return cache.result 219 225 220 226 const time = Date.now()
+192 -10
test/vite-node/test/server.test.ts
··· 1 - import { resolve } from 'pathe' 1 + import { join, resolve } from 'pathe' 2 2 import { ViteNodeServer } from 'vite-node/server' 3 3 import { describe, expect, test, vi } from 'vitest' 4 - import { createServer } from 'vite' 4 + import { type Plugin, type ViteDevServer, createServer } from 'vite' 5 5 import { extractSourceMap } from '../../../packages/vite-node/src/source-map' 6 6 7 7 describe('server works correctly', async () => { ··· 29 29 await vnServer.resolveId('/ssr', '/ssr path') 30 30 expect(resolveId).toHaveBeenCalledWith('/ssr', '/ssr path', { ssr: true }) 31 31 }) 32 - test('fetchModule with id, and got sourcemap source in absolute path', async () => { 33 - const server = await createServer({ 34 - logLevel: 'error', 35 - root: resolve(__dirname, '../'), 36 - }) 37 - const vnServer = new ViteNodeServer(server) 32 + }) 38 33 39 - // fetchModule in not a valid filesystem path 40 - const fetchResult = await vnServer.fetchModule('/src/foo.js') 34 + const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)) 35 + 36 + describe('server correctly caches data', () => { 37 + const it = test.extend<{ 38 + root: string 39 + plugin: Plugin 40 + ssrFiles: string[] 41 + webFiles: string[] 42 + server: ViteDevServer 43 + viteNode: ViteNodeServer 44 + }>({ 45 + ssrFiles: async ({}, use) => { 46 + await use([]) 47 + }, 48 + webFiles: async ({}, use) => { 49 + await use([]) 50 + }, 51 + root: resolve(__dirname, '../'), 52 + plugin: async ({ ssrFiles, webFiles }, use) => { 53 + const plugin: Plugin = { 54 + name: 'test', 55 + transform(code, id, options) { 56 + // this should be called only once if cached is configured correctly 57 + if (options?.ssr) 58 + ssrFiles.push(id) 59 + else 60 + webFiles.push(id) 61 + }, 62 + } 63 + await use(plugin) 64 + }, 65 + server: async ({ root, plugin }, use) => { 66 + const server = await createServer({ 67 + configFile: false, 68 + root, 69 + server: { 70 + middlewareMode: true, 71 + watch: null, 72 + }, 73 + optimizeDeps: { 74 + disabled: true, 75 + }, 76 + plugins: [plugin], 77 + }) 78 + await use(server) 79 + await server.close() 80 + }, 81 + viteNode: async ({ server }, use) => { 82 + const vnServer = new ViteNodeServer(server) 83 + await use(vnServer) 84 + }, 85 + }) 86 + 87 + it('fetchModule with id, and got sourcemap source in absolute path', async ({ viteNode }) => { 88 + const fetchResult = await viteNode.fetchModule('/src/foo.js') 41 89 42 90 const sourceMap = extractSourceMap(fetchResult.code!) 43 91 44 92 // expect got sourcemap source in a valid filesystem path 45 93 expect(sourceMap?.sources[0]).toBe('foo.js') 94 + }) 95 + 96 + it('correctly returns cached and invalidated ssr modules', async ({ root, viteNode, ssrFiles, webFiles, server }) => { 97 + await viteNode.fetchModule('/src/foo.js', 'ssr') 98 + 99 + const fsPath = join(root, './src/foo.js') 100 + 101 + expect(viteNode.fetchCaches.web.has(fsPath)).toBe(false) 102 + expect(viteNode.fetchCache.has(fsPath)).toBe(true) 103 + expect(viteNode.fetchCaches.ssr.has(fsPath)).toBe(true) 104 + 105 + expect(webFiles).toHaveLength(0) 106 + expect(ssrFiles).toHaveLength(1) 107 + expect(ssrFiles).toContain(fsPath) 108 + 109 + await viteNode.fetchModule('/src/foo.js', 'ssr') 110 + 111 + expect(ssrFiles).toHaveLength(1) 112 + 113 + server.moduleGraph.invalidateModule( 114 + server.moduleGraph.getModuleById(fsPath)!, 115 + new Set(), 116 + Date.now(), 117 + false, 118 + ) 119 + 120 + // wait so TS are different 121 + await wait(10) 122 + 123 + await viteNode.fetchModule('/src/foo.js', 'ssr') 124 + 125 + expect(ssrFiles).toHaveLength(2) 126 + 127 + // another fetch after invalidation returns cached result 128 + await viteNode.fetchModule('/src/foo.js', 'ssr') 129 + 130 + expect(ssrFiles).toHaveLength(2) 131 + 132 + server.moduleGraph.invalidateModule( 133 + server.moduleGraph.getModuleById(fsPath)!, 134 + new Set(), 135 + Date.now(), 136 + true, 137 + ) 138 + 139 + // wait so TS are different 140 + await wait(10) 141 + 142 + await viteNode.fetchModule('/src/foo.js', 'ssr') 143 + 144 + expect(ssrFiles).toHaveLength(3) 145 + 146 + // another fetch after invalidation returns cached result 147 + await viteNode.fetchModule('/src/foo.js', 'ssr') 148 + 149 + expect(ssrFiles).toHaveLength(3) 150 + expect(webFiles).toHaveLength(0) 151 + }) 152 + 153 + it('correctly returns cached and invalidated web modules', async ({ root, viteNode, webFiles, ssrFiles, server }) => { 154 + await viteNode.fetchModule('/src/foo.js', 'web') 155 + 156 + const fsPath = join(root, './src/foo.js') 157 + 158 + expect(viteNode.fetchCaches.ssr.has(fsPath)).toBe(false) 159 + expect(viteNode.fetchCache.has(fsPath)).toBe(true) 160 + expect(viteNode.fetchCaches.web.has(fsPath)).toBe(true) 161 + 162 + expect(ssrFiles).toHaveLength(0) 163 + expect(webFiles).toHaveLength(1) 164 + expect(webFiles).toContain(fsPath) 165 + 166 + await viteNode.fetchModule('/src/foo.js', 'web') 167 + 168 + expect(webFiles).toHaveLength(1) 169 + 170 + server.moduleGraph.invalidateModule( 171 + server.moduleGraph.getModuleById(fsPath)!, 172 + new Set(), 173 + Date.now(), 174 + false, 175 + ) 176 + 177 + // wait so TS are different 178 + await wait(10) 179 + 180 + await viteNode.fetchModule('/src/foo.js', 'web') 181 + 182 + expect(webFiles).toHaveLength(2) 183 + 184 + // another fetch after invalidation returns cached result 185 + await viteNode.fetchModule('/src/foo.js', 'web') 186 + 187 + expect(webFiles).toHaveLength(2) 188 + 189 + server.moduleGraph.invalidateModule( 190 + server.moduleGraph.getModuleById(fsPath)!, 191 + new Set(), 192 + Date.now(), 193 + true, 194 + ) 195 + 196 + // wait so TS are different 197 + await wait(10) 198 + 199 + await viteNode.fetchModule('/src/foo.js', 'web') 200 + 201 + expect(webFiles).toHaveLength(3) 202 + 203 + // another fetch after invalidation returns cached result 204 + await viteNode.fetchModule('/src/foo.js', 'web') 205 + 206 + expect(webFiles).toHaveLength(3) 207 + expect(ssrFiles).toHaveLength(0) 208 + }) 209 + 210 + it('correctly processes the same file with both transform modes', async ({ viteNode, ssrFiles, webFiles, root }) => { 211 + await viteNode.fetchModule('/src/foo.js', 'ssr') 212 + await viteNode.fetchModule('/src/foo.js', 'web') 213 + 214 + const fsPath = join(root, './src/foo.js') 215 + 216 + expect(viteNode.fetchCaches.ssr.has(fsPath)).toBe(true) 217 + expect(viteNode.fetchCache.has(fsPath)).toBe(true) 218 + expect(viteNode.fetchCaches.web.has(fsPath)).toBe(true) 219 + 220 + expect(ssrFiles).toHaveLength(1) 221 + expect(webFiles).toHaveLength(1) 222 + 223 + await viteNode.fetchModule('/src/foo.js', 'ssr') 224 + await viteNode.fetchModule('/src/foo.js', 'web') 225 + 226 + expect(ssrFiles).toHaveLength(1) 227 + expect(webFiles).toHaveLength(1) 46 228 }) 47 229 })