diff --git a/docs/guide/api-plugin.md b/docs/guide/api-plugin.md index 50353765261e34..76b9984a069828 100644 --- a/docs/guide/api-plugin.md +++ b/docs/guide/api-plugin.md @@ -305,6 +305,28 @@ Vite plugins can also provide hooks that serve Vite-specific purposes. These hoo Note `configureServer` is not called when running the production build so your other hooks need to guard against its absence. +### `configurePreviewServer` + +- **Type:** `(server: { middlewares: Connect.Server, httpServer: http.Server }) => (() => void) | void | Promise<(() => void) | void>` +- **Kind:** `async`, `sequential` + + Same as [`configureServer`](/guide/api-plugin.html#configureserver) but for the preview server. It provides the [connect](https://github.com/senchalabs/connect) server and its underlying [http server](https://nodejs.org/api/http.html). Similarly to `configureServer`, the `configurePreviewServer` hook is called before other middlewares are installed. If you want to inject a middleware **after** other middlewares, you can return a function from `configurePreviewServer`, which will be called after internal middlewares are installed: + + ```js + const myPlugin = () => ({ + name: 'configure-preview-server', + configurePreviewServer(server) { + // return a post hook that is called after other middlewares are + // installed + return () => { + server.middlewares.use((req, res, next) => { + // custom handle request... + }) + } + } + }) + ``` + ### `transformIndexHtml` - **Type:** `IndexHtmlTransformHook | { enforce?: 'pre' | 'post', transform: IndexHtmlTransformHook }` diff --git a/packages/vite/src/node/index.ts b/packages/vite/src/node/index.ts index 2e849d846527ca..901c5b943f8e14 100644 --- a/packages/vite/src/node/index.ts +++ b/packages/vite/src/node/index.ts @@ -33,6 +33,7 @@ export type { export type { PreviewOptions, PreviewServer, + PreviewServerHook, ResolvedPreviewOptions } from './preview' export type { diff --git a/packages/vite/src/node/plugin.ts b/packages/vite/src/node/plugin.ts index c613fe5f180d07..adf647d6d5500f 100644 --- a/packages/vite/src/node/plugin.ts +++ b/packages/vite/src/node/plugin.ts @@ -12,6 +12,7 @@ import type { ServerHook } from './server' import type { IndexHtmlTransform } from './plugins/html' import type { ModuleNode } from './server/moduleGraph' import type { HmrContext } from './server/hmr' +import type { PreviewServerHook } from './preview' import type { ConfigEnv, ResolvedConfig } from './' /** @@ -79,6 +80,15 @@ export interface Plugin extends RollupPlugin { * are applied. Hook can be async functions and will be called in series. */ configureServer?: ServerHook + /** + * Configure the preview server. The hook receives the connect server and + * its underlying http server. + * + * The hooks are called before other middlewares are applied. A hook can + * return a post hook that will be called after other middlewares are + * applied. Hooks can be async functions and will be called in series. + */ + configurePreviewServer?: PreviewServerHook /** * Transform index.html. * The hook receives the following arguments: diff --git a/packages/vite/src/node/preview.ts b/packages/vite/src/node/preview.ts index a230ab5b57421d..8debe521353b84 100644 --- a/packages/vite/src/node/preview.ts +++ b/packages/vite/src/node/preview.ts @@ -1,5 +1,6 @@ import path from 'path' import type { Server } from 'http' +import type * as http from 'http' import connect from 'connect' import sirv from 'sirv' import type { Connect } from 'types/connect' @@ -53,6 +54,11 @@ export interface PreviewServer { printUrls: () => void } +export type PreviewServerHook = (server: { + middlewares: Connect.Server + httpServer: http.Server +}) => (() => void) | void | Promise<(() => void) | void> + /** * Starts the Vite server in preview mode, to simulate a production deployment * @experimental @@ -69,6 +75,16 @@ export async function preview( await resolveHttpsConfig(config.preview?.https, config.cacheDir) ) + // apply server hooks from plugins + const postHooks: ((() => void) | void)[] = [] + for (const plugin of config.plugins) { + if (plugin.configurePreviewServer) { + postHooks.push( + await plugin.configurePreviewServer({ middlewares: app, httpServer }) + ) + } + } + // cors const { cors } = config.preview if (cors !== false) { @@ -83,6 +99,7 @@ export async function preview( app.use(compression()) + // static assets const distDir = path.resolve(config.root, config.build.outDir) app.use( config.base, @@ -93,6 +110,9 @@ export async function preview( }) ) + // apply post server hooks from plugins + postHooks.forEach((fn) => fn && fn()) + const options = config.preview const hostname = resolveHostname(options.host) const port = options.port ?? 4173