Repository: nuxt/nuxt.js
Pull request #6257 (2019-08-20 17:06:58)

fix: improve watching experience for generated files
<!--- Provide a general summary of your changes in the title above -->

## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (a non-breaking change which fixes an issue)
- [ ] New feature (a non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)


## Description
Nuxt has a frustrating DX issue when a page file is deleted or renamed. Webpack starts to rebuild as soon as the file is changed while still generated files (like `.nuxt/router.js`) are referring to the old file. This is happening because we debounce `generateRoutesAndFiles` function (also there is a little generation/fs process time) but webpack rebuilds as soon as possible. Causing a failing intermediate build like this:

![image](https://user-images.githubusercontent.com/5158436/63367823-ec153d80-c391-11e9-9640-c874e52538c7.png)

This PR set a longer default for [aggregateTimeout](https://webpack.js.org/configuration/watch/#watchoptionsaggregatetimeout) (200ms + ~800ms of generating process). That fixes the problem in normal cases when generation takes less than 800ms: (previously deadline was ~100ms)

![image](https://user-images.githubusercontent.com/5158436/63368260-cccae000-c392-11e9-9c42-707529d763f1.png)


Webpack watch will be also suspended during generate files and resumed/invalidated thanks to pausing/resume introduced webpack/webpack#9214 (@jkzing :heart:)

## Checklist:
<!--- Put an `x` in all the boxes that apply. -->
<!--- If your change requires a documentation PR, please link it appropriately -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly. (PR: #)
- [ ] I have added tests to cover my changes (if not applicable, please state why)
- [ ] All new and existing tests are passing.



codecov-io: # [Codecov](https://codecov.io/gh/nuxt/nuxt.js/pull/6257?src=pr&el=h1) Report
> Merging [#6257](https://codecov.io/gh/nuxt/nuxt.js/pull/6257?src=pr&el=desc) into [dev](https://codecov.io/gh/nuxt/nuxt.js/commit/fda1b1b54b248d5b06a181f16287a70f30f75673?src=pr&el=desc) will **decrease** coverage by `0.07%`.
> The diff coverage is `0%`.

[![Impacted file tree graph](https://codecov.io/gh/nuxt/nuxt.js/pull/6257/graphs/tree.svg?width=650&token=nGD1PtMB3M&height=150&src=pr)](https://codecov.io/gh/nuxt/nuxt.js/pull/6257?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##              dev    #6257      +/-   ##
==========================================
- Coverage   95.72%   95.65%   -0.08%     
==========================================
  Files          80       80              
  Lines        2666     2668       +2     
  Branches      687      687              
==========================================
  Hits         2552     2552              
- Misses         98      100       +2     
  Partials       16       16
```

| Flag | Coverage Δ | |
|---|---|---|
| #e2e | `100% <ø> (ø)` | :arrow_up: |
| #fixtures | `50.59% <0%> (-0.04%)` | :arrow_down: |
| #unit | `92.35% <0%> (-0.07%)` | :arrow_down: |

| [Impacted Files](https://codecov.io/gh/nuxt/nuxt.js/pull/6257?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [packages/config/src/config/\_common.js](https://codecov.io/gh/nuxt/nuxt.js/pull/6257/diff?src=pr&el=tree#diff-cGFja2FnZXMvY29uZmlnL3NyYy9jb25maWcvX2NvbW1vbi5qcw==) | `100% <ø> (ø)` | :arrow_up: |
| [packages/webpack/src/builder.js](https://codecov.io/gh/nuxt/nuxt.js/pull/6257/diff?src=pr&el=tree#diff-cGFja2FnZXMvd2VicGFjay9zcmMvYnVpbGRlci5qcw==) | `90.62% <0%> (-1.93%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/nuxt/nuxt.js/pull/6257?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/nuxt/nuxt.js/pull/6257?src=pr&el=footer). Last update [fda1b1b...61baa98](https://codecov.io/gh/nuxt/nuxt.js/pull/6257?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

Atinux: Expecting the strange failing test 🤔 
Awesome PR :)

Patch:
diff --git a/packages/builder/src/builder.js b/packages/builder/src/builder.js
index 734231b5d..e15f17f5e 100644
--- a/packages/builder/src/builder.js
+++ b/packages/builder/src/builder.js
@@ -216,6 +216,10 @@ export default class Builder {
   async generateRoutesAndFiles () {
     consola.debug('Generating nuxt files')
 
+    if (this.bundleBuilder) {
+      this.bundleBuilder.pauseWatch()
+    }
+
     // Plugins
     this.plugins = Array.from(this.normalizePlugins())
 
@@ -237,6 +241,10 @@ export default class Builder {
 
     await this.compileTemplates(templateContext)
 
+    if (this.bundleBuilder) {
+      this.bundleBuilder.resumeWatch()
+    }
+
     consola.success('Nuxt files generated')
   }
 
diff --git a/packages/config/src/config/_common.js b/packages/config/src/config/_common.js
index 5dbf4ff72..4353254e8 100644
--- a/packages/config/src/config/_common.js
+++ b/packages/config/src/config/_common.js
@@ -68,7 +68,9 @@ export default () => ({
   watch: [],
   watchers: {
     rewatchOnRawEvents: undefined,
-    webpack: {},
+    webpack: {
+      aggregateTimeout: 1000
+    },
     chokidar: {
       ignoreInitial: true
     }
diff --git a/packages/webpack/src/builder.js b/packages/webpack/src/builder.js
index 4ade5db78..a8b81d2e4 100644
--- a/packages/webpack/src/builder.js
+++ b/packages/webpack/src/builder.js
@@ -168,35 +168,27 @@ export class WebpackBundler {
     // Create webpack dev middleware
     this.devMiddleware[name] = pify(
       webpackDevMiddleware(
-        compiler,
-        Object.assign(
-          {
-            publicPath: buildOptions.publicPath,
-            stats: false,
-            logLevel: 'silent',
-            watchOptions: this.buildContext.options.watchers.webpack
-          },
-          buildOptions.devMiddleware
-        )
-      )
+        compiler, {
+          publicPath: buildOptions.publicPath,
+          stats: false,
+          logLevel: 'silent',
+          watchOptions: this.buildContext.options.watchers.webpack,
+          ...buildOptions.devMiddleware
+        })
     )
 
     this.devMiddleware[name].close = pify(this.devMiddleware[name].close)
 
+    this.compilersWatching.push(this.devMiddleware[name].context.watching)
+
     this.hotMiddleware[name] = pify(
       webpackHotMiddleware(
-        compiler,
-        Object.assign(
-          {
-            log: false,
-            heartbeat: 10000
-          },
-          hotMiddlewareOptions,
-          {
-            path: `/__webpack_hmr/${name}`
-          }
-        )
-      )
+        compiler, {
+          log: false,
+          heartbeat: 10000,
+          path: `/__webpack_hmr/${name}`,
+          ...hotMiddlewareOptions
+        })
     )
 
     // Register devMiddleware on server
@@ -221,6 +213,14 @@ export class WebpackBundler {
     await Promise.all(this.compilersWatching.map(watching => watching.close()))
   }
 
+  pauseWatch () {
+    this.compilersWatching.forEach(watching => watching.suspend())
+  }
+
+  resumeWatch () {
+    this.compilersWatching.forEach(watching => watching.resume())
+  }
+
   async close () {
     if (this.__closed) {
       return


Test patch:
diff --git a/packages/builder/test/builder.build.test.js b/packages/builder/test/builder.build.test.js
index 56279d71f..f2a6b7fb1 100644
--- a/packages/builder/test/builder.build.test.js
+++ b/packages/builder/test/builder.build.test.js
@@ -3,6 +3,7 @@ import consola from 'consola'
 import fsExtra from 'fs-extra'
 import semver from 'semver'
 import { r, waitFor } from '@nuxt/utils'
+import { BundleBuilder } from '@nuxt/webpack'
 
 import Builder from '../src/builder'
 import { createNuxt } from './__utils__'
@@ -12,6 +13,7 @@ jest.mock('semver')
 jest.mock('hash-sum', () => src => `hash(${src})`)
 jest.mock('@nuxt/utils')
 jest.mock('../src/ignore')
+jest.mock('@nuxt/webpack')
 
 describe('builder: builder build', () => {
   beforeAll(() => {
@@ -77,7 +79,7 @@ describe('builder: builder build', () => {
   test('should prevent duplicate build in dev mode', async () => {
     const nuxt = createNuxt()
     nuxt.options.dev = true
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder._buildStatus = 3
 
     waitFor.mockImplementationOnce(() => {
@@ -96,7 +98,7 @@ describe('builder: builder build', () => {
   test('should wait 1000ms and retry if building is in progress', async () => {
     const nuxt = createNuxt()
     nuxt.options.dev = true
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder._buildStatus = 2
 
     const buildReturn = await builder.build()
@@ -134,7 +136,7 @@ describe('builder: builder build', () => {
 
   test('should throw error when validateTemplate failed', async () => {
     const nuxt = createNuxt()
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.validatePages = jest.fn()
     builder.validateTemplate = jest.fn(() => {
       throw new Error('validate failed')
@@ -154,7 +156,7 @@ describe('builder: builder build', () => {
     const nuxt = createNuxt()
     nuxt.options.srcDir = '/var/nuxt/src'
     nuxt.options.dir = { pages: '/var/nuxt/src/pages' }
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     fsExtra.exists.mockReturnValue(false)
 
     await builder.validatePages()
@@ -175,7 +177,7 @@ describe('builder: builder build', () => {
     const nuxt = createNuxt()
     nuxt.options.srcDir = '/var/nuxt/src'
     nuxt.options.dir = { pages: '/var/nuxt/src/pages' }
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     fsExtra.exists
       .mockReturnValueOnce(false)
       .mockReturnValueOnce(true)
@@ -197,7 +199,7 @@ describe('builder: builder build', () => {
   test('should pass validation if createRoutes is function', async () => {
     const nuxt = createNuxt()
     nuxt.options.build.createRoutes = jest.fn()
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
 
     await builder.validatePages()
 
@@ -209,7 +211,7 @@ describe('builder: builder build', () => {
     const nuxt = createNuxt()
     nuxt.options.srcDir = '/var/nuxt/src'
     nuxt.options.dir = { pages: '/var/nuxt/src/pages' }
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     fsExtra.exists.mockReturnValueOnce(true)
 
     await builder.validatePages()
@@ -230,7 +232,7 @@ describe('builder: builder build', () => {
         nuxt: 'edge'
       }
     }
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     semver.satisfies
       .mockReturnValueOnce(true)
       .mockReturnValueOnce(true)
@@ -256,7 +258,7 @@ describe('builder: builder build', () => {
         nuxt: 'edge'
       }
     }
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     semver.satisfies
       .mockReturnValueOnce(false)
     nuxt.resolver.requireModule
diff --git a/packages/builder/test/builder.generate.test.js b/packages/builder/test/builder.generate.test.js
index 8c1b78cbd..5d5061f4a 100644
--- a/packages/builder/test/builder.generate.test.js
+++ b/packages/builder/test/builder.generate.test.js
@@ -4,6 +4,7 @@ import fs from 'fs-extra'
 import consola from 'consola'
 import template from 'lodash/template'
 import { r, createRoutes, stripWhitespace } from '@nuxt/utils'
+import { BundleBuilder } from '@nuxt/webpack'
 import Builder from '../src/builder'
 import TemplateContext from '../src/context/template'
 import { createNuxt } from './__utils__'
@@ -17,6 +18,7 @@ jest.mock('../src/context/template', () => jest.fn())
 jest.mock('../src/ignore', () => function () {
   this.filter = jest.fn(files => files)
 })
+jest.mock('@nuxt/webpack')
 
 describe('builder: builder generate', () => {
   beforeAll(() => {
@@ -45,7 +47,7 @@ describe('builder: builder generate', () => {
       },
       watch: []
     }
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.normalizePlugins = jest.fn(() => [{ name: 'test_plugin', src: '/var/somesrc' }])
     builder.resolveLayouts = jest.fn(() => 'resolveLayouts')
     builder.resolveRoutes = jest.fn(() => 'resolveRoutes')
@@ -88,7 +90,7 @@ describe('builder: builder generate', () => {
     const nuxt = createNuxt()
     nuxt.options.srcDir = '/var/nuxt/src'
     nuxt.options.ignore = '/var/nuxt/ignore'
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     Glob.mockReturnValue('matched files')
 
     const files = await builder.resolveFiles('/var/nuxt/dir')
@@ -105,7 +107,7 @@ describe('builder: builder generate', () => {
 
   test('should resolve relative files', async () => {
     const nuxt = createNuxt()
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.resolveFiles = jest.fn(dir => [ `${dir}/foo.vue`, `${dir}/bar.vue`, `${dir}/baz.vue` ])
 
     const files = await builder.resolveRelative('/var/nuxt/dir')
@@ -125,7 +127,7 @@ describe('builder: builder generate', () => {
     nuxt.options.dir = {
       store: '/var/nuxt/src/store'
     }
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.resolveRelative = jest.fn(dir => [
       { src: `${dir}/index.js` },
       { src: `${dir}/bar.js` },
@@ -155,7 +157,7 @@ describe('builder: builder generate', () => {
     nuxt.options.dir = {
       store: '/var/nuxt/src/store'
     }
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
 
     const templateVars = {}
     const templateFiles = []
@@ -171,7 +173,7 @@ describe('builder: builder generate', () => {
     nuxt.options.dir = {
       middleware: '/var/nuxt/src/middleware'
     }
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.resolveRelative = jest.fn(dir => [
       { src: `${dir}/midd.js` }
     ])
@@ -193,7 +195,7 @@ describe('builder: builder generate', () => {
         { src: '/var/nuxt/templates/baz.js', dst: 'baz.js' }
       ]
     }
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     fs.exists.mockReturnValueOnce(true)
 
     const templateContext = {
@@ -226,7 +228,7 @@ describe('builder: builder generate', () => {
     nuxt.options.build = {
       template: { dir: '/var/nuxt/templates' }
     }
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     fs.exists.mockReturnValueOnce(true)
 
     const templateFiles = []
@@ -252,7 +254,7 @@ describe('builder: builder generate', () => {
     nuxt.options.build = {
       template: { dir: '/var/nuxt/templates' }
     }
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     fs.exists
       .mockReturnValueOnce(false)
       .mockReturnValueOnce(true)
@@ -281,7 +283,7 @@ describe('builder: builder generate', () => {
     nuxt.options.build = {
       template: { dir: '/var/nuxt/templates' }
     }
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     fs.exists
       .mockReturnValueOnce(false)
       .mockReturnValueOnce(false)
@@ -304,7 +306,7 @@ describe('builder: builder generate', () => {
     nuxt.options.loadingIndicator = {
       name: false
     }
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
 
     await builder.resolveLoadingIndicator({ templateFiles: [] })
 
@@ -315,7 +317,7 @@ describe('builder: builder generate', () => {
     const nuxt = createNuxt()
     nuxt.options.build.watch = []
     nuxt.options.buildDir = '/var/nuxt/build'
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.relativeToBuild = jest.fn()
     const templateFn = jest.fn(() => 'compiled content')
     template.mockImplementation(() => templateFn)
@@ -385,7 +387,7 @@ describe('builder: builder generate', () => {
 
   test('should throw error if compile failed', async () => {
     const nuxt = createNuxt()
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.relativeToBuild = jest.fn()
     template.mockImplementation(() => {
       throw new Error('compile failed')
@@ -412,7 +414,7 @@ describe('builder: builder generate', () => {
       nuxt.options.layouts = {
         foo: '/var/nuxt/layouts/foo/index.vue'
       }
-      const builder = new Builder(nuxt, {})
+      const builder = new Builder(nuxt, BundleBuilder)
       builder.resolveFiles = jest.fn(layouts => [
         `${layouts}/foo.vue`,
         `${layouts}/bar.js`,
@@ -460,7 +462,7 @@ describe('builder: builder generate', () => {
       nuxt.options.dir = {
         layouts: '/var/nuxt/src/layouts'
       }
-      const builder = new Builder(nuxt, {})
+      const builder = new Builder(nuxt, BundleBuilder)
       builder.resolveFiles = jest.fn(layouts => [
         `${layouts}/error.vue`
       ])
@@ -487,7 +489,7 @@ describe('builder: builder generate', () => {
       nuxt.options.dir = {
         layouts: '/var/nuxt/src/layouts'
       }
-      const builder = new Builder(nuxt, {})
+      const builder = new Builder(nuxt, BundleBuilder)
       builder.resolveFiles = jest.fn()
       fs.exists.mockReturnValueOnce(false)
 
@@ -513,7 +515,7 @@ describe('builder: builder generate', () => {
       nuxt.options.srcDir = '/var/nuxt/src'
       nuxt.options.build.createRoutes = jest.fn(() => [ { name: 'default_route' } ])
       nuxt.options.router.extendRoutes = jest.fn(routes => [ ...routes, { name: 'extend_route' } ])
-      const builder = new Builder(nuxt, {})
+      const builder = new Builder(nuxt, BundleBuilder)
 
       const templateVars = {
         router: {
@@ -550,7 +552,7 @@ describe('builder: builder generate', () => {
       }
       nuxt.options.router.routeNameSplitter = '[splitter]'
       createRoutes.mockReturnValueOnce([ { name: 'default_route' } ])
-      const builder = new Builder(nuxt, {})
+      const builder = new Builder(nuxt, BundleBuilder)
       builder._defaultPage = true
 
       const templateVars = {
@@ -595,7 +597,7 @@ describe('builder: builder generate', () => {
         extendRoutes: jest.fn()
       }
       createRoutes.mockImplementationOnce(({ files }) => files.map(file => ({ path: file })))
-      const builder = new Builder(nuxt, {})
+      const builder = new Builder(nuxt, BundleBuilder)
       builder._nuxtPages = true
       builder.resolveFiles = jest.fn(dir => [
         `${dir}/foo.js`,
diff --git a/packages/builder/test/builder.plugin.test.js b/packages/builder/test/builder.plugin.test.js
index f398dbdd4..0b5ba6f4b 100644
--- a/packages/builder/test/builder.plugin.test.js
+++ b/packages/builder/test/builder.plugin.test.js
@@ -1,6 +1,7 @@
 import Glob from 'glob'
 import consola from 'consola'
 import { isIndexFileAndFolder } from '@nuxt/utils'
+import { BundleBuilder } from '@nuxt/webpack'
 
 import Builder from '../src/builder'
 import { createNuxt } from './__utils__'
@@ -10,6 +11,7 @@ jest.mock('pify', () => fn => fn)
 jest.mock('hash-sum', () => src => `hash(${src})`)
 jest.mock('@nuxt/utils')
 jest.mock('../src/ignore')
+jest.mock('@nuxt/webpack')
 
 describe('builder: builder plugins', () => {
   beforeEach(() => {
@@ -24,7 +26,7 @@ describe('builder: builder plugins', () => {
       { src: '/var/nuxt/plugins/test.server', mode: 'server' },
       { src: '/var/nuxt/plugins/test.client', ssr: false }
     ]
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
 
     const plugins = builder.normalizePlugins()
 
@@ -57,7 +59,7 @@ describe('builder: builder plugins', () => {
     nuxt.options.plugins = [
       { src: '/var/nuxt/plugins/test', mode: 'abc' }
     ]
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
 
     const plugins = builder.normalizePlugins()
 
@@ -74,7 +76,7 @@ describe('builder: builder plugins', () => {
 
   test('should resolve plugins', async () => {
     const nuxt = createNuxt()
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.plugins = [
       { src: '/var/nuxt/plugins/test.js', mode: 'all' },
       { src: '/var/nuxt/plugins/test.client', mode: 'client' },
@@ -100,7 +102,7 @@ describe('builder: builder plugins', () => {
 
   test('should throw error if plugin no existed', async () => {
     const nuxt = createNuxt()
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.plugins = [
       { src: '/var/nuxt/plugins/test.js', mode: 'all' }
     ]
@@ -111,7 +113,7 @@ describe('builder: builder plugins', () => {
 
   test('should warn if there are multiple files and not index', async () => {
     const nuxt = createNuxt()
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.plugins = [
       { src: '/var/nuxt/plugins/test', mode: 'all' }
     ]
@@ -129,7 +131,7 @@ describe('builder: builder plugins', () => {
 
   test('should detect plugin mode for client/server plugins', () => {
     const nuxt = createNuxt()
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.options.plugins = [
       { src: '/var/nuxt/plugins/test.js', mode: 'all' },
       { src: '/var/nuxt/plugins/test.client' },
diff --git a/packages/builder/test/builder.watch.test.js b/packages/builder/test/builder.watch.test.js
index 8482792b5..bbe5ce3cb 100644
--- a/packages/builder/test/builder.watch.test.js
+++ b/packages/builder/test/builder.watch.test.js
@@ -4,8 +4,10 @@ import upath from 'upath'
 import debounce from 'lodash/debounce'
 import { r, isString, isPureObject } from '@nuxt/utils'
 
+import { BundleBuilder } from '@nuxt/webpack'
 import Builder from '../src/builder'
 import { createNuxt } from './__utils__'
+jest.mock('@nuxt/webpack')
 
 jest.mock('chokidar', () => ({
   watch: jest.fn().mockReturnThis(),
@@ -16,6 +18,7 @@ jest.mock('upath', () => ({ normalizeSafe: jest.fn(src => src) }))
 jest.mock('lodash/debounce', () => jest.fn(fn => fn))
 jest.mock('@nuxt/utils')
 jest.mock('../src/ignore')
+jest.mock('@nuxt/webpack')
 
 describe('builder: builder watch', () => {
   beforeEach(() => {
@@ -33,7 +36,7 @@ describe('builder: builder watch', () => {
     }
     nuxt.options.build.watch = []
 
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.createFileWatcher = jest.fn()
     builder.assignWatcher = jest.fn(() => () => {})
     r.mockImplementation((dir, src) => src)
@@ -75,7 +78,7 @@ describe('builder: builder watch', () => {
     }
     nuxt.options.build.watch = []
 
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.createFileWatcher = jest.fn()
     builder.assignWatcher = jest.fn(() => () => {})
     r.mockImplementation((dir, src) => src)
@@ -100,7 +103,7 @@ describe('builder: builder watch', () => {
       chokidar: { test: true }
     }
 
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder._nuxtPages = true
     builder._defaultPage = true
     r.mockImplementation((dir, src) => src)
@@ -123,7 +126,7 @@ describe('builder: builder watch', () => {
       chokidar: { test: true }
     }
 
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder._nuxtPages = true
     r.mockImplementation((dir, src) => src)
 
@@ -149,7 +152,7 @@ describe('builder: builder watch', () => {
     nuxt.options.watchers = {
       chokidar: { test: true }
     }
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.watchCustom = jest.fn()
     r.mockImplementation((dir, src) => src)
 
@@ -179,7 +182,7 @@ describe('builder: builder watch', () => {
     nuxt.options.build.styleResources = [
       '/var/nuxt/src/style'
     ]
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.createFileWatcher = jest.fn()
     builder.assignWatcher = jest.fn(() => () => {})
     builder.watchClient()
@@ -212,7 +215,7 @@ describe('builder: builder watch', () => {
     const listener = jest.fn()
     const watcherCreatedCallback = jest.fn()
 
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.createFileWatcher(patterns, events, listener, watcherCreatedCallback)
 
     expect(chokidar.watch).toBeCalledTimes(1)
@@ -242,7 +245,7 @@ describe('builder: builder watch', () => {
     const listener = jest.fn()
     const watcherCreatedCallback = jest.fn()
 
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.createFileWatcher(patterns, events, listener, watcherCreatedCallback)
 
     expect(chokidar.on).toBeCalledTimes(2)
@@ -277,7 +280,7 @@ describe('builder: builder watch', () => {
       { path: '/test', handler: '/var/nuxt/src/serverMiddleware/test-handler' },
       { obj: 'test' }
     ]
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.ignore.ignoreFile = '/var/nuxt/src/.nuxtignore'
     isString.mockImplementation(src => typeof src === 'string')
     isPureObject.mockImplementation(obj => typeof obj === 'object')
@@ -315,7 +318,7 @@ describe('builder: builder watch', () => {
       '/var/nuxt/src/watch/test'
     ]
     nuxt.options.serverMiddleware = []
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
 
     builder.watchRestart()
 
@@ -350,7 +353,7 @@ describe('builder: builder watch', () => {
       '/var/nuxt/src/watch/test'
     ]
     nuxt.options.serverMiddleware = []
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
 
     builder.watchRestart()
 
@@ -363,7 +366,7 @@ describe('builder: builder watch', () => {
 
   test('should unwatch every watcher', () => {
     const nuxt = createNuxt()
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.watchers = {
       files: { close: jest.fn() },
       custom: { close: jest.fn() },
@@ -379,8 +382,7 @@ describe('builder: builder watch', () => {
 
   test('should close watch and bundle builder', async () => {
     const nuxt = createNuxt()
-    const bundleBuilderClose = jest.fn()
-    const builder = new Builder(nuxt, { close: bundleBuilderClose })
+    const builder = new Builder(nuxt, BundleBuilder)
     builder.unwatch = jest.fn()
 
     expect(builder.__closed).toBeUndefined()
@@ -389,7 +391,7 @@ describe('builder: builder watch', () => {
 
     expect(builder.__closed).toEqual(true)
     expect(builder.unwatch).toBeCalledTimes(1)
-    expect(bundleBuilderClose).toBeCalledTimes(1)
+    expect(builder.bundleBuilder.close).toBeCalledTimes(1)
   })
 
   test('should close bundleBuilder only if close api exists', async () => {
@@ -420,7 +422,7 @@ describe('builder: builder watch', () => {
 
   test('should assign watcher with key', () => {
     const nuxt = createNuxt()
-    const builder = new Builder(nuxt, {})
+    const builder = new Builder(nuxt, BundleBuilder)
 
     const key = 'key'
     const watcher = 'watcher'
diff --git a/packages/config/test/__snapshots__/options.test.js.snap b/packages/config/test/__snapshots__/options.test.js.snap
index c2c6b112f..e86ab8530 100644
--- a/packages/config/test/__snapshots__/options.test.js.snap
+++ b/packages/config/test/__snapshots__/options.test.js.snap
@@ -357,7 +357,9 @@ Object {
       "ignoreInitial": true,
     },
     "rewatchOnRawEvents": undefined,
-    "webpack": Object {},
+    "webpack": Object {
+      "aggregateTimeout": 1000,
+    },
   },
 }
 `;
diff --git a/packages/config/test/config/__snapshots__/index.test.js.snap b/packages/config/test/config/__snapshots__/index.test.js.snap
index ba98fa7a7..f6870e019 100644
--- a/packages/config/test/config/__snapshots__/index.test.js.snap
+++ b/packages/config/test/config/__snapshots__/index.test.js.snap
@@ -322,7 +322,9 @@ Object {
       "ignoreInitial": true,
     },
     "rewatchOnRawEvents": undefined,
-    "webpack": Object {},
+    "webpack": Object {
+      "aggregateTimeout": 1000,
+    },
   },
 }
 `;
@@ -649,7 +651,9 @@ Object {
       "ignoreInitial": true,
     },
     "rewatchOnRawEvents": undefined,
-    "webpack": Object {},
+    "webpack": Object {
+      "aggregateTimeout": 1000,
+    },
   },
 }
 `;