Skip to content

Commit

Permalink
fix(hmr): respect server https options when running as middleware
Browse files Browse the repository at this point in the history
If you are running vite over https, HMR works great in the standalone mode, but when in middleware mode, the middleware might be served over https and the websocket server wouldn't listen on https. This updates the websocket server to respect the config.server.https option when in middleware mode too.
  • Loading branch information
airhorns committed Mar 11, 2021
1 parent 5ec13d8 commit c4610c6
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 21 deletions.
8 changes: 6 additions & 2 deletions packages/vite/src/node/serve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import connect from 'connect'
import compression from 'compression'
import { ResolvedConfig } from '.'
import { Connect } from 'types/connect'
import { resolveHttpServer } from './server/http'
import { resolveHttpsConfig, resolveHttpServer } from './server/http'
import { openBrowser } from './server/openBrowser'

export async function serve(config: ResolvedConfig, port = 5000) {
Expand All @@ -23,7 +23,11 @@ export async function serve(config: ResolvedConfig, port = 5000) {
})
)

const server = await resolveHttpServer(config.server, app)
const server = await resolveHttpServer(
config,
app,
await resolveHttpsConfig(config)
)

const options = config.server || {}
const hostname = options.host || 'localhost'
Expand Down
21 changes: 12 additions & 9 deletions packages/vite/src/node/server/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,19 @@ import fs from 'fs'
import path from 'path'
import { Server as HttpServer } from 'http'
import { ServerOptions as HttpsServerOptions } from 'https'
import { ServerOptions } from '..'
import { ResolvedConfig } from '..'
import { Connect } from 'types/connect'

export async function resolveHttpServer(
{ https = false, proxy }: ServerOptions,
app: Connect.Server
config: ResolvedConfig,
app: Connect.Server,
httpsOptions?: HttpsServerOptions
): Promise<HttpServer> {
if (!https) {
if (!httpsOptions) {
return require('http').createServer(app)
}

const httpsOptions = await resolveHttpsConfig(
typeof https === 'boolean' ? {} : https
)
if (proxy) {
if (config.server?.proxy) {
// #484 fallback to http1 when proxy is needed.
return require('https').createServer(httpsOptions, app)
} else {
Expand All @@ -30,7 +28,12 @@ export async function resolveHttpServer(
}
}

export async function resolveHttpsConfig(httpsOption: HttpsServerOptions) {
export async function resolveHttpsConfig(config: ResolvedConfig) {
const httpsOption =
typeof config.server.https === 'boolean' ? {} : config.server.https

if (!httpsOption) return undefined

const { ca, cert, key, pfx } = httpsOption
Object.assign(httpsOption, {
ca: readFileIfExists(ca),
Expand Down
7 changes: 4 additions & 3 deletions packages/vite/src/node/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import corsMiddleware from 'cors'
import chalk from 'chalk'
import { AddressInfo } from 'net'
import chokidar from 'chokidar'
import { resolveHttpServer } from './http'
import { resolveHttpsConfig, resolveHttpServer } from './http'
import { resolveConfig, InlineConfig, ResolvedConfig } from '../config'
import {
createPluginContainer,
Expand Down Expand Up @@ -264,12 +264,13 @@ export async function createServer(
const root = config.root
const serverConfig = config.server || {}
const middlewareMode = !!serverConfig.middlewareMode
const httpsOptions = await resolveHttpsConfig(config)

const middlewares = connect() as Connect.Server
const httpServer = middlewareMode
? null
: await resolveHttpServer(serverConfig, middlewares)
const ws = createWebSocketServer(httpServer, config)
: await resolveHttpServer(config, middlewares, httpsOptions)
const ws = createWebSocketServer(httpServer, config, httpsOptions)

const { ignored = [], ...watchOptions } = serverConfig.watch || {}
const watcher = chokidar.watch(path.resolve(root), {
Expand Down
35 changes: 28 additions & 7 deletions packages/vite/src/node/server/ws.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import chalk from 'chalk'
import { Server } from 'http'
import { Server, STATUS_CODES } from 'http'
import { createServer, ServerOptions as HttpsServerOptions } from 'https'
import WebSocket from 'ws'
import { ErrorPayload, HMRPayload } from 'types/hmrPayload'
import { ResolvedConfig } from '..'
Expand All @@ -13,7 +14,8 @@ export interface WebSocketServer {

export function createWebSocketServer(
server: Server | null,
config: ResolvedConfig
config: ResolvedConfig,
httpsOptions?: HttpsServerOptions
): WebSocketServer {
let wss: WebSocket.Server

Expand All @@ -27,12 +29,31 @@ export function createWebSocketServer(
}
})
} else {
let websocketServerOptions: WebSocket.ServerOptions = {}
const port =
(typeof config.server.hmr === 'object' && config.server.hmr.port) || 24678
if (httpsOptions) {
// if we're serving the middlewares over https, the ws library doesn't support automatically creating an https server, so we need to do it ourselves
// create an inline https server and mount the websocket server to it
const httpsServer = createServer(httpsOptions, (req, res) => {
const body = STATUS_CODES[426]

res.writeHead(426, {
'Content-Length': body!.length,
'Content-Type': 'text/plain'
})
res.end(body)
})

httpsServer.listen(port)
websocketServerOptions.server = httpsServer
} else {
// we don't need to serve over https, just let ws handle its own server
websocketServerOptions.port = port
}

// vite dev server in middleware mode
wss = new WebSocket.Server({
port:
(typeof config.server.hmr === 'object' && config.server.hmr.port) ||
24678
})
wss = new WebSocket.Server(websocketServerOptions)
}

wss.on('connection', (socket) => {
Expand Down

0 comments on commit c4610c6

Please sign in to comment.