From eab49a4b7dd7e3bb0ff215c7e7937814cd63bb4f Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 8 May 2020 15:20:36 -0400 Subject: [PATCH] feat(hmr): change hmr API path to `vite/hmr` and provide typing Based on #92 --- README.md | 6 ++++-- hmr.d.ts | 12 ++++++++++++ package.json | 5 +++-- playground/testHmrManual.js | 2 +- src/node/server/index.ts | 2 +- src/node/server/serverPluginHmr.ts | 6 +++--- src/node/server/serverPluginModuleRewrite.ts | 18 +++++++++--------- 7 files changed, 33 insertions(+), 18 deletions(-) create mode 100644 hmr.d.ts diff --git a/README.md b/README.md index 1a726181b666db..10dcbefad45029 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ The above will throw an error by default. Vite detects such bare module imports ```js import { foo } from './foo.js' - import { hot } from '@hmr' + import { hot } from 'vite/hmr' foo() @@ -95,7 +95,7 @@ The above will throw an error by default. Vite detects such bare module imports Modules can also be self-accepting: ```js - import { hot } from '@hmr' + import { hot } from 'vite/hmr' export const count = 1 @@ -110,6 +110,8 @@ The above will throw an error by default. Vite detects such bare module imports A self-accepting module, or a module that expects to be accepted by others can use `hot.dispose` to cleanup any persistent side effects created by its updated copy: ```js + import { hot } from 'vite/hmr' + function setupSideEffect() {} function cleanupSideEffect() {} diff --git a/hmr.d.ts b/hmr.d.ts new file mode 100644 index 00000000000000..9921933440bf7f --- /dev/null +++ b/hmr.d.ts @@ -0,0 +1,12 @@ +export declare const hot: { + // single dep + accept(dep: string, cb?: (newModule: any) => void): void + // multiple deps + accept(deps: string[], cb?: (newModules: any[]) => void): void + // self-accepting + accept(cb: (newModule: any) => void): void + // dispose + dispose(cb: () => void): void + // custom events + on(event: string, cb: () => void): void +} diff --git a/package.json b/package.json index d3166b37a249e3..03198db578e0b6 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "types": "dist/index.d.ts", "files": [ "bin", - "dist" + "dist", + "hmr.d.ts" ], "engines": { "node": ">=10.0.0" @@ -29,7 +30,7 @@ "dev-node": "tsc -w --p src/node", "build": "rm -rf dist && tsc -p src/client && tsc -p src/node", "lint": "prettier --write --parser typescript \"src/**/*.ts\"", - "test": "jest --runInBand", + "test": "jest --clearCache && jest --runInBand", "windows-ci": "yarn build && jest --runInBand --forceExit", "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s", "prepublishOnly": "yarn build && yarn changelog", diff --git a/playground/testHmrManual.js b/playground/testHmrManual.js index e7e01cfb888c5a..206c05d6d96179 100644 --- a/playground/testHmrManual.js +++ b/playground/testHmrManual.js @@ -1,4 +1,4 @@ -import { hot } from '@hmr' +import { hot } from 'vite/hmr' export const foo = 1 diff --git a/src/node/server/index.ts b/src/node/server/index.ts index cafb374b7bdc2f..21eb7d68d9992f 100644 --- a/src/node/server/index.ts +++ b/src/node/server/index.ts @@ -39,6 +39,7 @@ export interface ServerConfig { } const internalPlugins: Plugin[] = [ + hmrPlugin, moduleRewritePlugin, moduleResolvePlugin, vuePlugin, @@ -46,7 +47,6 @@ const internalPlugins: Plugin[] = [ jsonPlugin, cssPlugin, assetPathPlugin, - hmrPlugin, serveStaticPlugin ] diff --git a/src/node/server/serverPluginHmr.ts b/src/node/server/serverPluginHmr.ts index 28f4647de616b6..1cb290896b93c2 100644 --- a/src/node/server/serverPluginHmr.ts +++ b/src/node/server/serverPluginHmr.ts @@ -9,7 +9,7 @@ // 4. When a js file changes, it triggers an HMR graph analysis, where we try to // walk its importer chains and see if we reach a "HMR boundary". An HMR // boundary is either a `.vue` file or a `.js` file that explicitly indicated -// that it accepts hot updates (by importing from the `/@hmr` special module) +// that it accepts hot updates (by importing from the `/vite/hmr` special module) // 5. If any parent chain exhausts without ever running into an HMR boundary, // it's considered a "dead end". This causes a full page reload. // 6. If a `.vue` boundary is encountered, we add it to the `vueImports` Set. @@ -21,7 +21,7 @@ // client to update all `jsImporters` and `vueImporters`. // How do we get a js HMR boundary's accepted list on the server -// 1. During the import rewriting, if `/@hmr` import is present in a js file, +// 1. During the import rewriting, if `/vite/hmr` import is present in a js file, // we will do a fullblown parse of the file to find the `hot.accept` call, // and records the file and its accepted dependencies in a `hmrBoundariesMap` // 2. We also inject the boundary file's full path into the `hot.accept` call @@ -60,7 +60,7 @@ export const importeeMap: HMRStateMap = new Map() // client and node files are placed flat in the dist folder export const hmrClientFilePath = path.resolve(__dirname, '../client.js') -export const hmrClientId = '@hmr' +export const hmrClientId = 'vite/hmr' export const hmrClientPublicPath = `/${hmrClientId}` interface HMRPayload { diff --git a/src/node/server/serverPluginModuleRewrite.ts b/src/node/server/serverPluginModuleRewrite.ts index c7c4df549b4c2e..48d3a9dda5d516 100644 --- a/src/node/server/serverPluginModuleRewrite.ts +++ b/src/node/server/serverPluginModuleRewrite.ts @@ -11,7 +11,8 @@ import { importeeMap, ensureMapEntry, rewriteFileWithHMR, - hmrClientPublicPath + hmrClientPublicPath, + hmrClientId } from './serverPluginHmr' import { readBody, @@ -100,7 +101,7 @@ export const moduleRewritePlugin: Plugin = ({ app, watcher, resolver }) => { ctx.response.is('js') && !ctx.url.endsWith('.map') && // skip internal client - !ctx.path.startsWith(`/@hmr`) && + !ctx.path.startsWith(hmrClientPublicPath) && // only need to rewrite for