mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +00:00
fix: refactor file watchers (chokidar/linux workaround) (#4950)
This commit is contained in:
parent
68f6880f54
commit
5ec5932bad
@ -580,6 +580,37 @@ export default class Builder {
|
||||
// )
|
||||
// }
|
||||
|
||||
createFileWatcher(patterns, events, listener, watcherCreatedCallback) {
|
||||
const options = this.options.watchers.chokidar
|
||||
const watcher = chokidar.watch(patterns, options)
|
||||
|
||||
for (const event of events) {
|
||||
watcher.on(event, listener)
|
||||
}
|
||||
|
||||
const { rewatchOnRawEvents } = this.options.watchers
|
||||
if (rewatchOnRawEvents && Array.isArray(rewatchOnRawEvents)) {
|
||||
watcher.on('raw', (_event) => {
|
||||
if (rewatchOnRawEvents.includes(_event)) {
|
||||
watcher.close()
|
||||
|
||||
listener()
|
||||
this.createFileWatcher(patterns, events, listener, watcherCreatedCallback)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof watcherCreatedCallback === 'function') {
|
||||
watcherCreatedCallback(watcher)
|
||||
}
|
||||
}
|
||||
|
||||
assignWatcher(key) {
|
||||
return (watcher) => {
|
||||
this.watchers[key] = watcher
|
||||
}
|
||||
}
|
||||
|
||||
watchClient() {
|
||||
const src = this.options.srcDir
|
||||
const rGlob = dir => ['*', '**/*'].map(glob => r(src, `${dir}/${glob}.{${this.supportedExtensions.join(',')}}`))
|
||||
@ -600,20 +631,11 @@ export default class Builder {
|
||||
|
||||
patterns = patterns.map(upath.normalizeSafe)
|
||||
|
||||
const options = this.options.watchers.chokidar
|
||||
const refreshFiles = debounce(() => this.generateRoutesAndFiles(), 200)
|
||||
|
||||
// Watch for src Files
|
||||
this.watchers.files = chokidar
|
||||
.watch(patterns, options)
|
||||
.on('add', refreshFiles)
|
||||
.on('unlink', refreshFiles)
|
||||
this.createFileWatcher(patterns, ['add', 'unlink'], refreshFiles, this.assignWatcher('files'))
|
||||
|
||||
this.watchCustom(refreshFiles)
|
||||
}
|
||||
|
||||
watchCustom(refreshFiles, refresh) {
|
||||
const options = this.options.watchers.chokidar
|
||||
// Watch for custom provided files
|
||||
const customPatterns = uniq([
|
||||
...this.options.build.watch,
|
||||
@ -624,25 +646,7 @@ export default class Builder {
|
||||
return
|
||||
}
|
||||
|
||||
if (refresh) {
|
||||
refreshFiles()
|
||||
}
|
||||
|
||||
this.watchers.custom = chokidar
|
||||
.watch(customPatterns, options)
|
||||
.on('change', refreshFiles)
|
||||
|
||||
const { rewatchOnRawEvents } = this.options.watchers
|
||||
if (rewatchOnRawEvents && Array.isArray(rewatchOnRawEvents)) {
|
||||
this.watchers.custom.on('raw', (_event, _path, opts) => {
|
||||
if (rewatchOnRawEvents.includes(_event)) {
|
||||
this.watchers.custom.close()
|
||||
this.watchers.custom = null
|
||||
|
||||
this.watchCustom(refreshFiles, true)
|
||||
}
|
||||
})
|
||||
}
|
||||
this.createFileWatcher(customPatterns, ['change'], refreshFiles, this.assignWatcher('custom'))
|
||||
}
|
||||
|
||||
watchRestart() {
|
||||
@ -657,15 +661,18 @@ export default class Builder {
|
||||
nuxtRestartWatch.push(this.ignore.ignoreFile)
|
||||
}
|
||||
|
||||
this.watchers.restart = chokidar
|
||||
.watch(nuxtRestartWatch, this.options.watchers.chokidar)
|
||||
.on('all', (event, _path) => {
|
||||
this.createFileWatcher(
|
||||
nuxtRestartWatch,
|
||||
['all'],
|
||||
(event, _path) => {
|
||||
if (['add', 'change', 'unlink'].includes(event) === false) {
|
||||
return
|
||||
}
|
||||
this.nuxt.callHook('watch:fileChanged', this, _path) // Legacy
|
||||
this.nuxt.callHook('watch:restart', { event, path: _path })
|
||||
})
|
||||
},
|
||||
this.assignWatcher('restart')
|
||||
)
|
||||
}
|
||||
|
||||
unwatch() {
|
||||
|
@ -31,10 +31,10 @@ describe('builder: builder watch', () => {
|
||||
middleware: '/var/nuxt/src/middleware'
|
||||
}
|
||||
nuxt.options.build.watch = []
|
||||
nuxt.options.watchers = {
|
||||
chokidar: { test: true }
|
||||
}
|
||||
|
||||
const builder = new Builder(nuxt, {})
|
||||
builder.createFileWatcher = jest.fn()
|
||||
builder.assignWatcher = jest.fn(() => () => {})
|
||||
r.mockImplementation((dir, src) => src)
|
||||
|
||||
builder.watchClient()
|
||||
@ -61,11 +61,9 @@ describe('builder: builder watch', () => {
|
||||
expect(upath.normalizeSafe).nthCalledWith(4, '/var/nuxt/src/layouts/*.{vue,js,ts,tsx}', 3, patterns)
|
||||
expect(upath.normalizeSafe).nthCalledWith(5, '/var/nuxt/src/layouts/**/*.{vue,js,ts,tsx}', 4, patterns)
|
||||
|
||||
expect(chokidar.watch).toBeCalledTimes(1)
|
||||
expect(chokidar.watch).toBeCalledWith(patterns, { test: true })
|
||||
expect(chokidar.on).toBeCalledTimes(2)
|
||||
expect(chokidar.on).nthCalledWith(1, 'add', expect.any(Function))
|
||||
expect(chokidar.on).nthCalledWith(2, 'unlink', expect.any(Function))
|
||||
expect(builder.createFileWatcher).toBeCalledTimes(1)
|
||||
expect(builder.createFileWatcher).toBeCalledWith(patterns, ['add', 'unlink'], expect.any(Function), expect.any(Function))
|
||||
expect(builder.assignWatcher).toBeCalledTimes(1)
|
||||
})
|
||||
|
||||
test('should watch pages files', () => {
|
||||
@ -81,6 +79,7 @@ describe('builder: builder watch', () => {
|
||||
nuxt.options.watchers = {
|
||||
chokidar: { test: true }
|
||||
}
|
||||
|
||||
const builder = new Builder(nuxt, {})
|
||||
builder._nuxtPages = true
|
||||
r.mockImplementation((dir, src) => src)
|
||||
@ -93,7 +92,7 @@ describe('builder: builder watch', () => {
|
||||
expect(r).nthCalledWith(8, '/var/nuxt/src', '/var/nuxt/src/pages/**/*.{vue,js,ts,tsx}')
|
||||
})
|
||||
|
||||
test('should watch custom in watchClient', () => {
|
||||
test('should invoke generateRoutesAndFiles on file refresh', () => {
|
||||
const nuxt = createNuxt()
|
||||
nuxt.options.srcDir = '/var/nuxt/src'
|
||||
nuxt.options.dir = {
|
||||
@ -119,14 +118,16 @@ describe('builder: builder watch', () => {
|
||||
builder.generateRoutesAndFiles = jest.fn()
|
||||
refreshFiles()
|
||||
expect(builder.generateRoutesAndFiles).toBeCalled()
|
||||
expect(builder.watchCustom).toBeCalledTimes(1)
|
||||
expect(builder.watchCustom).toBeCalledWith(refreshFiles)
|
||||
})
|
||||
|
||||
test('should watch custom patterns', () => {
|
||||
const nuxt = createNuxt()
|
||||
nuxt.options.watchers = {
|
||||
chokidar: { test: true }
|
||||
nuxt.options.srcDir = '/var/nuxt/src'
|
||||
nuxt.options.dir = {
|
||||
layouts: '/var/nuxt/src/layouts',
|
||||
pages: '/var/nuxt/src/pages',
|
||||
store: '/var/nuxt/src/store',
|
||||
middleware: '/var/nuxt/src/middleware'
|
||||
}
|
||||
nuxt.options.build.watch = [
|
||||
'/var/nuxt/src/custom'
|
||||
@ -135,61 +136,81 @@ describe('builder: builder watch', () => {
|
||||
'/var/nuxt/src/style'
|
||||
]
|
||||
const builder = new Builder(nuxt, {})
|
||||
const refreshFiles = jest.fn()
|
||||
builder.createFileWatcher = jest.fn()
|
||||
builder.assignWatcher = jest.fn(() => () => {})
|
||||
builder.watchClient()
|
||||
|
||||
builder.watchCustom(refreshFiles)
|
||||
const patterns = [
|
||||
'/var/nuxt/src/custom',
|
||||
'/var/nuxt/src/style'
|
||||
]
|
||||
|
||||
expect(chokidar.watch).toBeCalledTimes(1)
|
||||
expect(chokidar.watch).toBeCalledWith(
|
||||
['/var/nuxt/src/custom', '/var/nuxt/src/style'],
|
||||
{ test: true }
|
||||
)
|
||||
expect(chokidar.on).toBeCalledTimes(1)
|
||||
expect(chokidar.on).toBeCalledWith('change', refreshFiles)
|
||||
expect(builder.createFileWatcher).toBeCalledTimes(2)
|
||||
expect(builder.createFileWatcher).toBeCalledWith(patterns, ['change'], expect.any(Function), expect.any(Function))
|
||||
expect(builder.assignWatcher).toBeCalledTimes(2)
|
||||
})
|
||||
|
||||
test('should call refreshFiles before watching custom patterns', () => {
|
||||
test('should invoke chokidar to create watcher', () => {
|
||||
const nuxt = createNuxt()
|
||||
nuxt.options.srcDir = '/var/nuxt/src'
|
||||
nuxt.options.dir = {
|
||||
layouts: '/var/nuxt/src/layouts',
|
||||
pages: '/var/nuxt/src/pages',
|
||||
store: '/var/nuxt/src/store',
|
||||
middleware: '/var/nuxt/src/middleware'
|
||||
}
|
||||
nuxt.options.watchers = {
|
||||
chokidar: { test: true }
|
||||
}
|
||||
nuxt.options.build.watch = [
|
||||
'/var/nuxt/src/custom'
|
||||
]
|
||||
|
||||
const patterns = ['/patterns']
|
||||
const events = ['event', 'another event']
|
||||
const listener = jest.fn()
|
||||
const watcherCreatedCallback = jest.fn()
|
||||
|
||||
const builder = new Builder(nuxt, {})
|
||||
const refreshFiles = jest.fn()
|
||||
builder.createFileWatcher(patterns, events, listener, watcherCreatedCallback)
|
||||
|
||||
builder.watchCustom(refreshFiles, true)
|
||||
|
||||
expect(refreshFiles).toBeCalledTimes(1)
|
||||
expect(chokidar.watch).toBeCalledTimes(1)
|
||||
expect(chokidar.watch).toBeCalledWith(patterns, { test: true })
|
||||
expect(chokidar.on).toBeCalledTimes(2)
|
||||
expect(chokidar.on).nthCalledWith(1, 'event', listener)
|
||||
expect(chokidar.on).nthCalledWith(2, 'another event', listener)
|
||||
expect(watcherCreatedCallback).toBeCalledTimes(1)
|
||||
})
|
||||
|
||||
test('should rewatch custom patterns when event is included in rewatchOnRawEvents', () => {
|
||||
test('should restart watcher when event is included in rewatchOnRawEvents', () => {
|
||||
const nuxt = createNuxt()
|
||||
nuxt.options.srcDir = '/var/nuxt/src'
|
||||
nuxt.options.dir = {
|
||||
layouts: '/var/nuxt/src/layouts',
|
||||
pages: '/var/nuxt/src/pages',
|
||||
store: '/var/nuxt/src/store',
|
||||
middleware: '/var/nuxt/src/middleware'
|
||||
}
|
||||
nuxt.options.watchers = {
|
||||
chokidar: { test: true },
|
||||
rewatchOnRawEvents: ['rename']
|
||||
}
|
||||
nuxt.options.build.watch = [
|
||||
'/var/nuxt/src/custom'
|
||||
]
|
||||
const builder = new Builder(nuxt, {})
|
||||
const refreshFiles = jest.fn()
|
||||
|
||||
builder.watchCustom(refreshFiles)
|
||||
const patterns = ['/pattern']
|
||||
const events = ['event']
|
||||
const listener = jest.fn()
|
||||
const watcherCreatedCallback = jest.fn()
|
||||
|
||||
const builder = new Builder(nuxt, {})
|
||||
builder.createFileWatcher(patterns, events, listener, watcherCreatedCallback)
|
||||
|
||||
expect(chokidar.on).toBeCalledTimes(2)
|
||||
expect(chokidar.on).nthCalledWith(2, 'raw', expect.any(Function))
|
||||
|
||||
const rewatchHandler = chokidar.on.mock.calls[1][1]
|
||||
builder.watchCustom = jest.fn()
|
||||
rewatchHandler('rename')
|
||||
rewatchHandler('change')
|
||||
|
||||
expect(chokidar.close).toBeCalledTimes(1)
|
||||
expect(builder.watchers.custom).toBeNull()
|
||||
expect(builder.watchCustom).toBeCalledTimes(1)
|
||||
expect(builder.watchCustom).toBeCalledWith(refreshFiles, true)
|
||||
expect(watcherCreatedCallback).toBeCalledTimes(2)
|
||||
})
|
||||
|
||||
test('should watch files for restarting server', () => {
|
||||
@ -327,4 +348,18 @@ describe('builder: builder watch', () => {
|
||||
expect(builder.unwatch).not.toBeCalled()
|
||||
expect(bundleBuilderClose).not.toBeCalled()
|
||||
})
|
||||
|
||||
test('should assign watcher with key', () => {
|
||||
const nuxt = createNuxt()
|
||||
const builder = new Builder(nuxt, {})
|
||||
|
||||
const key = 'key'
|
||||
const watcher = 'watcher'
|
||||
|
||||
const fn = builder.assignWatcher(key)
|
||||
fn(watcher)
|
||||
|
||||
expect(Boolean(builder.watchers[key])).toBe(true)
|
||||
expect(builder.watchers[key]).toBe(watcher)
|
||||
})
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user