Skip to content

Commit

Permalink
feat(server): invalidate module with hmr (#10333)
Browse files Browse the repository at this point in the history
  • Loading branch information
bluwy committed Oct 14, 2022
1 parent a9f9d31 commit 8328011
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 14 deletions.
5 changes: 5 additions & 0 deletions docs/guide/api-javascript.md
Expand Up @@ -119,6 +119,11 @@ interface ViteDevServer {
* Fix ssr error stacktrace.
*/
ssrFixStacktrace(e: Error): void
/**
* Triggers HMR for a module in the module graph. You can use the `server.moduleGraph`
* API to retrieve the module to be reloaded. If `hmr` is false, this is a no-op.
*/
reloadModule(module: ModuleNode): Promise<void>
/**
* Start the server.
*/
Expand Down
11 changes: 11 additions & 0 deletions packages/vite/src/node/server/index.ts
Expand Up @@ -65,6 +65,7 @@ import {
serveStaticMiddleware
} from './middlewares/static'
import { timeMiddleware } from './middlewares/time'
import type { ModuleNode } from './moduleGraph'
import { ModuleGraph } from './moduleGraph'
import { errorMiddleware, prepareError } from './middlewares/error'
import type { HmrOptions } from './hmr'
Expand Down Expand Up @@ -245,6 +246,11 @@ export interface ViteDevServer {
* Mutates the given SSR error by rewriting the stacktrace
*/
ssrFixStacktrace(e: Error): void
/**
* Triggers HMR for a module in the module graph. You can use the `server.moduleGraph`
* API to retrieve the module to be reloaded. If `hmr` is false, this is a no-op.
*/
reloadModule(module: ModuleNode): Promise<void>
/**
* Start the server.
*/
Expand Down Expand Up @@ -382,6 +388,11 @@ export async function createServer(
ssrRewriteStacktrace(stack: string) {
return ssrRewriteStacktrace(stack, moduleGraph)
},
async reloadModule(module) {
if (serverConfig.hmr !== false && module.file) {
updateModules(module.file, [module], Date.now(), server)
}
},
async listen(port?: number, isRestart?: boolean) {
await startServer(server, port, isRestart)
if (httpServer) {
Expand Down
14 changes: 13 additions & 1 deletion playground/hmr/__tests__/hmr.spec.ts
Expand Up @@ -651,11 +651,23 @@ if (!isBuild) {
test('handle virtual module updates', async () => {
await page.goto(viteTestUrl)
const el = await page.$('.virtual')
expect(await el.textContent()).toBe('[success]')
expect(await el.textContent()).toBe('[success]0')
editFile('importedVirtual.js', (code) => code.replace('[success]', '[wow]'))
await untilUpdated(async () => {
const el = await page.$('.virtual')
return await el.textContent()
}, '[wow]')
})

test('invalidate virtual module', async () => {
await page.goto(viteTestUrl)
const el = await page.$('.virtual')
expect(await el.textContent()).toBe('[wow]0')
const btn = await page.$('.virtual-update')
btn.click()
await untilUpdated(async () => {
const el = await page.$('.virtual')
return await el.textContent()
}, '[wow]1')
})
}
7 changes: 7 additions & 0 deletions playground/hmr/hmr.ts
Expand Up @@ -10,6 +10,13 @@ text('.dep', depFoo)
text('.nested', nestedFoo)
text('.virtual', virtual)

const btn = document.querySelector('.virtual-update') as HTMLButtonElement
btn.onclick = () => {
if (import.meta.hot) {
import.meta.hot.send('virtual:increment')
}
}

if (import.meta.hot) {
import.meta.hot.accept(({ foo }) => {
console.log('(self-accepting 1) foo is now:', foo)
Expand Down
2 changes: 2 additions & 0 deletions playground/hmr/index.html
Expand Up @@ -5,6 +5,8 @@
href="./global.css?param=required"
/>
</div>
<button class="virtual-update">update virtual module</button>

<script type="module" src="./hmr.ts"></script>
<style>
.import-image {
Expand Down
44 changes: 31 additions & 13 deletions playground/hmr/vite.config.ts
@@ -1,4 +1,5 @@
import { defineConfig } from 'vite'
import type { Plugin } from 'vite'

export default defineConfig({
experimental: {
Expand All @@ -20,18 +21,35 @@ export default defineConfig({
})
}
},
{
name: 'virtual-file',
resolveId(id) {
if (id === 'virtual:file') {
return '\0virtual:file'
}
},
load(id) {
if (id === '\0virtual:file') {
return 'import { virtual } from "/importedVirtual.js"; export { virtual };'
}
}
}
virtualPlugin()
]
})

function virtualPlugin(): Plugin {
let num = 0
return {
name: 'virtual-file',
resolveId(id) {
if (id === 'virtual:file') {
return '\0virtual:file'
}
},
load(id) {
if (id === '\0virtual:file') {
return `\
import { virtual as _virtual } from "/importedVirtual.js";
export const virtual = _virtual + '${num}';`
}
},
configureServer(server) {
server.ws.on('virtual:increment', async () => {
const mod = await server.moduleGraph.getModuleByUrl('\0virtual:file')
console.log(mod)
if (mod) {
num++
server.reloadModule(mod)
}
})
}
}
}

0 comments on commit 8328011

Please sign in to comment.