Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use preview server parameter in preview server hook #11647

Merged
merged 6 commits into from Mar 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
40 changes: 40 additions & 0 deletions docs/guide/api-javascript.md
Expand Up @@ -198,6 +198,46 @@ import { preview } from 'vite'
})()
```

## `PreviewServer`

```ts
interface PreviewServer extends PreviewServerForHook {
resolvedUrls: ResolvedServerUrls
}
```

## `PreviewServerForHook`

```ts
interface PreviewServerForHook {
/**
* The resolved vite config object
*/
config: ResolvedConfig
/**
* A connect app instance.
* - Can be used to attach custom middlewares to the preview server.
* - Can also be used as the handler function of a custom http server
* or as a middleware in any connect-style Node.js frameworks
*
* https://github.com/senchalabs/connect#use-middleware
*/
middlewares: Connect.Server
/**
* native Node http server instance
*/
httpServer: http.Server
/**
* The resolved urls Vite prints on the CLI
*/
resolvedUrls: ResolvedServerUrls | null
/**
* Print server urls
*/
printUrls(): void
}
```

## `resolveConfig`

**Type Signature:**
Expand Down
5 changes: 3 additions & 2 deletions docs/guide/api-plugin.md
Expand Up @@ -309,10 +309,11 @@ Vite plugins can also provide hooks that serve Vite-specific purposes. These hoo

### `configurePreviewServer`

- **Type:** `(server: { middlewares: Connect.Server, httpServer: http.Server }) => (() => void) | void | Promise<(() => void) | void>`
- **Type:** `(server: PreviewServerForHook) => (() => void) | void | Promise<(() => void) | void>`
- **Kind:** `async`, `sequential`
- **See also:** [PreviewServerForHook](./api-javascript#previewserverforhook)

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:
Same as [`configureServer`](/guide/api-plugin.html#configureserver) but for the preview server. 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 = () => ({
Expand Down
1 change: 1 addition & 0 deletions packages/vite/src/node/index.ts
Expand Up @@ -34,6 +34,7 @@ export type {
export type {
PreviewOptions,
PreviewServer,
PreviewServerForHook,
PreviewServerHook,
ResolvedPreviewOptions,
} from './preview'
Expand Down
5 changes: 3 additions & 2 deletions packages/vite/src/node/plugin.ts
Expand Up @@ -91,8 +91,9 @@ export interface Plugin extends RollupPlugin {
*/
configureServer?: ObjectHook<ServerHook>
/**
* Configure the preview server. The hook receives the connect server and
* its underlying http server.
* Configure the preview server. The hook receives the {@link PreviewServerForHook}
* instance. This can also be used to store a reference to the server
* for use in other hooks.
*
* The hooks are called before other middlewares are applied. A hook can
* return a post hook that will be called after other middlewares are
Expand Down
55 changes: 37 additions & 18 deletions packages/vite/src/node/preview.ts
Expand Up @@ -45,31 +45,42 @@ export function resolvePreviewOptions(
}
}

export interface PreviewServer {
// TODO: merge with PreviewServer in Vite 5
export interface PreviewServerForHook {
/**
* The resolved vite config object
*/
config: ResolvedConfig
/**
* A connect app instance.
* - Can be used to attach custom middlewares to the preview server.
* - Can also be used as the handler function of a custom http server
* or as a middleware in any connect-style Node.js frameworks
*
* https://github.com/senchalabs/connect#use-middleware
*/
middlewares: Connect.Server
/**
* native Node http server instance
*/
httpServer: http.Server
/**
* The resolved urls Vite prints on the CLI
*/
resolvedUrls: ResolvedServerUrls
resolvedUrls: ResolvedServerUrls | null
/**
* Print server urls
*/
printUrls(): void
}

export interface PreviewServer extends PreviewServerForHook {
resolvedUrls: ResolvedServerUrls
}

export type PreviewServerHook = (
this: void,
server: {
middlewares: Connect.Server
httpServer: http.Server
},
server: PreviewServerForHook,
) => (() => void) | void | Promise<(() => void) | void>

/**
Expand Down Expand Up @@ -108,10 +119,27 @@ export async function preview(
)
setClientErrorHandler(httpServer, config.logger)

const options = config.preview
const logger = config.logger

const server: PreviewServerForHook = {
config,
middlewares: app,
httpServer,
resolvedUrls: null,
printUrls() {
if (server.resolvedUrls) {
printServerUrls(server.resolvedUrls, options.host, logger.info)
} else {
throw new Error('cannot print server URLs before server is listening.')
}
},
}

// apply server hooks from plugins
const postHooks: ((() => void) | void)[] = []
for (const hook of config.getSortedPluginHooks('configurePreviewServer')) {
postHooks.push(await hook({ middlewares: app, httpServer }))
postHooks.push(await hook(server))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

configurePreviewServer hooks now runs after the server started to listen on the port.
I'm not sure if this is safe or not. But I think it's better to align with the dev server.

How about adding PreviewServerForHook type that has a nullable resolvedUrls property? And then use PreviewServerForHook for the hooks and use PreviewServer for the return type of preview function for compatibility.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah you're right. I think PreviewServerForHook makes sense, but for the next major, maybe we can make it nullable by default so the types are cleaner.

With this change, I think this PR is good too.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could merge this in 4.3. @sapphi-red if you agree, you can directly commit your suggestion and merge this one. The alignment is quite uncontroversial to me, we shouldn't need a meeting to review this one IMO.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rebased on main and pushed some commits 👍

}

// cors
Expand Down Expand Up @@ -153,11 +181,9 @@ export async function preview(
// apply post server hooks from plugins
postHooks.forEach((fn) => fn && fn())

const options = config.preview
const hostname = await resolveHostname(options.host)
const port = options.port ?? DEFAULT_PREVIEW_PORT
const protocol = options.https ? 'https' : 'http'
const logger = config.logger

const serverPort = await httpServerStart(httpServer, {
port,
Expand All @@ -166,7 +192,7 @@ export async function preview(
logger,
})

const resolvedUrls = await resolveServerUrls(
server.resolvedUrls = await resolveServerUrls(
httpServer,
config.preview,
config,
Expand All @@ -183,12 +209,5 @@ export async function preview(
)
}

return {
config,
httpServer,
resolvedUrls,
printUrls() {
printServerUrls(resolvedUrls, options.host, logger.info)
},
}
return server as PreviewServer
}