From c0dd5ba109d122324ace8eba9ce67efce5f5fec1 Mon Sep 17 00:00:00 2001 From: Sacha STAFYNIAK Date: Sat, 9 Jan 2021 10:47:16 +0100 Subject: [PATCH 1/7] feat(cli): add build --watch option (wip) --- packages/vite/src/node/build.ts | 132 +++++++++++++++++++++++--------- packages/vite/src/node/cli.ts | 1 + 2 files changed, 98 insertions(+), 35 deletions(-) diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index 0c953b276f7c58..b1e7f81f81b790 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -10,7 +10,8 @@ import Rollup, { WarningHandler, WarningHandlerWithDefault, OutputOptions, - RollupOutput + RollupOutput, + RollupWatchOptions } from 'rollup' import { buildReporterPlugin } from './plugins/reporter' import { buildDefinePlugin } from './plugins/define' @@ -141,6 +142,10 @@ export interface BuildOptions { * @internal for now */ ssr?: boolean + /** + * @internal for now + */ + watch?: boolean } export interface LibraryOptions { @@ -171,6 +176,7 @@ export function resolveBuildOptions( manifest: false, lib: false, ssr: false, + watch: false, ...raw } @@ -242,7 +248,7 @@ const paralellBuilds: RollupBuild[] = [] */ export async function build( inlineConfig: InlineConfig = {} -): Promise { +): Promise { parallelCallCounts++ try { return await doBuild(inlineConfig) @@ -257,7 +263,7 @@ export async function build( async function doBuild( inlineConfig: InlineConfig = {} -): Promise { +): Promise { const config = await resolveConfig(inlineConfig, 'build', 'production') config.logger.info(chalk.cyan(`building for production...`)) @@ -272,31 +278,28 @@ async function doBuild( const publicDir = resolve('public') const rollup = require('rollup') as typeof Rollup + const rollupOptions: RollupOptions = { + input, + preserveEntrySignatures: libOptions ? 'strict' : false, + ...options.rollupOptions, + plugins: config.plugins as Plugin[], + onwarn(warning, warn) { + onRollupWarning( + warning, + warn, + config.optimizeDeps?.allowNodeBuiltins, + options.rollupOptions?.onwarn + ) + } + } try { - const bundle = await rollup.rollup({ - input, - preserveEntrySignatures: libOptions ? 'strict' : false, - ...options.rollupOptions, - plugins: config.plugins as Plugin[], - onwarn(warning, warn) { - onRollupWarning( - warning, - warn, - config.optimizeDeps?.allowNodeBuiltins, - options.rollupOptions?.onwarn - ) - } - }) - - paralellBuilds.push(bundle) - const pkgName = libOptions && JSON.parse(lookupFile(config.root, ['package.json']) || `{}`).name - const generate = (output: OutputOptions = {}) => { - return bundle[options.write ? 'write' : 'generate']({ + const buildOuputOptions = (output: OutputOptions = {}): OutputOptions => { + return { dir: outDir, format: 'es', exports: 'auto', @@ -315,13 +318,6 @@ async function doBuild( // #1048 add `Symbol.toStringTag` for module default export namespaceToStringTag: true, ...output - }) - } - - if (options.write) { - emptyDir(outDir) - if (fs.existsSync(publicDir)) { - copyDir(publicDir, outDir) } } @@ -331,14 +327,80 @@ async function doBuild( libOptions, config.logger ) - if (Array.isArray(outputs)) { - const res = [] - for (const output of outputs) { - res.push(await generate(output)) + + if (config.build.watch) { + config.logger.info(chalk.cyan(`watching for file changes...`)) + + const output: OutputOptions[] = [] + if (Array.isArray(outputs)) { + for (const _output of outputs) { + output.push(buildOuputOptions(_output)) + } + } else { + output.push(buildOuputOptions(outputs)) } - return res + + const watcherOptions: RollupWatchOptions = { + ...rollupOptions, + output, + watch: { + clearScreen: true, + chokidar: { + ignored: [ + '**/node_modules/**', + '**/.git/**' + // ...(watchOptions.ignored || []) + ], + ignoreInitial: true, + ignorePermissionErrors: true + // ...watchOptions + } + } + } + const watcher = rollup.watch(watcherOptions) + + watcher.on('event', (event) => { + if (event.code === 'BUNDLE_START') { + if (options.write) { + emptyDir(outDir) + if (fs.existsSync(publicDir)) { + copyDir(publicDir, outDir) + } + } + } else if (event.code === 'BUNDLE_END') { + event.result.close() + config.logger.info(chalk.cyan(`rebuilt in ${event.duration}ms.`)) + } + }) + + // stop watching + watcher.close() } else { - return generate(outputs) + const bundle = await rollup.rollup(rollupOptions) + paralellBuilds.push(bundle) + + const generate = (output: OutputOptions = {}) => { + return bundle[options.write ? 'write' : 'generate']( + buildOuputOptions(output) + ) + } + + if (options.write) { + emptyDir(outDir) + if (fs.existsSync(publicDir)) { + copyDir(publicDir, outDir) + } + } + + if (Array.isArray(outputs)) { + const res = [] + for (const output of outputs) { + res.push(await generate(output)) + } + return res + } else { + return generate(outputs) + } } } catch (e) { config.logger.error( diff --git a/packages/vite/src/node/cli.ts b/packages/vite/src/node/cli.ts index d0a20929fc2051..06a77bd3fbe263 100644 --- a/packages/vite/src/node/cli.ts +++ b/packages/vite/src/node/cli.ts @@ -111,6 +111,7 @@ cli `or specify minifier to use (default: terser)` ) .option('--manifest', `[boolean] emit build manifest json`) + .option('--watch', `[boolean] rebuilds when modules have changed on disk.`) .option('-m, --mode ', `[string] set env mode`) .action(async (root: string, options: BuildOptions & GlobalCLIOptions) => { const { build } = await import('./build') From e076fa318b716eaccdc686e9101c74274aaee738 Mon Sep 17 00:00:00 2001 From: Sacha STAFYNIAK Date: Sat, 9 Jan 2021 13:31:50 +0100 Subject: [PATCH 2/7] feat(cli): rollup watcher configuration --- packages/vite/src/node/build.ts | 78 ++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index b1e7f81f81b790..1224fa8fcd9695 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -11,7 +11,7 @@ import Rollup, { WarningHandlerWithDefault, OutputOptions, RollupOutput, - RollupWatchOptions + WatcherOptions } from 'rollup' import { buildReporterPlugin } from './plugins/reporter' import { buildDefinePlugin } from './plugins/define' @@ -139,13 +139,14 @@ export interface BuildOptions { */ lib?: LibraryOptions | false /** - * @internal for now + * Rollup watch options + * https://rollupjs.org/guide/en/#watchoptions */ - ssr?: boolean + watch?: WatcherOptions | null /** * @internal for now */ - watch?: boolean + ssr?: boolean } export interface LibraryOptions { @@ -176,7 +177,7 @@ export function resolveBuildOptions( manifest: false, lib: false, ssr: false, - watch: false, + watch: null, ...raw } @@ -328,8 +329,9 @@ async function doBuild( config.logger ) + // watch file changes with rollup if (config.build.watch) { - config.logger.info(chalk.cyan(`watching for file changes...`)) + config.logger.info(chalk.cyanBright(`watching for file changes...`)) const output: OutputOptions[] = [] if (Array.isArray(outputs)) { @@ -340,27 +342,28 @@ async function doBuild( output.push(buildOuputOptions(outputs)) } - const watcherOptions: RollupWatchOptions = { + const watcherOptions = config.build.watch + const watcher = rollup.watch({ ...rollupOptions, output, watch: { - clearScreen: true, + ...watcherOptions, chokidar: { ignored: [ '**/node_modules/**', - '**/.git/**' - // ...(watchOptions.ignored || []) + '**/.git/**', + ...(watcherOptions?.chokidar?.ignored || []) ], ignoreInitial: true, - ignorePermissionErrors: true - // ...watchOptions + ignorePermissionErrors: true, + ...watcherOptions.chokidar } } - } - const watcher = rollup.watch(watcherOptions) + }) watcher.on('event', (event) => { if (event.code === 'BUNDLE_START') { + // clean previous files if (options.write) { emptyDir(outDir) if (fs.existsSync(publicDir)) { @@ -369,38 +372,41 @@ async function doBuild( } } else if (event.code === 'BUNDLE_END') { event.result.close() - config.logger.info(chalk.cyan(`rebuilt in ${event.duration}ms.`)) + config.logger.info(chalk.cyanBright(`built in ${event.duration}ms.`)) } }) // stop watching watcher.close() - } else { - const bundle = await rollup.rollup(rollupOptions) - paralellBuilds.push(bundle) - const generate = (output: OutputOptions = {}) => { - return bundle[options.write ? 'write' : 'generate']( - buildOuputOptions(output) - ) - } + return + } - if (options.write) { - emptyDir(outDir) - if (fs.existsSync(publicDir)) { - copyDir(publicDir, outDir) - } + // write or generate files with rollup + const bundle = await rollup.rollup(rollupOptions) + paralellBuilds.push(bundle) + + const generate = (output: OutputOptions = {}) => { + return bundle[options.write ? 'write' : 'generate']( + buildOuputOptions(output) + ) + } + + if (options.write) { + emptyDir(outDir) + if (fs.existsSync(publicDir)) { + copyDir(publicDir, outDir) } + } - if (Array.isArray(outputs)) { - const res = [] - for (const output of outputs) { - res.push(await generate(output)) - } - return res - } else { - return generate(outputs) + if (Array.isArray(outputs)) { + const res = [] + for (const output of outputs) { + res.push(await generate(output)) } + return res + } else { + return generate(outputs) } } catch (e) { config.logger.error( From 8391765224ad97f90328f65339c1d258b5d48334 Mon Sep 17 00:00:00 2001 From: Sacha STAFYNIAK Date: Thu, 18 Mar 2021 18:32:02 +0100 Subject: [PATCH 3/7] fix: output build error when watcher is enabled --- packages/vite/src/node/build.ts | 43 +++++++++++++++++---------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index f0ce9c6b2378ce..6c0bc7d5c035d0 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -13,7 +13,9 @@ import Rollup, { WatcherOptions, ExternalOption, GetManualChunk, - GetModuleInfo + GetModuleInfo, + RollupWatcher, + RollupError } from 'rollup' import { buildReporterPlugin } from './plugins/reporter' import { buildHtmlPlugin } from './plugins/html' @@ -286,7 +288,7 @@ const paralellBuilds: RollupBuild[] = [] */ export async function build( inlineConfig: InlineConfig = {} -): Promise { +): Promise { parallelCallCounts++ try { return await doBuild(inlineConfig) @@ -301,7 +303,7 @@ export async function build( async function doBuild( inlineConfig: InlineConfig = {} -): Promise { +): Promise { const config = await resolveConfig(inlineConfig, 'build', 'production') const options = config.build const ssr = !!options.ssr @@ -377,6 +379,19 @@ async function doBuild( } } + const outputBuildError = (e: RollupError) => { + config.logger.error( + chalk.red(`${e.plugin ? `[${e.plugin}] ` : ``}${e.message}`) + ) + if (e.id) { + const loc = e.loc ? `:${e.loc.line}:${e.loc.column}` : `` + config.logger.error(`file: ${chalk.cyan(`${e.id}${loc}`)}`) + } + if (e.frame) { + config.logger.error(chalk.yellow(e.frame)) + } + } + try { const pkgName = libOptions && getPkgName(config.root) @@ -464,13 +479,15 @@ async function doBuild( } else if (event.code === 'BUNDLE_END') { event.result.close() config.logger.info(chalk.cyanBright(`built in ${event.duration}ms.`)) + } else if (event.code === 'ERROR') { + outputBuildError(event.error) } }) // stop watching watcher.close() - return + return watcher } // write or generate files with rollup @@ -508,13 +525,6 @@ async function doBuild( } } - // // resolve lib mode outputs - // const outputs = resolveBuildOutputs( - // options.rollupOptions?.output, - // libOptions, - // config.logger - // ) - if (Array.isArray(outputs)) { const res = [] for (const output of outputs) { @@ -525,16 +535,7 @@ async function doBuild( return await generate(outputs) } } catch (e) { - config.logger.error( - chalk.red(`${e.plugin ? `[${e.plugin}] ` : ``}${e.message}`) - ) - if (e.id) { - const loc = e.loc ? `:${e.loc.line}:${e.loc.column}` : `` - config.logger.error(`file: ${chalk.cyan(`${e.id}${loc}`)}`) - } - if (e.frame) { - config.logger.error(chalk.yellow(e.frame)) - } + outputBuildError(e) throw e } } From e7720d2d314022c4282d448f49528952172144bb Mon Sep 17 00:00:00 2001 From: Sacha STAFYNIAK Date: Fri, 19 Mar 2021 17:10:16 +0100 Subject: [PATCH 4/7] chore: fix nitpick and apply contributing guidelines --- packages/vite/src/node/build.ts | 18 +++++++++--------- packages/vite/src/node/cli.ts | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index 6c0bc7d5c035d0..972b7d482fa324 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -10,10 +10,10 @@ import Rollup, { WarningHandler, OutputOptions, RollupOutput, - WatcherOptions, ExternalOption, GetManualChunk, GetModuleInfo, + WatcherOptions, RollupWatcher, RollupError } from 'rollup' @@ -159,11 +159,6 @@ export interface BuildOptions { * configurations that are suitable for distributing libraries. */ lib?: LibraryOptions | false - /** - * Rollup watch options - * https://rollupjs.org/guide/en/#watchoptions - */ - watch?: WatcherOptions | null /** * Produce SSR oriented build. Note this requires specifying SSR entry via * `rollupOptions.input`. @@ -184,6 +179,11 @@ export interface BuildOptions { * @default 500 */ chunkSizeWarningLimit?: number + /** + * Rollup watch options + * https://rollupjs.org/guide/en/#watchoptions + */ + watch?: WatcherOptions | null } export interface LibraryOptions { @@ -219,10 +219,10 @@ export function resolveBuildOptions(raw?: BuildOptions): ResolvedBuildOptions { manifest: false, lib: false, ssr: false, - watch: null, ssrManifest: false, brotliSize: true, chunkSizeWarningLimit: 500, + watch: null, ...raw } @@ -381,10 +381,10 @@ async function doBuild( const outputBuildError = (e: RollupError) => { config.logger.error( - chalk.red(`${e.plugin ? `[${e.plugin}] ` : ``}${e.message}`) + chalk.red(`${e.plugin ? `[${e.plugin}] ` : ''}${e.message}`) ) if (e.id) { - const loc = e.loc ? `:${e.loc.line}:${e.loc.column}` : `` + const loc = e.loc ? `:${e.loc.line}:${e.loc.column}` : '' config.logger.error(`file: ${chalk.cyan(`${e.id}${loc}`)}`) } if (e.frame) { diff --git a/packages/vite/src/node/cli.ts b/packages/vite/src/node/cli.ts index 480d143f07493c..27abf6c4fca1e9 100644 --- a/packages/vite/src/node/cli.ts +++ b/packages/vite/src/node/cli.ts @@ -124,13 +124,13 @@ cli `or specify minifier to use (default: terser)` ) .option('--manifest', `[boolean] emit build manifest json`) - .option('--watch', `[boolean] rebuilds when modules have changed on disk.`) .option('--ssrManifest', `[boolean] emit ssr manifest json`) .option( '--emptyOutDir', `[boolean] force empty outDir when it's outside of root` ) .option('-m, --mode ', `[string] set env mode`) + .option('--watch', `[boolean] rebuilds when modules have changed on disk`) .action(async (root: string, options: BuildOptions & GlobalCLIOptions) => { const { build } = await import('./build') const buildOptions = cleanOptions(options) as BuildOptions From 52a7404ac73e989173d33b903d9a5a7497c080a5 Mon Sep 17 00:00:00 2001 From: Sacha STAFYNIAK Date: Fri, 2 Apr 2021 22:09:40 +0200 Subject: [PATCH 5/7] chore: add -w option shorthand to build --watch, improve watch output --- packages/vite/src/node/build.ts | 4 +++- packages/vite/src/node/cli.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index b42a8976c3f758..56e2c7422a67de 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -437,7 +437,7 @@ async function doBuild( // watch file changes with rollup if (config.build.watch) { - config.logger.info(chalk.cyanBright(`watching for file changes...`)) + config.logger.info(chalk.cyanBright(`\nwatching for file changes...`)) const output: OutputOptions[] = [] if (Array.isArray(outputs)) { @@ -469,6 +469,8 @@ async function doBuild( watcher.on('event', (event) => { if (event.code === 'BUNDLE_START') { + config.logger.info(chalk.cyanBright(`\nbuild started...`)) + // clean previous files if (options.write) { emptyDir(outDir) diff --git a/packages/vite/src/node/cli.ts b/packages/vite/src/node/cli.ts index 7eb84a495de6e3..41ed363388d7a7 100644 --- a/packages/vite/src/node/cli.ts +++ b/packages/vite/src/node/cli.ts @@ -130,7 +130,7 @@ cli `[boolean] force empty outDir when it's outside of root` ) .option('-m, --mode ', `[string] set env mode`) - .option('--watch', `[boolean] rebuilds when modules have changed on disk`) + .option('-w, --watch', `[boolean] rebuilds when modules have changed on disk`) .action(async (root: string, options: BuildOptions & GlobalCLIOptions) => { const { build } = await import('./build') const buildOptions = cleanOptions(options) as BuildOptions From fad683267bb90e74c1c16dfe739f6d2e7b4320a1 Mon Sep 17 00:00:00 2001 From: Sacha STAFYNIAK Date: Fri, 2 Apr 2021 23:50:15 +0200 Subject: [PATCH 6/7] chore: add build --watch documentation --- docs/config/index.md | 7 +++++++ docs/guide/build.md | 15 +++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/docs/config/index.md b/docs/config/index.md index 6f85e92e58e082..4e8a71a436dd3a 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -557,6 +557,13 @@ export default async ({ command, mode }) => { - **Default:** `500` Limit for chunk size warnings (in kbs). + +### build.watch + +- **Type:** [`WatcherOptions`](https://rollupjs.org/guide/en/#watch-options)`| null` +- **Default:** `null` + + Set to `{}` to enable rollup watcher. This is mostly used in cases that involve build-only plugins or integrations processes. ## Dep Optimization Options diff --git a/docs/guide/build.md b/docs/guide/build.md index 0f8ea3f681f25e..dd0c940e2fbf50 100644 --- a/docs/guide/build.md +++ b/docs/guide/build.md @@ -46,6 +46,21 @@ module.exports = { For example, you can specify multiple Rollup outputs with plugins that are only applied during build. +## Rebuild on files changes + +You can enable rollup watcher with `vite build --watch`. Or, you can directly adjust the underlying [`WatcherOptions`](https://rollupjs.org/guide/en/#watch-options) via `build.watch`: + +```js +// vite.config.js +module.exports = { + build: { + watch: { + // https://rollupjs.org/guide/en/#watch-options + } + } +} +``` + ## Multi-Page App Suppose you have the following source code structure: From ca52d84d6c734595000b9d45c0d515a71862c429 Mon Sep 17 00:00:00 2001 From: Sacha STAFYNIAK Date: Mon, 5 Apr 2021 14:50:34 +0200 Subject: [PATCH 7/7] dx: typo nitpicking --- packages/vite/src/node/build.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index 56e2c7422a67de..73d520675206ee 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -441,8 +441,8 @@ async function doBuild( const output: OutputOptions[] = [] if (Array.isArray(outputs)) { - for (const _output of outputs) { - output.push(buildOuputOptions(_output)) + for (const resolvedOutput of outputs) { + output.push(buildOuputOptions(resolvedOutput)) } } else { output.push(buildOuputOptions(outputs))