Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
9db2c72
feat: add experimental.fullBundleMode
sapphi-red May 27, 2025
e466415
feat: add `--fullBundleMode` flag for `vite dev`
sapphi-red May 27, 2025
9af37a8
feat: add `ResolvedConfig.isBundled`
sapphi-red May 27, 2025
9476366
feat: disable minify by default in development
sapphi-red Jun 4, 2025
1f05a2d
feat: disable json minify by default in development
sapphi-red Jun 4, 2025
178f573
Revert "feat: disable minify by default in development"
sapphi-red Jun 16, 2025
b92fbdf
Revert "feat: disable json minify by default in development"
sapphi-red Jun 16, 2025
77b9198
refactor: make `invalidateModule` function in DevEnvironment a method
sapphi-red Jun 13, 2025
da9dd70
feat: disable minify by default in full bundle mode
sapphi-red Jun 16, 2025
d596881
feat: disable buildImportAnalysisPlugin for full bundle mode
sapphi-red Jun 16, 2025
0042906
wip: full bundle dev env
sapphi-red May 27, 2025
e7bc97b
wip: revamp state handling
sapphi-red Jun 5, 2025
6a4dc96
wip: full bundle dev env
sapphi-red Jun 6, 2025
abb9682
test: add test for basic scenarios
sapphi-red Jun 10, 2025
e2bb620
wip: support assets
sapphi-red Jul 9, 2025
e1fb1f7
wip: update for new rolldown
sapphi-red Jul 11, 2025
8eae017
perf: skip warmup requests
sapphi-red Jul 15, 2025
3924b99
perf: avoid buildStart hook call
sapphi-red Jul 15, 2025
c3a3fac
wip: full bundle dev env
sapphi-red Jul 18, 2025
c921410
wip: update for new rolldown
sapphi-red Jul 30, 2025
1b964a9
wip: simplify
sapphi-red Jul 31, 2025
0969c53
wip: skip optimizerResolvePlugin
sapphi-red Jul 31, 2025
7e9f126
wip: change flag to --full-bundle
sapphi-red Jul 31, 2025
04aca34
wip: fix dynamic import vars plugin
sapphi-red Aug 1, 2025
8dcf3b9
wip: fix define/modulePreloadPolyfill plugin
sapphi-red Aug 4, 2025
875a8a5
perf: skip worker renderChunk in dev
sapphi-red Aug 4, 2025
47b7e05
wip: add debug time
sapphi-red Aug 4, 2025
213eeab
perf: copy files lazily
sapphi-red Aug 4, 2025
4f6f5fc
wip: disable renderBuiltUrl in dev
sapphi-red Aug 5, 2025
c3883ca
wip: pass path as-is to `hmrInvalidate`
sapphi-red Aug 12, 2025
8b69238
wip: full bundle dev env
sapphi-red Aug 22, 2025
ae87d9a
wip: full bundle dev env
sapphi-red Aug 27, 2025
5cb8ade
wip: full bundle dev env
sapphi-red Aug 27, 2025
1a04bea
wip: full bundle dev env
sapphi-red Aug 27, 2025
b7efbbf
wip: full bundle dev env
sapphi-red Aug 27, 2025
ccee1d3
wip: update
sapphi-red Sep 11, 2025
89cb603
wip: update
sapphi-red Sep 11, 2025
ddc6aba
wip: update
sapphi-red Sep 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 74 additions & 25 deletions packages/vite/src/client/client.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/// <reference types="rolldown/experimental/runtime-types" />
import type { ErrorPayload, HotPayload } from 'types/hmrPayload'
import type { ViteHotContext } from 'types/hot'
import { HMRClient, HMRContext } from '../shared/hmr'
Expand All @@ -20,6 +21,7 @@ declare const __HMR_BASE__: string
declare const __HMR_TIMEOUT__: number
declare const __HMR_ENABLE_OVERLAY__: boolean
declare const __WS_TOKEN__: string
declare const __FULL_BUNDLE_MODE__: boolean

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

Expand All @@ -37,6 +39,7 @@ const directSocketHost = __HMR_DIRECT_TARGET__
const base = __BASE__ || '/'
const hmrTimeout = __HMR_TIMEOUT__
const wsToken = __WS_TOKEN__
const isFullBundleMode = __FULL_BUNDLE_MODE__

const transport = normalizeModuleRunnerTransport(
(() => {
Expand Down Expand Up @@ -140,32 +143,53 @@ const hmrClient = new HMRClient(
debug: (...msg) => console.debug('[vite]', ...msg),
},
transport,
async function importUpdatedModule({
acceptedPath,
timestamp,
explicitImportRequired,
isWithinCircularImport,
}) {
const [acceptedPathWithoutQuery, query] = acceptedPath.split(`?`)
const importPromise = import(
/* @vite-ignore */
base +
acceptedPathWithoutQuery.slice(1) +
`?${explicitImportRequired ? 'import&' : ''}t=${timestamp}${
query ? `&${query}` : ''
}`
)
if (isWithinCircularImport) {
importPromise.catch(() => {
console.info(
`[hmr] ${acceptedPath} failed to apply HMR as it's within a circular import. Reloading page to reset the execution order. ` +
`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.`,
isFullBundleMode
? async function importUpdatedModule({
url,
acceptedPath,
isWithinCircularImport,
}) {
const importPromise = import(base + url!).then(() =>
// @ts-expect-error globalThis.__rolldown_runtime__
globalThis.__rolldown_runtime__.loadExports(acceptedPath),
)
pageReload()
})
}
return await importPromise
},
if (isWithinCircularImport) {
importPromise.catch(() => {
console.info(
`[hmr] ${acceptedPath} failed to apply HMR as it's within a circular import. Reloading page to reset the execution order. ` +
`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.`,
)
pageReload()
})
}
return await importPromise
}
: async function importUpdatedModule({
acceptedPath,
timestamp,
explicitImportRequired,
isWithinCircularImport,
}) {
const [acceptedPathWithoutQuery, query] = acceptedPath.split(`?`)
const importPromise = import(
/* @vite-ignore */
base +
acceptedPathWithoutQuery.slice(1) +
`?${explicitImportRequired ? 'import&' : ''}t=${timestamp}${
query ? `&${query}` : ''
}`
)
if (isWithinCircularImport) {
importPromise.catch(() => {
console.info(
`[hmr] ${acceptedPath} failed to apply HMR as it's within a circular import. Reloading page to reset the execution order. ` +
`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.`,
)
pageReload()
})
}
return await importPromise
},
)
transport.connect!(createHMRHandler(handleMessage))

Expand Down Expand Up @@ -575,3 +599,28 @@ export function injectQuery(url: string, queryToInject: string): string {
}

export { ErrorOverlay }

if (isFullBundleMode && typeof DevRuntime !== 'undefined') {
class ViteDevRuntime extends DevRuntime {
override createModuleHotContext(moduleId: string) {
const ctx = createHotContext(moduleId)
// @ts-expect-error TODO: support CSS
ctx._internal = {
updateStyle,
removeStyle,
}
// @ts-expect-error TODO: support this function (used by plugin-react)
ctx.getExports = async () =>
// @ts-expect-error __rolldown_runtime__ / ctx.ownerPath
__rolldown_runtime__.loadExports(ctx.ownerPath)
return ctx
}

override applyUpdates(_boundaries: string[]): void {
// TODO: how should this be handled?
// noop, handled in the HMR client
}
}

;(globalThis as any).__rolldown_runtime__ ??= new ViteDevRuntime()
}
20 changes: 11 additions & 9 deletions packages/vite/src/node/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ export function resolveBuildEnvironmentOptions(
raw: BuildEnvironmentOptions,
logger: Logger,
consumer: 'client' | 'server' | undefined,
isFullBundledDev: boolean,
): ResolvedBuildEnvironmentOptions {
const deprecatedPolyfillModulePreload = raw.polyfillModulePreload
const { polyfillModulePreload, ...rest } = raw
Expand All @@ -427,7 +428,7 @@ export function resolveBuildEnvironmentOptions(
{
...buildEnvironmentOptionsDefaults,
cssCodeSplit: !raw.lib,
minify: consumer === 'server' ? false : 'oxc',
minify: consumer === 'server' || isFullBundledDev ? false : 'oxc',
rollupOptions: {},
rolldownOptions: undefined,
ssr: consumer === 'server',
Expand Down Expand Up @@ -488,10 +489,11 @@ export async function resolveBuildPlugins(config: ResolvedConfig): Promise<{
pre: Plugin[]
post: Plugin[]
}> {
const isBuild = config.command === 'build'
return {
pre: [
completeSystemWrapPlugin(),
...(!config.isWorker ? [prepareOutDirPlugin()] : []),
...(isBuild && !config.isWorker ? [prepareOutDirPlugin()] : []),
perEnvironmentPlugin(
'vite:rollup-options-plugins',
async (environment) =>
Expand All @@ -504,11 +506,11 @@ export async function resolveBuildPlugins(config: ResolvedConfig): Promise<{
...(config.isWorker ? [webWorkerPostPlugin(config)] : []),
],
post: [
...buildImportAnalysisPlugin(config),
...(isBuild ? buildImportAnalysisPlugin(config) : []),
...(config.nativePluginEnabledLevel >= 1 ? [] : [buildOxcPlugin()]),
...(config.build.minify === 'esbuild' ? [buildEsbuildPlugin()] : []),
terserPlugin(config),
...(!config.isWorker
...(isBuild ? [terserPlugin(config)] : []),
...(isBuild && !config.isWorker
? [
manifestPlugin(config),
ssrManifestPlugin(),
Expand Down Expand Up @@ -549,10 +551,10 @@ function resolveConfigToBuild(
)
}

function resolveRolldownOptions(
export function resolveRolldownOptions(
environment: Environment,
chunkMetadataMap: ChunkMetadataMap,
) {
): RolldownOptions {
const { root, packageCache, build: options } = environment.config
const libOptions = options.lib
const { logger } = environment
Expand Down Expand Up @@ -874,7 +876,7 @@ async function buildEnvironment(
}
}

function enhanceRollupError(e: RollupError) {
export function enhanceRollupError(e: RollupError): void {
const stackOnly = extractStack(e)

let msg = colors.red((e.plugin ? `[${e.plugin}] ` : '') + e.message)
Expand Down Expand Up @@ -1040,7 +1042,7 @@ const dynamicImportWarningIgnoreList = [
`statically analyzed`,
]

function clearLine() {
export function clearLine(): void {
const tty = process.stdout.isTTY && !process.env.CI
if (tty) {
process.stdout.clearLine(0)
Expand Down
168 changes: 92 additions & 76 deletions packages/vite/src/node/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ interface GlobalCLIOptions {
w?: boolean
}

interface ExperimentalDevOptions {
fullBundle?: boolean
}

interface BuilderCLIOptions {
app?: boolean
}
Expand Down Expand Up @@ -195,93 +199,105 @@ cli
'--force',
`[boolean] force the optimizer to ignore the cache and re-bundle`,
)
.action(async (root: string, options: ServerOptions & GlobalCLIOptions) => {
filterDuplicateOptions(options)
// output structure is preserved even after bundling so require()
// is ok here
const { createServer } = await import('./server')
try {
const server = await createServer({
root,
base: options.base,
mode: options.mode,
configFile: options.config,
configLoader: options.configLoader,
logLevel: options.logLevel,
clearScreen: options.clearScreen,
server: cleanGlobalCLIOptions(options),
forceOptimizeDeps: options.force,
})
.option('--fullBundle', `[boolean] use experimental full bundle mode`)
.action(
async (
root: string,
options: ServerOptions & ExperimentalDevOptions & GlobalCLIOptions,
) => {
filterDuplicateOptions(options)
// output structure is preserved even after bundling so require()
// is ok here
const { createServer } = await import('./server')
try {
const server = await createServer({
root,
base: options.base,
mode: options.mode,
configFile: options.config,
configLoader: options.configLoader,
logLevel: options.logLevel,
clearScreen: options.clearScreen,
server: cleanGlobalCLIOptions(options),
forceOptimizeDeps: options.force,
experimental: {
fullBundleMode: options.fullBundle,
},
})

if (!server.httpServer) {
throw new Error('HTTP server not available')
}
if (!server.httpServer) {
throw new Error('HTTP server not available')
}

await server.listen()
await server.listen()

const info = server.config.logger.info
const info = server.config.logger.info

const modeString =
options.mode && options.mode !== 'development'
? ` ${colors.bgGreen(` ${colors.bold(options.mode)} `)}`
const modeString =
options.mode && options.mode !== 'development'
? ` ${colors.bgGreen(` ${colors.bold(options.mode)} `)}`
: ''
const viteStartTime = global.__vite_start_time ?? false
const startupDurationString = viteStartTime
? colors.dim(
`ready in ${colors.reset(
colors.bold(Math.ceil(performance.now() - viteStartTime)),
)} ms`,
)
: ''
const viteStartTime = global.__vite_start_time ?? false
const startupDurationString = viteStartTime
? colors.dim(
`ready in ${colors.reset(
colors.bold(Math.ceil(performance.now() - viteStartTime)),
)} ms`,
)
: ''
const hasExistingLogs =
process.stdout.bytesWritten > 0 || process.stderr.bytesWritten > 0
const hasExistingLogs =
process.stdout.bytesWritten > 0 || process.stderr.bytesWritten > 0

info(
`\n ${colors.green(
`${colors.bold('ROLLDOWN-VITE')} v${VERSION}`,
)}${modeString} ${startupDurationString}\n`,
{
clear: !hasExistingLogs,
},
)
info(
`\n ${colors.green(
`${colors.bold('ROLLDOWN-VITE')} v${VERSION}`,
)}${modeString} ${startupDurationString}\n`,
{
clear: !hasExistingLogs,
},
)

server.printUrls()
const customShortcuts: CLIShortcut<typeof server>[] = []
if (profileSession) {
customShortcuts.push({
key: 'p',
description: 'start/stop the profiler',
async action(server) {
if (profileSession) {
await stopProfiler(server.config.logger.info)
} else {
const inspector = await import('node:inspector').then(
(r) => r.default,
)
await new Promise<void>((res) => {
profileSession = new inspector.Session()
profileSession.connect()
profileSession.post('Profiler.enable', () => {
profileSession!.post('Profiler.start', () => {
server.config.logger.info('Profiler started')
res()
server.printUrls()
const customShortcuts: CLIShortcut<typeof server>[] = []
if (profileSession) {
customShortcuts.push({
key: 'p',
description: 'start/stop the profiler',
async action(server) {
if (profileSession) {
await stopProfiler(server.config.logger.info)
} else {
const inspector = await import('node:inspector').then(
(r) => r.default,
)
await new Promise<void>((res) => {
profileSession = new inspector.Session()
profileSession.connect()
profileSession.post('Profiler.enable', () => {
profileSession!.post('Profiler.start', () => {
server.config.logger.info('Profiler started')
res()
})
})
})
})
}
}
},
})
}
server.bindCLIShortcuts({ print: true, customShortcuts })
} catch (e) {
const logger = createLogger(options.logLevel)
logger.error(
colors.red(`error when starting dev server:\n${e.stack}`),
{
error: e,
},
})
)
await stopProfiler(logger.info)
process.exit(1)
}
server.bindCLIShortcuts({ print: true, customShortcuts })
} catch (e) {
const logger = createLogger(options.logLevel)
logger.error(colors.red(`error when starting dev server:\n${e.stack}`), {
error: e,
})
await stopProfiler(logger.info)
process.exit(1)
}
})
},
)

// build
cli
Expand Down
Loading
Loading