Skip to content

Commit

Permalink
feat(cli): build watch mode, fix vitejs#1434 (vitejs#1449)
Browse files Browse the repository at this point in the history
  • Loading branch information
stafyniaksacha committed Apr 5, 2021
1 parent 2a89c57 commit 0dc6e37
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 38 deletions.
7 changes: 7 additions & 0 deletions docs/config/index.md
Expand Up @@ -561,6 +561,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

Expand Down
15 changes: 15 additions & 0 deletions docs/guide/build.md
Expand Up @@ -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:
Expand Down
154 changes: 116 additions & 38 deletions packages/vite/src/node/build.ts
Expand Up @@ -12,7 +12,10 @@ import Rollup, {
RollupOutput,
ExternalOption,
GetManualChunk,
GetModuleInfo
GetModuleInfo,
WatcherOptions,
RollupWatcher,
RollupError
} from 'rollup'
import { buildReporterPlugin } from './plugins/reporter'
import { buildHtmlPlugin } from './plugins/html'
Expand Down Expand Up @@ -176,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 {
Expand Down Expand Up @@ -214,6 +222,7 @@ export function resolveBuildOptions(raw?: BuildOptions): ResolvedBuildOptions {
ssrManifest: false,
brotliSize: true,
chunkSizeWarningLimit: 500,
watch: null,
...raw
}

Expand Down Expand Up @@ -279,7 +288,7 @@ const parallelBuilds: RollupBuild[] = []
*/
export async function build(
inlineConfig: InlineConfig = {}
): Promise<RollupOutput | RollupOutput[]> {
): Promise<RollupOutput | RollupOutput[] | RollupWatcher> {
parallelCallCounts++
try {
return await doBuild(inlineConfig)
Expand All @@ -294,7 +303,7 @@ export async function build(

async function doBuild(
inlineConfig: InlineConfig = {}
): Promise<RollupOutput | RollupOutput[]> {
): Promise<RollupOutput | RollupOutput[] | RollupWatcher> {
const config = await resolveConfig(inlineConfig, 'build', 'production')
const options = config.build
const ssr = !!options.ssr
Expand Down Expand Up @@ -355,29 +364,39 @@ async function doBuild(
}

const rollup = require('rollup') as typeof Rollup
const rollupOptions: RollupOptions = {
input,
preserveEntrySignatures: ssr
? 'allow-extension'
: libOptions
? 'strict'
: false,
...options.rollupOptions,
plugins,
external,
onwarn(warning, warn) {
onRollupWarning(warning, warn, config)
}
}

try {
const bundle = await rollup.rollup({
input,
preserveEntrySignatures: ssr
? 'allow-extension'
: libOptions
? 'strict'
: false,
...options.rollupOptions,
plugins,
external,
onwarn(warning, warn) {
onRollupWarning(warning, warn, config)
}
})

parallelBuilds.push(bundle)
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)

const generate = (output: OutputOptions = {}) => {
return bundle[options.write ? 'write' : 'generate']({
const buildOuputOptions = (output: OutputOptions = {}): OutputOptions => {
return {
dir: outDir,
format: ssr ? 'cjs' : 'es',
exports: ssr ? 'named' : 'auto',
Expand Down Expand Up @@ -406,7 +425,81 @@ async function doBuild(
? createMoveToVendorChunkFn(config)
: undefined,
...output
}
}

// resolve lib mode outputs
const outputs = resolveBuildOutputs(
options.rollupOptions?.output,
libOptions,
config.logger
)

// watch file changes with rollup
if (config.build.watch) {
config.logger.info(chalk.cyanBright(`\nwatching for file changes...`))

const output: OutputOptions[] = []
if (Array.isArray(outputs)) {
for (const resolvedOutput of outputs) {
output.push(buildOuputOptions(resolvedOutput))
}
} else {
output.push(buildOuputOptions(outputs))
}

const watcherOptions = config.build.watch
const watcher = rollup.watch({
...rollupOptions,
output,
watch: {
...watcherOptions,
chokidar: {
ignored: [
'**/node_modules/**',
'**/.git/**',
...(watcherOptions?.chokidar?.ignored || [])
],
ignoreInitial: true,
ignorePermissionErrors: true,
...watcherOptions.chokidar
}
}
})

watcher.on('event', (event) => {
if (event.code === 'BUNDLE_START') {
config.logger.info(chalk.cyanBright(`\nbuild started...`))

// clean previous files
if (options.write) {
emptyDir(outDir)
if (fs.existsSync(config.publicDir)) {
copyDir(config.publicDir, outDir)
}
}
} 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 watcher
}

// write or generate files with rollup
const bundle = await rollup.rollup(rollupOptions)
parallelBuilds.push(bundle)

const generate = (output: OutputOptions = {}) => {
return bundle[options.write ? 'write' : 'generate'](
buildOuputOptions(output)
)
}

if (options.write) {
Expand Down Expand Up @@ -434,12 +527,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) {
Expand All @@ -450,16 +537,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
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/vite/src/node/cli.ts
Expand Up @@ -130,6 +130,7 @@ cli
`[boolean] force empty outDir when it's outside of root`
)
.option('-m, --mode <mode>', `[string] set env mode`)
.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
Expand Down

0 comments on commit 0dc6e37

Please sign in to comment.