diff --git a/packages/vite/src/node/plugins/clientInjections.ts b/packages/vite/src/node/plugins/clientInjections.ts index bf46c0e42ce597..dfd3b878b6f459 100644 --- a/packages/vite/src/node/plugins/clientInjections.ts +++ b/packages/vite/src/node/plugins/clientInjections.ts @@ -13,54 +13,74 @@ const normalizedEnvEntry = normalizePath(ENV_ENTRY) * @server-only */ export function clientInjectionsPlugin(config: ResolvedConfig): Plugin { + let injectConfigValues: (code: string) => string + return { name: 'vite:client-inject', - async transform(code, id, options) { - if (id === normalizedClientEntry || id === normalizedEnvEntry) { - const resolvedServerHostname = ( - await resolveHostname(config.server.host) - ).name - const resolvedServerPort = config.server.port! - const devBase = config.base + async buildStart() { + const resolvedServerHostname = (await resolveHostname(config.server.host)) + .name + const resolvedServerPort = config.server.port! + const devBase = config.base + + const serverHost = `${resolvedServerHostname}:${resolvedServerPort}${devBase}` - const serverHost = `${resolvedServerHostname}:${resolvedServerPort}${devBase}` + let hmrConfig = config.server.hmr + hmrConfig = isObject(hmrConfig) ? hmrConfig : undefined + const host = hmrConfig?.host || null + const protocol = hmrConfig?.protocol || null + const timeout = hmrConfig?.timeout || 30000 + const overlay = hmrConfig?.overlay !== false + const isHmrServerSpecified = !!hmrConfig?.server - let hmrConfig = config.server.hmr - hmrConfig = isObject(hmrConfig) ? hmrConfig : undefined - const host = hmrConfig?.host || null - const protocol = hmrConfig?.protocol || null - const timeout = hmrConfig?.timeout || 30000 - const overlay = hmrConfig?.overlay !== false - const isHmrServerSpecified = !!hmrConfig?.server + // hmr.clientPort -> hmr.port + // -> (24678 if middleware mode and HMR server is not specified) -> new URL(import.meta.url).port + let port = hmrConfig?.clientPort || hmrConfig?.port || null + if (config.server.middlewareMode && !isHmrServerSpecified) { + port ||= 24678 + } + + let directTarget = hmrConfig?.host || resolvedServerHostname + directTarget += `:${hmrConfig?.port || resolvedServerPort}` + directTarget += devBase - // hmr.clientPort -> hmr.port - // -> (24678 if middleware mode and HMR server is not specified) -> new URL(import.meta.url).port - let port = hmrConfig?.clientPort || hmrConfig?.port || null - if (config.server.middlewareMode && !isHmrServerSpecified) { - port ||= 24678 - } + let hmrBase = devBase + if (hmrConfig?.path) { + hmrBase = path.posix.join(hmrBase, hmrConfig.path) + } - let directTarget = hmrConfig?.host || resolvedServerHostname - directTarget += `:${hmrConfig?.port || resolvedServerPort}` - directTarget += devBase + const serializedDefines = serializeDefine(config.define || {}) - let hmrBase = devBase - if (hmrConfig?.path) { - hmrBase = path.posix.join(hmrBase, hmrConfig.path) - } + const modeReplacement = escapeReplacement(config.mode) + const baseReplacement = escapeReplacement(devBase) + const definesReplacement = () => serializedDefines + const serverHostReplacement = escapeReplacement(serverHost) + const hmrProtocolReplacement = escapeReplacement(protocol) + const hmrHostnameReplacement = escapeReplacement(host) + const hmrPortReplacement = escapeReplacement(port) + const hmrDirectTargetReplacement = escapeReplacement(directTarget) + const hmrBaseReplacement = escapeReplacement(hmrBase) + const hmrTimeoutReplacement = escapeReplacement(timeout) + const hmrEnableOverlayReplacement = escapeReplacement(overlay) + injectConfigValues = (code: string) => { return code - .replace(`__MODE__`, JSON.stringify(config.mode)) - .replace(/__BASE__/g, JSON.stringify(devBase)) - .replace(`__DEFINES__`, serializeDefine(config.define || {})) - .replace(`__SERVER_HOST__`, JSON.stringify(serverHost)) - .replace(`__HMR_PROTOCOL__`, JSON.stringify(protocol)) - .replace(`__HMR_HOSTNAME__`, JSON.stringify(host)) - .replace(`__HMR_PORT__`, JSON.stringify(port)) - .replace(`__HMR_DIRECT_TARGET__`, JSON.stringify(directTarget)) - .replace(`__HMR_BASE__`, JSON.stringify(hmrBase)) - .replace(`__HMR_TIMEOUT__`, JSON.stringify(timeout)) - .replace(`__HMR_ENABLE_OVERLAY__`, JSON.stringify(overlay)) + .replace(`__MODE__`, modeReplacement) + .replace(/__BASE__/g, baseReplacement) + .replace(`__DEFINES__`, definesReplacement) + .replace(`__SERVER_HOST__`, serverHostReplacement) + .replace(`__HMR_PROTOCOL__`, hmrProtocolReplacement) + .replace(`__HMR_HOSTNAME__`, hmrHostnameReplacement) + .replace(`__HMR_PORT__`, hmrPortReplacement) + .replace(`__HMR_DIRECT_TARGET__`, hmrDirectTargetReplacement) + .replace(`__HMR_BASE__`, hmrBaseReplacement) + .replace(`__HMR_TIMEOUT__`, hmrTimeoutReplacement) + .replace(`__HMR_ENABLE_OVERLAY__`, hmrEnableOverlayReplacement) + } + }, + transform(code, id, options) { + if (id === normalizedClientEntry || id === normalizedEnvEntry) { + return injectConfigValues(code) } else if (!options?.ssr && code.includes('process.env.NODE_ENV')) { // replace process.env.NODE_ENV instead of defining a global // for it to avoid shimming a `process` object during dev, @@ -75,6 +95,11 @@ export function clientInjectionsPlugin(config: ResolvedConfig): Plugin { } } +function escapeReplacement(value: string | number | boolean | null) { + const jsonValue = JSON.stringify(value) + return () => jsonValue +} + function serializeDefine(define: Record): string { let res = `{` for (const key in define) {