diff --git a/README.md b/README.md index ea28f01..56cba5f 100644 --- a/README.md +++ b/README.md @@ -40,14 +40,12 @@ npm i -D vite-plugin-full-reload # yarn add -D vite-plugin-full-reload Add it to your plugins in `vite.config.ts` ```ts -import { defineConfig } from 'vite' -import FullReload from 'vite-plugin-full-reload' +import { defineConfig } from "vite"; +import FullReload from "vite-plugin-full-reload"; export default defineConfig({ - plugins: [ - FullReload(['config/routes.rb', 'app/views/**/*']) - ], -}) + plugins: [FullReload(["config/routes.rb", "app/views/**/*"])], +}); ``` This is useful to trigger a page refresh for files that are not being imported, such as server-rendered templates. @@ -59,35 +57,47 @@ To see which file globbing options are available, check [picomatch]. The following options can be provided: - root - + Files will be resolved against this directory. - __Default:__ `process.cwd()` + **Default:** `process.cwd()` - ``` js + ```js FullReload('config/routes.rb', { root: __dirname }), - ``` + ``` - delay How many milliseconds to wait before reloading the page after a file change. It can be used to offset slow template compilation in Rails. - __Default:__ `0` - + **Default:** `0` + ```js - FullReload('app/views/**/*', { delay: 100 }) - ``` + FullReload("app/views/**/*", { delay: 100 }); + ``` + +- debounce + + How many milliseconds to postpone the execution of the reload function since it's last invocation. + This is useful if you have a lot of changes in a short period of time and need to make sure that + only one `full-reload` event is sent to Vite. + + **Default:** `0` + + ```js + FullReload("app/views/**/*", { debounce: 100 }); + ``` - always Whether to refresh the page even if the modified HTML file is not currently being displayed. - __Default:__ `true` - + **Default:** `true` + ```js - FullReload('app/views/**/*', { always: false }) - ``` + FullReload("app/views/**/*", { always: false }); + ``` ## Acknowledgements diff --git a/src/index.ts b/src/index.ts index 7fafa22..1f74479 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ import { relative, resolve } from 'path' import colors from 'picocolors' import picomatch from 'picomatch' +import debounce from 'debounce' import { type PluginOption, type ViteDevServer, normalizePath } from 'vite' /** @@ -19,6 +20,15 @@ export interface Config { */ delay?: number + /** + * How many milliseconds to postpone the execution of the reload function since it's last invocation. + * This is useful if you have a lot of changes in a short period of time and need to make sure that + * only only one `full-reload` event is sent to Vite. + * + * @default 0 + */ + debounce?: number + /** * Whether to log when a file change triggers a full reload. * @default true @@ -48,13 +58,15 @@ export default (paths: string | string[], config: Config = {}): PluginOption => config: () => ({ server: { watch: { disableGlobbing: false } } }), configureServer ({ watcher, ws, config: { logger } }: ViteDevServer) { - const { root = process.cwd(), log = true, always = true, delay = 0 } = config + const { root = process.cwd(), log = true, always = true, delay = 0, debounce: debounceMs = 0 } = config const files = normalizePaths(root, paths) const shouldReload = picomatch(files) + const sendReloadEvent = (path: string) => setTimeout(() => ws.send({ type: 'full-reload', path: always ? '*' : path }), delay) + const reload = debounceMs ? debounce(sendReloadEvent, debounceMs) : sendReloadEvent const checkReload = (path: string) => { if (shouldReload(path)) { - setTimeout(() => ws.send({ type: 'full-reload', path: always ? '*' : path }), delay) + reload(path) if (log) logger.info(`${colors.green('page reload')} ${colors.dim(relative(root, path))}`, { clear: true, timestamp: true }) }