mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +00:00
fix(builder): watch store dir and serverMiddleware
paths (#5681)
* fix(builder): Watch store dir to restart Nuxt app when options.store=false * hotfix: Linting issues * hotfix: Use path.resolve instead of path.join * test: Update test for watcher * hotfix: revert to path.join and fix tests * hotfix: Fix coverage for hard to test condition * hotfix: Fix test for Windows * Update builder.js * fix lint error * fix: Cache serverMiddlewarePaths
This commit is contained in:
parent
f2bd2f56de
commit
03eb049677
@ -22,7 +22,9 @@ import {
|
||||
determineGlobals,
|
||||
stripWhitespace,
|
||||
isString,
|
||||
isIndexFileAndFolder
|
||||
isIndexFileAndFolder,
|
||||
isPureObject,
|
||||
clearRequireCache
|
||||
} from '@nuxt/utils'
|
||||
|
||||
import Ignore from './ignore'
|
||||
@ -30,7 +32,6 @@ import BuildContext from './context/build'
|
||||
import TemplateContext from './context/template'
|
||||
|
||||
const glob = pify(Glob)
|
||||
|
||||
export default class Builder {
|
||||
constructor(nuxt, bundleBuilder) {
|
||||
this.nuxt = nuxt
|
||||
@ -616,10 +617,12 @@ export default class Builder {
|
||||
|
||||
let patterns = [
|
||||
r(src, this.options.dir.layouts),
|
||||
r(src, this.options.dir.store),
|
||||
r(src, this.options.dir.middleware),
|
||||
...rGlob(this.options.dir.layouts)
|
||||
]
|
||||
if (this.options.store) {
|
||||
patterns.push(r(src, this.options.dir.store))
|
||||
}
|
||||
|
||||
if (this._nuxtPages) {
|
||||
patterns.push(
|
||||
@ -648,10 +651,25 @@ export default class Builder {
|
||||
this.createFileWatcher(customPatterns, ['change'], refreshFiles, this.assignWatcher('custom'))
|
||||
}
|
||||
|
||||
getServerMiddlewarePaths() {
|
||||
return this.options.serverMiddleware
|
||||
.map((serverMiddleware) => {
|
||||
if (isString(serverMiddleware)) {
|
||||
return serverMiddleware
|
||||
}
|
||||
if (isPureObject(serverMiddleware) && isString(serverMiddleware.handler)) {
|
||||
return serverMiddleware.handler
|
||||
}
|
||||
})
|
||||
.filter(Boolean)
|
||||
.map(p => path.extname(p) ? p : this.nuxt.resolver.resolvePath(p))
|
||||
}
|
||||
|
||||
watchRestart() {
|
||||
const serverMiddlewarePaths = this.getServerMiddlewarePaths()
|
||||
const nuxtRestartWatch = [
|
||||
// Server middleware
|
||||
...this.options.serverMiddleware.filter(isString),
|
||||
...serverMiddlewarePaths,
|
||||
// Custom watchers
|
||||
...this.options.watch
|
||||
].map(this.nuxt.resolver.resolveAlias)
|
||||
@ -659,6 +677,10 @@ export default class Builder {
|
||||
if (this.ignore.ignoreFile) {
|
||||
nuxtRestartWatch.push(this.ignore.ignoreFile)
|
||||
}
|
||||
// If store not activated, watch for a file in the directory
|
||||
if (!this.options.store) {
|
||||
nuxtRestartWatch.push(path.join(this.options.srcDir, this.options.dir.store))
|
||||
}
|
||||
|
||||
this.createFileWatcher(
|
||||
nuxtRestartWatch,
|
||||
@ -667,6 +689,11 @@ export default class Builder {
|
||||
if (['add', 'change', 'unlink'].includes(event) === false) {
|
||||
return
|
||||
}
|
||||
/* istanbul ignore if */
|
||||
if (serverMiddlewarePaths.includes(fileName)) {
|
||||
consola.debug(`Clear cache for ${fileName}`)
|
||||
clearRequireCache(fileName)
|
||||
}
|
||||
await this.nuxt.callHook('watch:fileChanged', this, fileName) // Legacy
|
||||
await this.nuxt.callHook('watch:restart', { event, path: fileName })
|
||||
},
|
||||
|
@ -10,6 +10,7 @@ export const createNuxt = () => ({
|
||||
callHook: jest.fn(),
|
||||
resolver: {
|
||||
requireModule: jest.fn(() => ({ template: 'builder-template' })),
|
||||
resolveAlias: jest.fn(src => `resolveAlias(${src})`)
|
||||
resolveAlias: jest.fn(src => `resolveAlias(${src})`),
|
||||
resolvePath: jest.fn(src => `resolvePath(${src})`)
|
||||
}
|
||||
})
|
||||
|
@ -1,7 +1,8 @@
|
||||
import path from 'path'
|
||||
import chokidar from 'chokidar'
|
||||
import upath from 'upath'
|
||||
import debounce from 'lodash/debounce'
|
||||
import { r, isString } from '@nuxt/utils'
|
||||
import { r, isString, isPureObject } from '@nuxt/utils'
|
||||
|
||||
import Builder from '../src/builder'
|
||||
import { createNuxt } from './__utils__'
|
||||
@ -41,31 +42,51 @@ describe('builder: builder watch', () => {
|
||||
|
||||
const patterns = [
|
||||
'/var/nuxt/src/layouts',
|
||||
'/var/nuxt/src/store',
|
||||
'/var/nuxt/src/middleware',
|
||||
'/var/nuxt/src/layouts/*.{vue,js,ts,tsx}',
|
||||
'/var/nuxt/src/layouts/**/*.{vue,js,ts,tsx}'
|
||||
]
|
||||
|
||||
expect(r).toBeCalledTimes(5)
|
||||
expect(r).toBeCalledTimes(4)
|
||||
expect(r).nthCalledWith(1, '/var/nuxt/src', '/var/nuxt/src/layouts')
|
||||
expect(r).nthCalledWith(2, '/var/nuxt/src', '/var/nuxt/src/store')
|
||||
expect(r).nthCalledWith(3, '/var/nuxt/src', '/var/nuxt/src/middleware')
|
||||
expect(r).nthCalledWith(4, '/var/nuxt/src', '/var/nuxt/src/layouts/*.{vue,js,ts,tsx}')
|
||||
expect(r).nthCalledWith(5, '/var/nuxt/src', '/var/nuxt/src/layouts/**/*.{vue,js,ts,tsx}')
|
||||
expect(r).nthCalledWith(2, '/var/nuxt/src', '/var/nuxt/src/middleware')
|
||||
expect(r).nthCalledWith(3, '/var/nuxt/src', '/var/nuxt/src/layouts/*.{vue,js,ts,tsx}')
|
||||
expect(r).nthCalledWith(4, '/var/nuxt/src', '/var/nuxt/src/layouts/**/*.{vue,js,ts,tsx}')
|
||||
|
||||
expect(upath.normalizeSafe).toBeCalledTimes(5)
|
||||
expect(upath.normalizeSafe).toBeCalledTimes(4)
|
||||
expect(upath.normalizeSafe).nthCalledWith(1, '/var/nuxt/src/layouts', 0, patterns)
|
||||
expect(upath.normalizeSafe).nthCalledWith(2, '/var/nuxt/src/store', 1, patterns)
|
||||
expect(upath.normalizeSafe).nthCalledWith(3, '/var/nuxt/src/middleware', 2, patterns)
|
||||
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(upath.normalizeSafe).nthCalledWith(2, '/var/nuxt/src/middleware', 1, patterns)
|
||||
expect(upath.normalizeSafe).nthCalledWith(3, '/var/nuxt/src/layouts/*.{vue,js,ts,tsx}', 2, patterns)
|
||||
expect(upath.normalizeSafe).nthCalledWith(4, '/var/nuxt/src/layouts/**/*.{vue,js,ts,tsx}', 3, patterns)
|
||||
|
||||
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 store files', () => {
|
||||
const nuxt = createNuxt()
|
||||
nuxt.options.store = 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 = []
|
||||
|
||||
const builder = new Builder(nuxt, {})
|
||||
builder.createFileWatcher = jest.fn()
|
||||
builder.assignWatcher = jest.fn(() => () => {})
|
||||
r.mockImplementation((dir, src) => src)
|
||||
|
||||
builder.watchClient()
|
||||
|
||||
expect(r).toBeCalledTimes(5)
|
||||
expect(r).nthCalledWith(5, '/var/nuxt/src', '/var/nuxt/src/store')
|
||||
})
|
||||
|
||||
test('should watch pages files', () => {
|
||||
const nuxt = createNuxt()
|
||||
nuxt.options.srcDir = '/var/nuxt/src'
|
||||
@ -86,10 +107,10 @@ describe('builder: builder watch', () => {
|
||||
|
||||
builder.watchClient()
|
||||
|
||||
expect(r).toBeCalledTimes(8)
|
||||
expect(r).nthCalledWith(6, '/var/nuxt/src', '/var/nuxt/src/pages')
|
||||
expect(r).nthCalledWith(7, '/var/nuxt/src', '/var/nuxt/src/pages/*.{vue,js,ts,tsx}')
|
||||
expect(r).nthCalledWith(8, '/var/nuxt/src', '/var/nuxt/src/pages/**/*.{vue,js,ts,tsx}')
|
||||
expect(r).toBeCalledTimes(7)
|
||||
expect(r).nthCalledWith(5, '/var/nuxt/src', '/var/nuxt/src/pages')
|
||||
expect(r).nthCalledWith(6, '/var/nuxt/src', '/var/nuxt/src/pages/*.{vue,js,ts,tsx}')
|
||||
expect(r).nthCalledWith(7, '/var/nuxt/src', '/var/nuxt/src/pages/**/*.{vue,js,ts,tsx}')
|
||||
})
|
||||
|
||||
test('should invoke generateRoutesAndFiles on file refresh', () => {
|
||||
@ -215,6 +236,13 @@ describe('builder: builder watch', () => {
|
||||
|
||||
test('should watch files for restarting server', () => {
|
||||
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 }
|
||||
}
|
||||
@ -222,21 +250,25 @@ describe('builder: builder watch', () => {
|
||||
'/var/nuxt/src/watch/test'
|
||||
]
|
||||
nuxt.options.serverMiddleware = [
|
||||
'/var/nuxt/src/middleware/test',
|
||||
'/var/nuxt/src/serverMiddleware/test',
|
||||
{ path: '/test', handler: '/var/nuxt/src/serverMiddleware/test-handler' },
|
||||
{ obj: 'test' }
|
||||
]
|
||||
const builder = new Builder(nuxt, {})
|
||||
builder.ignore.ignoreFile = '/var/nuxt/src/.nuxtignore'
|
||||
isString.mockImplementationOnce(src => typeof src === 'string')
|
||||
isString.mockImplementation(src => typeof src === 'string')
|
||||
isPureObject.mockImplementation(obj => typeof obj === 'object')
|
||||
|
||||
builder.watchRestart()
|
||||
|
||||
expect(chokidar.watch).toBeCalledTimes(1)
|
||||
expect(chokidar.watch).toBeCalledWith(
|
||||
[
|
||||
'resolveAlias(/var/nuxt/src/middleware/test)',
|
||||
'resolveAlias(resolvePath(/var/nuxt/src/serverMiddleware/test))',
|
||||
'resolveAlias(resolvePath(/var/nuxt/src/serverMiddleware/test-handler))',
|
||||
'resolveAlias(/var/nuxt/src/watch/test)',
|
||||
'/var/nuxt/src/.nuxtignore'
|
||||
'/var/nuxt/src/.nuxtignore',
|
||||
path.join('/var/nuxt/src/var/nuxt/src/store') // because store == false + using path.join()
|
||||
],
|
||||
{ test: true }
|
||||
)
|
||||
@ -246,6 +278,13 @@ describe('builder: builder watch', () => {
|
||||
|
||||
test('should trigger restarting when files changed', async () => {
|
||||
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 }
|
||||
}
|
||||
@ -274,6 +313,13 @@ describe('builder: builder watch', () => {
|
||||
|
||||
test('should ignore other events in watchRestart', () => {
|
||||
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 }
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ export default {
|
||||
const nuxt = await cmd.getNuxt(config)
|
||||
|
||||
// Setup hooks
|
||||
nuxt.hook('watch:restart', payload => this.onWatchRestart(payload, { nuxt, builder, cmd, argv }))
|
||||
nuxt.hook('watch:restart', payload => this.onWatchRestart(payload, { nuxt, cmd, argv }))
|
||||
nuxt.hook('bundler:change', changedFileName => this.onBundlerChange(changedFileName))
|
||||
|
||||
// Wait for nuxt to be ready
|
||||
|
@ -6,9 +6,7 @@ export const isString = obj => typeof obj === 'string' || obj instanceof String
|
||||
|
||||
export const isNonEmptyString = obj => Boolean(obj && isString(obj))
|
||||
|
||||
export const isPureObject = function isPureObject(o) {
|
||||
return !Array.isArray(o) && typeof o === 'object'
|
||||
}
|
||||
export const isPureObject = obj => !Array.isArray(obj) && typeof obj === 'object'
|
||||
|
||||
export const isUrl = function isUrl(url) {
|
||||
return ['http', '//'].some(str => url.startsWith(str))
|
||||
|
Loading…
Reference in New Issue
Block a user