|
1 | 1 | import path from 'node:path' |
| 2 | +import fs from 'node:fs' |
2 | 3 | import type { Plugin } from '../plugin' |
3 | 4 | import type { ResolvedConfig } from '../config' |
4 | 5 | import { CLIENT_ENTRY, ENV_ENTRY } from '../constants' |
@@ -33,66 +34,7 @@ export function clientInjectionsPlugin(config: ResolvedConfig): Plugin { |
33 | 34 | return { |
34 | 35 | name: 'vite:client-inject', |
35 | 36 | async buildStart() { |
36 | | - const resolvedServerHostname = (await resolveHostname(config.server.host)) |
37 | | - .name |
38 | | - const resolvedServerPort = config.server.port! |
39 | | - const devBase = config.base |
40 | | - |
41 | | - const serverHost = `${resolvedServerHostname}:${resolvedServerPort}${devBase}` |
42 | | - |
43 | | - let hmrConfig = config.server.hmr |
44 | | - hmrConfig = isObject(hmrConfig) ? hmrConfig : undefined |
45 | | - const host = hmrConfig?.host || null |
46 | | - const protocol = hmrConfig?.protocol || null |
47 | | - const timeout = hmrConfig?.timeout || 30000 |
48 | | - const overlay = hmrConfig?.overlay !== false |
49 | | - const isHmrServerSpecified = !!hmrConfig?.server |
50 | | - const hmrConfigName = path.basename(config.configFile || 'vite.config.js') |
51 | | - |
52 | | - // hmr.clientPort -> hmr.port |
53 | | - // -> (24678 if middleware mode and HMR server is not specified) -> new URL(import.meta.url).port |
54 | | - let port = hmrConfig?.clientPort || hmrConfig?.port || null |
55 | | - if (config.server.middlewareMode && !isHmrServerSpecified) { |
56 | | - port ||= 24678 |
57 | | - } |
58 | | - |
59 | | - let directTarget = hmrConfig?.host || resolvedServerHostname |
60 | | - directTarget += `:${hmrConfig?.port || resolvedServerPort}` |
61 | | - directTarget += devBase |
62 | | - |
63 | | - let hmrBase = devBase |
64 | | - if (hmrConfig?.path) { |
65 | | - hmrBase = path.posix.join(hmrBase, hmrConfig.path) |
66 | | - } |
67 | | - |
68 | | - const modeReplacement = escapeReplacement(config.mode) |
69 | | - const baseReplacement = escapeReplacement(devBase) |
70 | | - const serverHostReplacement = escapeReplacement(serverHost) |
71 | | - const hmrProtocolReplacement = escapeReplacement(protocol) |
72 | | - const hmrHostnameReplacement = escapeReplacement(host) |
73 | | - const hmrPortReplacement = escapeReplacement(port) |
74 | | - const hmrDirectTargetReplacement = escapeReplacement(directTarget) |
75 | | - const hmrBaseReplacement = escapeReplacement(hmrBase) |
76 | | - const hmrTimeoutReplacement = escapeReplacement(timeout) |
77 | | - const hmrEnableOverlayReplacement = escapeReplacement(overlay) |
78 | | - const hmrConfigNameReplacement = escapeReplacement(hmrConfigName) |
79 | | - const wsTokenReplacement = escapeReplacement(config.webSocketToken) |
80 | | - |
81 | | - injectConfigValues = (code: string) => { |
82 | | - return code |
83 | | - .replace(`__MODE__`, modeReplacement) |
84 | | - .replace(/__BASE__/g, baseReplacement) |
85 | | - .replace(`__SERVER_HOST__`, serverHostReplacement) |
86 | | - .replace(`__HMR_PROTOCOL__`, hmrProtocolReplacement) |
87 | | - .replace(`__HMR_HOSTNAME__`, hmrHostnameReplacement) |
88 | | - .replace(`__HMR_PORT__`, hmrPortReplacement) |
89 | | - .replace(`__HMR_DIRECT_TARGET__`, hmrDirectTargetReplacement) |
90 | | - .replace(`__HMR_BASE__`, hmrBaseReplacement) |
91 | | - .replace(`__HMR_TIMEOUT__`, hmrTimeoutReplacement) |
92 | | - .replace(`__HMR_ENABLE_OVERLAY__`, hmrEnableOverlayReplacement) |
93 | | - .replace(`__HMR_CONFIG_NAME__`, hmrConfigNameReplacement) |
94 | | - .replace(`__WS_TOKEN__`, wsTokenReplacement) |
95 | | - } |
| 37 | + injectConfigValues = await createClientConfigValueReplacer(config) |
96 | 38 | }, |
97 | 39 | async transform(code, id, options) { |
98 | 40 | // TODO: Remove options?.ssr, Vitest currently hijacks this plugin |
@@ -121,3 +63,83 @@ function escapeReplacement(value: string | number | boolean | null) { |
121 | 63 | const jsonValue = JSON.stringify(value) |
122 | 64 | return () => jsonValue |
123 | 65 | } |
| 66 | + |
| 67 | +async function createClientConfigValueReplacer( |
| 68 | + config: ResolvedConfig, |
| 69 | +): Promise<(code: string) => string> { |
| 70 | + const resolvedServerHostname = (await resolveHostname(config.server.host)) |
| 71 | + .name |
| 72 | + const resolvedServerPort = config.server.port! |
| 73 | + const devBase = config.base |
| 74 | + |
| 75 | + const serverHost = `${resolvedServerHostname}:${resolvedServerPort}${devBase}` |
| 76 | + |
| 77 | + let hmrConfig = config.server.hmr |
| 78 | + hmrConfig = isObject(hmrConfig) ? hmrConfig : undefined |
| 79 | + const host = hmrConfig?.host || null |
| 80 | + const protocol = hmrConfig?.protocol || null |
| 81 | + const timeout = hmrConfig?.timeout || 30000 |
| 82 | + const overlay = hmrConfig?.overlay !== false |
| 83 | + const isHmrServerSpecified = !!hmrConfig?.server |
| 84 | + const hmrConfigName = path.basename(config.configFile || 'vite.config.js') |
| 85 | + |
| 86 | + // hmr.clientPort -> hmr.port |
| 87 | + // -> (24678 if middleware mode and HMR server is not specified) -> new URL(import.meta.url).port |
| 88 | + let port = hmrConfig?.clientPort || hmrConfig?.port || null |
| 89 | + if (config.server.middlewareMode && !isHmrServerSpecified) { |
| 90 | + port ||= 24678 |
| 91 | + } |
| 92 | + |
| 93 | + let directTarget = hmrConfig?.host || resolvedServerHostname |
| 94 | + directTarget += `:${hmrConfig?.port || resolvedServerPort}` |
| 95 | + directTarget += devBase |
| 96 | + |
| 97 | + let hmrBase = devBase |
| 98 | + if (hmrConfig?.path) { |
| 99 | + hmrBase = path.posix.join(hmrBase, hmrConfig.path) |
| 100 | + } |
| 101 | + |
| 102 | + const modeReplacement = escapeReplacement(config.mode) |
| 103 | + const baseReplacement = escapeReplacement(devBase) |
| 104 | + const serverHostReplacement = escapeReplacement(serverHost) |
| 105 | + const hmrProtocolReplacement = escapeReplacement(protocol) |
| 106 | + const hmrHostnameReplacement = escapeReplacement(host) |
| 107 | + const hmrPortReplacement = escapeReplacement(port) |
| 108 | + const hmrDirectTargetReplacement = escapeReplacement(directTarget) |
| 109 | + const hmrBaseReplacement = escapeReplacement(hmrBase) |
| 110 | + const hmrTimeoutReplacement = escapeReplacement(timeout) |
| 111 | + const hmrEnableOverlayReplacement = escapeReplacement(overlay) |
| 112 | + const hmrConfigNameReplacement = escapeReplacement(hmrConfigName) |
| 113 | + const wsTokenReplacement = escapeReplacement(config.webSocketToken) |
| 114 | + const fullBundleModeReplacement = escapeReplacement( |
| 115 | + config.experimental.fullBundleMode || false, |
| 116 | + ) |
| 117 | + |
| 118 | + return (code) => |
| 119 | + code |
| 120 | + .replace(`__MODE__`, modeReplacement) |
| 121 | + .replace(/__BASE__/g, baseReplacement) |
| 122 | + .replace(`__SERVER_HOST__`, serverHostReplacement) |
| 123 | + .replace(`__HMR_PROTOCOL__`, hmrProtocolReplacement) |
| 124 | + .replace(`__HMR_HOSTNAME__`, hmrHostnameReplacement) |
| 125 | + .replace(`__HMR_PORT__`, hmrPortReplacement) |
| 126 | + .replace(`__HMR_DIRECT_TARGET__`, hmrDirectTargetReplacement) |
| 127 | + .replace(`__HMR_BASE__`, hmrBaseReplacement) |
| 128 | + .replace(`__HMR_TIMEOUT__`, hmrTimeoutReplacement) |
| 129 | + .replace(`__HMR_ENABLE_OVERLAY__`, hmrEnableOverlayReplacement) |
| 130 | + .replace(`__HMR_CONFIG_NAME__`, hmrConfigNameReplacement) |
| 131 | + .replace(`__WS_TOKEN__`, wsTokenReplacement) |
| 132 | + .replaceAll(`__FULL_BUNDLE_MODE__`, fullBundleModeReplacement) |
| 133 | +} |
| 134 | + |
| 135 | +export async function getHmrImplementation( |
| 136 | + config: ResolvedConfig, |
| 137 | +): Promise<string> { |
| 138 | + const content = fs.readFileSync(normalizedClientEntry, 'utf-8') |
| 139 | + const replacer = await createClientConfigValueReplacer(config) |
| 140 | + return ( |
| 141 | + replacer(content) |
| 142 | + // the rolldown runtime shouldn't be importer a module |
| 143 | + .replace(/import\s*['"]@vite\/env['"]/, '') |
| 144 | + ) |
| 145 | +} |
0 commit comments