From 82412fc6fe5e2c7b7701d80f213bf6ed70f57eb6 Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Mon, 18 Nov 2024 17:05:38 +0900 Subject: [PATCH] feat: use Rolldown's watch API --- packages/vite/src/node/build.ts | 97 +++++++++++----------- packages/vite/src/node/index.ts | 2 +- playground/assets/__tests__/assets.spec.ts | 3 +- playground/vitestSetup.ts | 25 +++--- 4 files changed, 67 insertions(+), 60 deletions(-) diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index 4648600a0445db..2b062751ead0c0 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -14,7 +14,7 @@ import type { RollupLog, RollupOptions, RollupOutput, - // RollupWatcher, + watch as rolldownWatch, // WatcherOptions, } from 'rolldown' import { @@ -65,7 +65,7 @@ import { findNearestPackageData } from './packages' import type { PackageCache } from './packages' import { getResolvedOutDirs, - // resolveChokidarOptions, + resolveChokidarOptions, resolveEmptyOutDir, } from './watch' import { completeSystemWrapPlugin } from './plugins/completeSystemWrap' @@ -79,6 +79,9 @@ import { import type { MinimalPluginContext, Plugin, PluginContext } from './plugin' import type { RollupPluginHooks } from './typeUtils' +export type RollupWatcher = Awaited> +type WatcherOptions = { _: never } + export interface BuildEnvironmentOptions { /** * Compatibility transform target. The transform is performed with esbuild @@ -272,7 +275,7 @@ export interface BuildEnvironmentOptions { * https://rollupjs.org/configuration-options/#watch * @default null */ - // watch?: WatcherOptions | null + watch?: WatcherOptions | null /** * create the Build Environment instance */ @@ -536,7 +539,7 @@ export async function resolveBuildPlugins(config: ResolvedConfig): Promise<{ */ export async function build( inlineConfig: InlineConfig = {}, -): Promise { +): Promise { const builder = await createBuilder(inlineConfig, true) const environment = Object.values(builder.environments)[0] if (!environment) throw new Error('No environment found') @@ -564,7 +567,7 @@ function resolveConfigToBuild( **/ async function buildEnvironment( environment: BuildEnvironment, -): Promise { +): Promise { const { root, packageCache } = environment.config const options = environment.config.build const libOptions = options.lib @@ -699,11 +702,11 @@ async function buildEnvironment( } } - // const outputBuildError = (e: RollupError) => { - // enhanceRollupError(e) - // clearLine() - // logger.error(e.message, { error: e }) - // } + const outputBuildError = (e: RollupError) => { + enhanceRollupError(e) + clearLine() + logger.error(e.message, { error: e }) + } let bundle: RollupBuild | undefined let startTime: number | undefined @@ -806,42 +809,42 @@ async function buildEnvironment( ) // watch file changes with rollup - // if (options.watch) { - // logger.info(colors.cyan(`\nwatching for file changes...`)) - - // const resolvedChokidarOptions = resolveChokidarOptions( - // options.watch.chokidar, - // resolvedOutDirs, - // emptyOutDir, - // environment.config.cacheDir, - // ) - - // const { watch } = await import('rolldown') - // const watcher = watch({ - // ...rollupOptions, - // output: normalizedOutputs, - // watch: { - // ...options.watch, - // chokidar: resolvedChokidarOptions, - // }, - // }) - - // watcher.on('event', (event) => { - // if (event.code === 'BUNDLE_START') { - // logger.info(colors.cyan(`\nbuild started...`)) - // if (options.write) { - // prepareOutDir(resolvedOutDirs, emptyOutDir, environment) - // } - // } else if (event.code === 'BUNDLE_END') { - // event.result.close() - // logger.info(colors.cyan(`built in ${event.duration}ms.`)) - // } else if (event.code === 'ERROR') { - // outputBuildError(event.error) - // } - // }) - - // return watcher - // } + if (options.watch) { + logger.info(colors.cyan(`\nwatching for file changes...`)) + + const resolvedChokidarOptions = resolveChokidarOptions( + {}, // options.watch.chokidar, + resolvedOutDirs, + emptyOutDir, + environment.config.cacheDir, + ) + + const { watch } = await import('rolldown') + const watcher = await watch({ + ...rollupOptions, + output: normalizedOutputs[0], // normalizedOutputs, + watch: { + ...options.watch, + chokidar: resolvedChokidarOptions, + }, + }) + + watcher.on('event', (event) => { + if (event.code === 'BUNDLE_START') { + logger.info(colors.cyan(`\nbuild started...`)) + if (options.write) { + prepareOutDir(resolvedOutDirs, emptyOutDir, environment) + } + } else if (event.code === 'BUNDLE_END') { + // event.result.close() + logger.info(colors.cyan(`built in ${event.duration}ms.`)) + } else if (event.code === 'ERROR') { + outputBuildError(event.error) + } + }) + + return watcher + } // write or generate files with rollup const { rolldown } = await import('rolldown') @@ -1502,7 +1505,7 @@ export interface ViteBuilder { buildApp(): Promise build( environment: BuildEnvironment, - ): Promise + ): Promise } export interface BuilderOptions { diff --git a/packages/vite/src/node/index.ts b/packages/vite/src/node/index.ts index 04b5c7d8d6e621..abf2f9c986a323 100644 --- a/packages/vite/src/node/index.ts +++ b/packages/vite/src/node/index.ts @@ -12,7 +12,7 @@ export { perEnvironmentPlugin } from './plugin' export { perEnvironmentState } from './environment' export { createServer } from './server' export { preview } from './preview' -export { build, createBuilder } from './build' +export { build, createBuilder, type RollupWatcher } from './build' export { optimizeDeps } from './optimizer' export { createIdResolver } from './idResolver' diff --git a/playground/assets/__tests__/assets.spec.ts b/playground/assets/__tests__/assets.spec.ts index b16ed048c49f1f..a6842564aa022e 100644 --- a/playground/assets/__tests__/assets.spec.ts +++ b/playground/assets/__tests__/assets.spec.ts @@ -550,8 +550,7 @@ test.runIf(isBuild)('manifest', async () => { } }) -// TODO: rolldown does not support rebuild -describe.runIf(isBuild).skip('css and assets in css in build watch', () => { +describe.runIf(isBuild)('css and assets in css in build watch', () => { test('css will not be lost and css does not contain undefined', async () => { editFile('index.html', (code) => code.replace('Assets', 'assets'), true) await notifyRebuildComplete(watcher) diff --git a/playground/vitestSetup.ts b/playground/vitestSetup.ts index 1e2d469c86f5e0..84a6f8a210b9d3 100644 --- a/playground/vitestSetup.ts +++ b/playground/vitestSetup.ts @@ -8,6 +8,7 @@ import type { Logger, PluginOption, ResolvedConfig, + RollupWatcher, UserConfig, ViteDevServer, } from 'vite' @@ -20,7 +21,7 @@ import { preview, } from 'vite' import type { Browser, Page } from 'playwright-chromium' -import type { RollupError, RollupWatcher, RollupWatcherEvent } from 'rollup' +import type { RollupError, RollupWatcherEvent } from 'rollup' import type { RunnerTestFile } from 'vitest' import { beforeAll, inject } from 'vitest' @@ -72,7 +73,7 @@ export let resolvedConfig: ResolvedConfig = undefined! export let page: Page = undefined! export let browser: Browser = undefined! export let viteTestUrl: string = '' -export const watcher: RollupWatcher | undefined = undefined +export let watcher: RollupWatcher | undefined = undefined export function setViteUrl(url: string): void { viteTestUrl = url @@ -273,13 +274,14 @@ export async function startDefaultServe(): Promise { const builder = await createBuilder(buildConfig) await builder.buildApp() } else { - /* const rollupOutput = */ await build(buildConfig) - // const isWatch = !!resolvedConfig!.build.watch - // // in build watch,call startStaticServer after the build is complete - // if (isWatch) { - // watcher = rollupOutput as RollupWatcher - // await notifyRebuildComplete(watcher) - // } + const rollupOutput = await build(buildConfig) + const isWatch = !!resolvedConfig!.build.watch + // in build watch,call startStaticServer after the build is complete + if (isWatch) { + watcher = rollupOutput as RollupWatcher + await notifyRebuildComplete(watcher) + await new Promise((resolve) => setTimeout(resolve, 1000)) + } if (buildConfig.__test__) { buildConfig.__test__() } @@ -315,7 +317,10 @@ export async function notifyRebuildComplete( await new Promise((resolve) => { resolveFn = resolve }) - return watcher.off('event', callback) + // During tests we edit the files too fast and sometimes chokidar + // misses change events, so wait 100ms for consistency + await new Promise((resolve) => setTimeout(resolve, 100)) + return watcher // watcher.off('event', callback) } export function createInMemoryLogger(logs: string[]): Logger {