fix: improve watching experience for generated files (#6257)

This commit is contained in:
Pooya Parsa 2019-08-21 23:34:04 +04:30 committed by GitHub
parent 6ac5544428
commit 81b92b6395
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 101 additions and 77 deletions

View File

@ -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')
}

View File

@ -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

View File

@ -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`,

View File

@ -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' },

View File

@ -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'

View File

@ -68,7 +68,9 @@ export default () => ({
watch: [],
watchers: {
rewatchOnRawEvents: undefined,
webpack: {},
webpack: {
aggregateTimeout: 1000
},
chokidar: {
ignoreInitial: true
}

View File

@ -357,7 +357,9 @@ Object {
"ignoreInitial": true,
},
"rewatchOnRawEvents": undefined,
"webpack": Object {},
"webpack": Object {
"aggregateTimeout": 1000,
},
},
}
`;

View File

@ -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,
},
},
}
`;

View File

@ -168,35 +168,27 @@ export class WebpackBundler {
// Create webpack dev middleware
this.devMiddleware[name] = pify(
webpackDevMiddleware(
compiler,
Object.assign(
{
compiler, {
publicPath: buildOptions.publicPath,
stats: false,
logLevel: 'silent',
watchOptions: this.buildContext.options.watchers.webpack
},
buildOptions.devMiddleware
)
)
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(
{
compiler, {
log: false,
heartbeat: 10000
},
hotMiddlewareOptions,
{
path: `/__webpack_hmr/${name}`
}
)
)
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