|
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