Skip to content

Commit 83d8c99

Browse files
sapphi-redunderfin
andauthored
feat: highly experimental full bundle mode (#21235)
Co-authored-by: underfin <likui.underfin@gmail.com>
1 parent 9349446 commit 83d8c99

36 files changed

Lines changed: 1791 additions & 637 deletions

packages/vite/src/client/client.ts

Lines changed: 90 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import type {
2+
DevRuntime as DevRuntimeType,
3+
Messenger,
4+
} from 'rolldown/experimental/runtime-types'
15
import type { ErrorPayload, HotPayload } from '#types/hmrPayload'
26
import type { ViteHotContext } from '#types/hot'
37
import { HMRClient, HMRContext } from '../shared/hmr'
@@ -20,6 +24,7 @@ declare const __HMR_BASE__: string
2024
declare const __HMR_TIMEOUT__: number
2125
declare const __HMR_ENABLE_OVERLAY__: boolean
2226
declare const __WS_TOKEN__: string
27+
declare const __BUNDLED_DEV__: boolean
2328

2429
console.debug('[vite] connecting...')
2530

@@ -37,6 +42,7 @@ const directSocketHost = __HMR_DIRECT_TARGET__
3742
const base = __BASE__ || '/'
3843
const hmrTimeout = __HMR_TIMEOUT__
3944
const wsToken = __WS_TOKEN__
45+
const isBundleMode = __BUNDLED_DEV__
4046

4147
const transport = normalizeModuleRunnerTransport(
4248
(() => {
@@ -140,32 +146,53 @@ const hmrClient = new HMRClient(
140146
debug: (...msg) => console.debug('[vite]', ...msg),
141147
},
142148
transport,
143-
async function importUpdatedModule({
144-
acceptedPath,
145-
timestamp,
146-
explicitImportRequired,
147-
isWithinCircularImport,
148-
}) {
149-
const [acceptedPathWithoutQuery, query] = acceptedPath.split(`?`)
150-
const importPromise = import(
151-
/* @vite-ignore */
152-
base +
153-
acceptedPathWithoutQuery.slice(1) +
154-
`?${explicitImportRequired ? 'import&' : ''}t=${timestamp}${
155-
query ? `&${query}` : ''
156-
}`
157-
)
158-
if (isWithinCircularImport) {
159-
importPromise.catch(() => {
160-
console.info(
161-
`[hmr] ${acceptedPath} failed to apply HMR as it's within a circular import. Reloading page to reset the execution order. ` +
162-
`To debug and break the circular import, you can run \`vite --debug hmr\` to log the circular dependency path if a file change triggered it.`,
149+
isBundleMode
150+
? async function importUpdatedModule({
151+
url,
152+
acceptedPath,
153+
isWithinCircularImport,
154+
}) {
155+
const importPromise = import(base + url!).then(() =>
156+
// @ts-expect-error globalThis.__rolldown_runtime__
157+
globalThis.__rolldown_runtime__.loadExports(acceptedPath),
163158
)
164-
pageReload()
165-
})
166-
}
167-
return await importPromise
168-
},
159+
if (isWithinCircularImport) {
160+
importPromise.catch(() => {
161+
console.info(
162+
`[hmr] ${acceptedPath} failed to apply HMR as it's within a circular import. Reloading page to reset the execution order. ` +
163+
`To debug and break the circular import, you can run \`vite --debug hmr\` to log the circular dependency path if a file change triggered it.`,
164+
)
165+
pageReload()
166+
})
167+
}
168+
return await importPromise
169+
}
170+
: async function importUpdatedModule({
171+
acceptedPath,
172+
timestamp,
173+
explicitImportRequired,
174+
isWithinCircularImport,
175+
}) {
176+
const [acceptedPathWithoutQuery, query] = acceptedPath.split(`?`)
177+
const importPromise = import(
178+
/* @vite-ignore */
179+
base +
180+
acceptedPathWithoutQuery.slice(1) +
181+
`?${explicitImportRequired ? 'import&' : ''}t=${timestamp}${
182+
query ? `&${query}` : ''
183+
}`
184+
)
185+
if (isWithinCircularImport) {
186+
importPromise.catch(() => {
187+
console.info(
188+
`[hmr] ${acceptedPath} failed to apply HMR as it's within a circular import. Reloading page to reset the execution order. ` +
189+
`To debug and break the circular import, you can run \`vite --debug hmr\` to log the circular dependency path if a file change triggered it.`,
190+
)
191+
pageReload()
192+
})
193+
}
194+
return await importPromise
195+
},
169196
)
170197
transport.connect!(createHMRHandler(handleMessage))
171198

@@ -593,3 +620,41 @@ export function injectQuery(url: string, queryToInject: string): string {
593620
}
594621

595622
export { ErrorOverlay }
623+
624+
declare const DevRuntime: typeof DevRuntimeType
625+
626+
if (isBundleMode && typeof DevRuntime !== 'undefined') {
627+
class ViteDevRuntime extends DevRuntime {
628+
override createModuleHotContext(moduleId: string) {
629+
const ctx = createHotContext(moduleId)
630+
// @ts-expect-error TODO: support CSS properly
631+
ctx._internal = { updateStyle, removeStyle }
632+
return ctx
633+
}
634+
635+
override applyUpdates(_boundaries: [string, string][]): void {
636+
// noop, handled in the HMR client
637+
}
638+
}
639+
640+
const wrappedSocket: Messenger = {
641+
send(message) {
642+
switch (message.type) {
643+
case 'hmr:module-registered': {
644+
transport.send({
645+
type: 'custom',
646+
event: 'vite:module-loaded',
647+
// clone array as the runtime reuses the array instance
648+
data: { modules: message.modules.slice() },
649+
})
650+
break
651+
}
652+
default:
653+
throw new Error(`Unknown message type: ${JSON.stringify(message)}`)
654+
}
655+
},
656+
}
657+
;(globalThis as any).__rolldown_runtime__ ??= new ViteDevRuntime(
658+
wrappedSocket,
659+
)
660+
}

packages/vite/src/node/build.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,7 @@ export function resolveBuildEnvironmentOptions(
420420
raw: BuildEnvironmentOptions,
421421
logger: Logger,
422422
consumer: 'client' | 'server' | undefined,
423+
isBundledDev: boolean,
423424
): ResolvedBuildEnvironmentOptions {
424425
const deprecatedPolyfillModulePreload = raw.polyfillModulePreload
425426
const { polyfillModulePreload, ...rest } = raw
@@ -440,7 +441,7 @@ export function resolveBuildEnvironmentOptions(
440441
{
441442
..._buildEnvironmentOptionsDefaults,
442443
cssCodeSplit: !raw.lib,
443-
minify: consumer === 'server' ? false : 'oxc',
444+
minify: consumer === 'server' || isBundledDev ? false : 'oxc',
444445
rollupOptions: {},
445446
rolldownOptions: undefined,
446447
ssr: consumer === 'server',
@@ -501,9 +502,10 @@ export async function resolveBuildPlugins(config: ResolvedConfig): Promise<{
501502
pre: Plugin[]
502503
post: Plugin[]
503504
}> {
505+
const isBuild = config.command === 'build'
504506
return {
505507
pre: [
506-
...(!config.isWorker ? [prepareOutDirPlugin()] : []),
508+
...(isBuild && !config.isWorker ? [prepareOutDirPlugin()] : []),
507509
perEnvironmentPlugin(
508510
'vite:rollup-options-plugins',
509511
async (environment) =>
@@ -516,11 +518,11 @@ export async function resolveBuildPlugins(config: ResolvedConfig): Promise<{
516518
...(config.isWorker ? [webWorkerPostPlugin(config)] : []),
517519
],
518520
post: [
519-
...buildImportAnalysisPlugin(config),
521+
...(isBuild ? buildImportAnalysisPlugin(config) : []),
520522
...(config.nativePluginEnabledLevel >= 1 ? [] : [buildOxcPlugin()]),
521523
...(config.build.minify === 'esbuild' ? [buildEsbuildPlugin()] : []),
522-
terserPlugin(config),
523-
...(!config.isWorker
524+
...(isBuild ? [terserPlugin(config)] : []),
525+
...(isBuild && !config.isWorker
524526
? [
525527
licensePlugin(),
526528
manifestPlugin(config),
@@ -562,10 +564,10 @@ function resolveConfigToBuild(
562564
)
563565
}
564566

565-
function resolveRolldownOptions(
567+
export function resolveRolldownOptions(
566568
environment: Environment,
567569
chunkMetadataMap: ChunkMetadataMap,
568-
) {
570+
): RolldownOptions {
569571
const { root, packageCache, build: options } = environment.config
570572
const libOptions = options.lib
571573
const { logger } = environment
@@ -883,7 +885,7 @@ async function buildEnvironment(
883885
}
884886
}
885887

886-
function enhanceRollupError(e: RollupError) {
888+
export function enhanceRollupError(e: RollupError): void {
887889
const stackOnly = extractStack(e)
888890

889891
let msg = colors.red((e.plugin ? `[${e.plugin}] ` : '') + e.message)
@@ -1049,7 +1051,7 @@ const dynamicImportWarningIgnoreList = [
10491051
`statically analyzed`,
10501052
]
10511053

1052-
function clearLine() {
1054+
export function clearLine(): void {
10531055
const tty = process.stdout.isTTY && !process.env.CI
10541056
if (tty) {
10551057
process.stdout.clearLine(0)

0 commit comments

Comments
 (0)