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,
|
determineGlobals,
|
||||||
stripWhitespace,
|
stripWhitespace,
|
||||||
isString,
|
isString,
|
||||||
isIndexFileAndFolder
|
isIndexFileAndFolder,
|
||||||
|
isPureObject,
|
||||||
|
clearRequireCache
|
||||||
} from '@nuxt/utils'
|
} from '@nuxt/utils'
|
||||||
|
|
||||||
import Ignore from './ignore'
|
import Ignore from './ignore'
|
||||||
@ -30,7 +32,6 @@ import BuildContext from './context/build'
|
|||||||
import TemplateContext from './context/template'
|
import TemplateContext from './context/template'
|
||||||
|
|
||||||
const glob = pify(Glob)
|
const glob = pify(Glob)
|
||||||
|
|
||||||
export default class Builder {
|
export default class Builder {
|
||||||
constructor(nuxt, bundleBuilder) {
|
constructor(nuxt, bundleBuilder) {
|
||||||
this.nuxt = nuxt
|
this.nuxt = nuxt
|
||||||
@ -616,10 +617,12 @@ export default class Builder {
|
|||||||
|
|
||||||
let patterns = [
|
let patterns = [
|
||||||
r(src, this.options.dir.layouts),
|
r(src, this.options.dir.layouts),
|
||||||
r(src, this.options.dir.store),
|
|
||||||
r(src, this.options.dir.middleware),
|
r(src, this.options.dir.middleware),
|
||||||
...rGlob(this.options.dir.layouts)
|
...rGlob(this.options.dir.layouts)
|
||||||
]
|
]
|
||||||
|
if (this.options.store) {
|
||||||
|
patterns.push(r(src, this.options.dir.store))
|
||||||
|
}
|
||||||
|
|
||||||
if (this._nuxtPages) {
|
if (this._nuxtPages) {
|
||||||
patterns.push(
|
patterns.push(
|
||||||
@ -648,10 +651,25 @@ export default class Builder {
|
|||||||
this.createFileWatcher(customPatterns, ['change'], refreshFiles, this.assignWatcher('custom'))
|
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() {
|
watchRestart() {
|
||||||
|
const serverMiddlewarePaths = this.getServerMiddlewarePaths()
|
||||||
const nuxtRestartWatch = [
|
const nuxtRestartWatch = [
|
||||||
// Server middleware
|
// Server middleware
|
||||||
...this.options.serverMiddleware.filter(isString),
|
...serverMiddlewarePaths,
|
||||||
// Custom watchers
|
// Custom watchers
|
||||||
...this.options.watch
|
...this.options.watch
|
||||||
].map(this.nuxt.resolver.resolveAlias)
|
].map(this.nuxt.resolver.resolveAlias)
|
||||||
@ -659,6 +677,10 @@ export default class Builder {
|
|||||||
if (this.ignore.ignoreFile) {
|
if (this.ignore.ignoreFile) {
|
||||||
nuxtRestartWatch.push(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(
|
this.createFileWatcher(
|
||||||
nuxtRestartWatch,
|
nuxtRestartWatch,
|
||||||
@ -667,6 +689,11 @@ export default class Builder {
|
|||||||
if (['add', 'change', 'unlink'].includes(event) === false) {
|
if (['add', 'change', 'unlink'].includes(event) === false) {
|
||||||
return
|
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:fileChanged', this, fileName) // Legacy
|
||||||
await this.nuxt.callHook('watch:restart', { event, path: fileName })
|
await this.nuxt.callHook('watch:restart', { event, path: fileName })
|
||||||
},
|
},
|
||||||
|
@ -10,6 +10,7 @@ export const createNuxt = () => ({
|
|||||||
callHook: jest.fn(),
|
callHook: jest.fn(),
|
||||||
resolver: {
|
resolver: {
|
||||||
requireModule: jest.fn(() => ({ template: 'builder-template' })),
|
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 chokidar from 'chokidar'
|
||||||
import upath from 'upath'
|
import upath from 'upath'
|
||||||
import debounce from 'lodash/debounce'
|
import debounce from 'lodash/debounce'
|
||||||
import { r, isString } from '@nuxt/utils'
|
import { r, isString, isPureObject } from '@nuxt/utils'
|
||||||
|
|
||||||
import Builder from '../src/builder'
|
import Builder from '../src/builder'
|
||||||
import { createNuxt } from './__utils__'
|
import { createNuxt } from './__utils__'
|
||||||
@ -41,31 +42,51 @@ describe('builder: builder watch', () => {
|
|||||||
|
|
||||||
const patterns = [
|
const patterns = [
|
||||||
'/var/nuxt/src/layouts',
|
'/var/nuxt/src/layouts',
|
||||||
'/var/nuxt/src/store',
|
|
||||||
'/var/nuxt/src/middleware',
|
'/var/nuxt/src/middleware',
|
||||||
'/var/nuxt/src/layouts/*.{vue,js,ts,tsx}',
|
'/var/nuxt/src/layouts/*.{vue,js,ts,tsx}',
|
||||||
'/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(1, '/var/nuxt/src', '/var/nuxt/src/layouts')
|
||||||
expect(r).nthCalledWith(2, '/var/nuxt/src', '/var/nuxt/src/store')
|
expect(r).nthCalledWith(2, '/var/nuxt/src', '/var/nuxt/src/middleware')
|
||||||
expect(r).nthCalledWith(3, '/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(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(upath.normalizeSafe).toBeCalledTimes(5)
|
expect(upath.normalizeSafe).toBeCalledTimes(4)
|
||||||
expect(upath.normalizeSafe).nthCalledWith(1, '/var/nuxt/src/layouts', 0, patterns)
|
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(2, '/var/nuxt/src/middleware', 1, patterns)
|
||||||
expect(upath.normalizeSafe).nthCalledWith(3, '/var/nuxt/src/middleware', 2, 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(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(builder.createFileWatcher).toBeCalledTimes(1)
|
expect(builder.createFileWatcher).toBeCalledTimes(1)
|
||||||
expect(builder.createFileWatcher).toBeCalledWith(patterns, ['add', 'unlink'], expect.any(Function), expect.any(Function))
|
expect(builder.createFileWatcher).toBeCalledWith(patterns, ['add', 'unlink'], expect.any(Function), expect.any(Function))
|
||||||
expect(builder.assignWatcher).toBeCalledTimes(1)
|
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', () => {
|
test('should watch pages files', () => {
|
||||||
const nuxt = createNuxt()
|
const nuxt = createNuxt()
|
||||||
nuxt.options.srcDir = '/var/nuxt/src'
|
nuxt.options.srcDir = '/var/nuxt/src'
|
||||||
@ -86,10 +107,10 @@ describe('builder: builder watch', () => {
|
|||||||
|
|
||||||
builder.watchClient()
|
builder.watchClient()
|
||||||
|
|
||||||
expect(r).toBeCalledTimes(8)
|
expect(r).toBeCalledTimes(7)
|
||||||
expect(r).nthCalledWith(6, '/var/nuxt/src', '/var/nuxt/src/pages')
|
expect(r).nthCalledWith(5, '/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(6, '/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).nthCalledWith(7, '/var/nuxt/src', '/var/nuxt/src/pages/**/*.{vue,js,ts,tsx}')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should invoke generateRoutesAndFiles on file refresh', () => {
|
test('should invoke generateRoutesAndFiles on file refresh', () => {
|
||||||
@ -215,6 +236,13 @@ describe('builder: builder watch', () => {
|
|||||||
|
|
||||||
test('should watch files for restarting server', () => {
|
test('should watch files for restarting server', () => {
|
||||||
const nuxt = createNuxt()
|
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 = {
|
nuxt.options.watchers = {
|
||||||
chokidar: { test: true }
|
chokidar: { test: true }
|
||||||
}
|
}
|
||||||
@ -222,21 +250,25 @@ describe('builder: builder watch', () => {
|
|||||||
'/var/nuxt/src/watch/test'
|
'/var/nuxt/src/watch/test'
|
||||||
]
|
]
|
||||||
nuxt.options.serverMiddleware = [
|
nuxt.options.serverMiddleware = [
|
||||||
'/var/nuxt/src/middleware/test',
|
'/var/nuxt/src/serverMiddleware/test',
|
||||||
|
{ path: '/test', handler: '/var/nuxt/src/serverMiddleware/test-handler' },
|
||||||
{ obj: 'test' }
|
{ obj: 'test' }
|
||||||
]
|
]
|
||||||
const builder = new Builder(nuxt, {})
|
const builder = new Builder(nuxt, {})
|
||||||
builder.ignore.ignoreFile = '/var/nuxt/src/.nuxtignore'
|
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()
|
builder.watchRestart()
|
||||||
|
|
||||||
expect(chokidar.watch).toBeCalledTimes(1)
|
expect(chokidar.watch).toBeCalledTimes(1)
|
||||||
expect(chokidar.watch).toBeCalledWith(
|
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)',
|
'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 }
|
{ test: true }
|
||||||
)
|
)
|
||||||
@ -246,6 +278,13 @@ describe('builder: builder watch', () => {
|
|||||||
|
|
||||||
test('should trigger restarting when files changed', async () => {
|
test('should trigger restarting when files changed', async () => {
|
||||||
const nuxt = createNuxt()
|
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 = {
|
nuxt.options.watchers = {
|
||||||
chokidar: { test: true }
|
chokidar: { test: true }
|
||||||
}
|
}
|
||||||
@ -274,6 +313,13 @@ describe('builder: builder watch', () => {
|
|||||||
|
|
||||||
test('should ignore other events in watchRestart', () => {
|
test('should ignore other events in watchRestart', () => {
|
||||||
const nuxt = createNuxt()
|
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 = {
|
nuxt.options.watchers = {
|
||||||
chokidar: { test: true }
|
chokidar: { test: true }
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ export default {
|
|||||||
const nuxt = await cmd.getNuxt(config)
|
const nuxt = await cmd.getNuxt(config)
|
||||||
|
|
||||||
// Setup hooks
|
// 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))
|
nuxt.hook('bundler:change', changedFileName => this.onBundlerChange(changedFileName))
|
||||||
|
|
||||||
// Wait for nuxt to be ready
|
// 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 isNonEmptyString = obj => Boolean(obj && isString(obj))
|
||||||
|
|
||||||
export const isPureObject = function isPureObject(o) {
|
export const isPureObject = obj => !Array.isArray(obj) && typeof obj === 'object'
|
||||||
return !Array.isArray(o) && typeof o === 'object'
|
|
||||||
}
|
|
||||||
|
|
||||||
export const isUrl = function isUrl(url) {
|
export const isUrl = function isUrl(url) {
|
||||||
return ['http', '//'].some(str => url.startsWith(str))
|
return ['http', '//'].some(str => url.startsWith(str))
|
||||||
|
Loading…
Reference in New Issue
Block a user