mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-26 07:32:01 +00:00
feat(nuxt): add watch
option and refactor dev server restarting (#19530)
This commit is contained in:
parent
eb1bb59542
commit
9036142b14
@ -1,7 +1,6 @@
|
||||
import type { AddressInfo } from 'node:net'
|
||||
import type { RequestListener } from 'node:http'
|
||||
import { existsSync, readdirSync } from 'node:fs'
|
||||
import { resolve, relative, normalize } from 'pathe'
|
||||
import { resolve, relative } from 'pathe'
|
||||
import chokidar from 'chokidar'
|
||||
import { debounce } from 'perfect-debounce'
|
||||
import type { Nuxt } from '@nuxt/schema'
|
||||
@ -160,42 +159,11 @@ export default defineNuxtCommand({
|
||||
// Watch for config changes
|
||||
// TODO: Watcher service, modules, and requireTree
|
||||
const dLoad = debounce(load)
|
||||
const watcher = chokidar.watch([rootDir], { ignoreInitial: true, depth: 1 })
|
||||
watcher.on('all', (event, _file) => {
|
||||
if (!currentNuxt) { return }
|
||||
const file = normalize(_file)
|
||||
const buildDir = withTrailingSlash(normalize(currentNuxt.options.buildDir))
|
||||
if (file.startsWith(buildDir)) { return }
|
||||
const relativePath = relative(rootDir, file)
|
||||
if (file.match(/(nuxt\.config\.(js|ts|mjs|cjs)|\.nuxtignore|\.env|\.nuxtrc)$/)) {
|
||||
dLoad(true, `${relativePath} updated`)
|
||||
}
|
||||
|
||||
const isDirChange = ['addDir', 'unlinkDir'].includes(event)
|
||||
const isFileChange = ['add', 'unlink'].includes(event)
|
||||
const pagesDir = resolve(currentNuxt.options.srcDir, currentNuxt.options.dir.pages)
|
||||
const reloadDirs = ['components', 'composables', 'utils'].map(d => resolve(currentNuxt.options.srcDir, d))
|
||||
|
||||
if (isDirChange) {
|
||||
if (reloadDirs.includes(file)) {
|
||||
return dLoad(true, `Directory \`${relativePath}/\` ${event === 'addDir' ? 'created' : 'removed'}`)
|
||||
}
|
||||
}
|
||||
|
||||
if (isFileChange) {
|
||||
if (file.match(/(app|error|app\.config)\.(js|ts|mjs|jsx|tsx|vue)$/)) {
|
||||
return dLoad(true, `\`${relativePath}\` ${event === 'add' ? 'created' : 'removed'}`)
|
||||
}
|
||||
}
|
||||
|
||||
if (file.startsWith(pagesDir)) {
|
||||
const hasPages = existsSync(pagesDir) ? readdirSync(pagesDir).length > 0 : false
|
||||
if (currentNuxt && !currentNuxt.options.pages && hasPages) {
|
||||
return dLoad(true, 'Pages enabled')
|
||||
}
|
||||
if (currentNuxt && currentNuxt.options.pages && !hasPages) {
|
||||
return dLoad(true, 'Pages disabled')
|
||||
}
|
||||
const watcher = chokidar.watch([rootDir], { ignoreInitial: true, depth: 0 })
|
||||
watcher.on('all', (_event, _file) => {
|
||||
const file = relative(rootDir, _file)
|
||||
if (file.match(/^(nuxt\.config\.(js|ts|mjs|cjs)|\.nuxtignore|\.env|\.nuxtrc)$/)) {
|
||||
dLoad(true, `${file} updated`)
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -148,6 +148,17 @@ export default defineNuxtModule<ComponentsOptions>({
|
||||
}
|
||||
})
|
||||
|
||||
// Restart dev server when component directories are added/removed
|
||||
nuxt.hook('builder:watch', (event, path) => {
|
||||
const isDirChange = ['addDir', 'unlinkDir'].includes(event)
|
||||
const fullPath = resolve(nuxt.options.srcDir, path)
|
||||
|
||||
if (isDirChange && componentDirs.some(dir => dir.path === fullPath)) {
|
||||
console.info(`Directory \`${path}/\` ${event === 'addDir' ? 'created' : 'removed'}`)
|
||||
return nuxt.callHook('restart')
|
||||
}
|
||||
})
|
||||
|
||||
// Scan components and add to plugin
|
||||
nuxt.hook('app:templates', async () => {
|
||||
const newComponents = await scanComponents(componentDirs, nuxt.options.srcDir!)
|
||||
|
@ -161,10 +161,6 @@ async function initNuxt (nuxt: Nuxt) {
|
||||
// Register user and then ad-hoc modules
|
||||
modulesToInstall.push(...nuxt.options.modules, ...nuxt.options._modules)
|
||||
|
||||
nuxt.hooks.hookOnce('builder:watch', (event, path) => {
|
||||
if (watchedPaths.has(path)) { nuxt.callHook('restart', { hard: true }) }
|
||||
})
|
||||
|
||||
// Add <NuxtWelcome>
|
||||
addComponent({
|
||||
name: 'NuxtWelcome',
|
||||
@ -285,6 +281,29 @@ async function initNuxt (nuxt: Nuxt) {
|
||||
|
||||
await nuxt.callHook('modules:done')
|
||||
|
||||
nuxt.hooks.hook('builder:watch', (event, path) => {
|
||||
// Local module patterns
|
||||
if (watchedPaths.has(path)) {
|
||||
return nuxt.callHook('restart', { hard: true })
|
||||
}
|
||||
|
||||
// User provided patterns
|
||||
for (const pattern of nuxt.options.watch) {
|
||||
if (typeof pattern === 'string') {
|
||||
if (pattern === path) { return nuxt.callHook('restart') }
|
||||
continue
|
||||
}
|
||||
if (pattern.test(path)) { return nuxt.callHook('restart') }
|
||||
}
|
||||
|
||||
// Core Nuxt files: app.vue, error.vue and app.config.ts
|
||||
const isFileChange = ['add', 'unlink'].includes(event)
|
||||
if (isFileChange && path.match(/^(app|error|app\.config)\.(js|ts|mjs|jsx|tsx|vue)$/i)) {
|
||||
console.info(`\`${path}\` ${event === 'add' ? 'created' : 'removed'}`)
|
||||
return nuxt.callHook('restart')
|
||||
}
|
||||
})
|
||||
|
||||
// Normalize windows transpile paths added by modules
|
||||
nuxt.options.build.transpile = nuxt.options.build.transpile.map(t => typeof t === 'string' ? normalize(t) : t)
|
||||
|
||||
|
@ -61,6 +61,17 @@ export default defineNuxtModule<Partial<ImportsOptions>>({
|
||||
await nuxt.callHook('imports:dirs', composablesDirs)
|
||||
composablesDirs = composablesDirs.map(dir => normalize(dir))
|
||||
|
||||
// Restart nuxt when composable directories are added/removed
|
||||
nuxt.hook('builder:watch', (event, path) => {
|
||||
const isDirChange = ['addDir', 'unlinkDir'].includes(event)
|
||||
const fullPath = resolve(nuxt.options.srcDir, path)
|
||||
|
||||
if (isDirChange && composablesDirs.includes(fullPath)) {
|
||||
console.info(`Directory \`${path}/\` ${event === 'addDir' ? 'created' : 'removed'}`)
|
||||
return nuxt.callHook('restart')
|
||||
}
|
||||
})
|
||||
|
||||
// Support for importing from '#imports'
|
||||
addTemplate({
|
||||
filename: 'imports.mjs',
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { existsSync, readdirSync } from 'node:fs'
|
||||
import { defineNuxtModule, addTemplate, addPlugin, addVitePlugin, addWebpackPlugin, findPath, addComponent, updateTemplates } from '@nuxt/kit'
|
||||
import { relative, resolve } from 'pathe'
|
||||
import { join, relative, resolve } from 'pathe'
|
||||
import { genString, genImport, genObjectFromRawEntries } from 'knitwork'
|
||||
import escapeRE from 'escape-string-regexp'
|
||||
import { joinURL } from 'ufo'
|
||||
@ -21,9 +21,10 @@ export default defineNuxtModule({
|
||||
|
||||
// Disable module (and use universal router) if pages dir do not exists or user has disabled it
|
||||
const isNonEmptyDir = (dir: string) => existsSync(dir) && readdirSync(dir).length
|
||||
const userPreference = nuxt.options.pages
|
||||
const isPagesEnabled = () => {
|
||||
if (typeof nuxt.options.pages === 'boolean') {
|
||||
return nuxt.options.pages
|
||||
if (typeof userPreference === 'boolean') {
|
||||
return userPreference
|
||||
}
|
||||
if (nuxt.options._layers.some(layer => existsSync(resolve(layer.config.srcDir, 'app/router.options.ts')))) {
|
||||
return true
|
||||
@ -35,6 +36,22 @@ export default defineNuxtModule({
|
||||
}
|
||||
nuxt.options.pages = isPagesEnabled()
|
||||
|
||||
// Restart Nuxt when pages dir is added or removed
|
||||
const restartPaths = nuxt.options._layers.flatMap(layer => [
|
||||
join(layer.config.srcDir, 'app/router.options.ts'),
|
||||
join(layer.config.srcDir, layer.config.dir?.pages || 'pages')
|
||||
])
|
||||
nuxt.hooks.hook('builder:watch', (event, path) => {
|
||||
const fullPath = join(nuxt.options.srcDir, path)
|
||||
if (restartPaths.some(path => path === fullPath || fullPath.startsWith(path + '/'))) {
|
||||
const newSetting = isPagesEnabled()
|
||||
if (nuxt.options.pages !== newSetting) {
|
||||
console.info('Pages', newSetting ? 'enabled' : 'disabled')
|
||||
return nuxt.callHook('restart')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (!nuxt.options.pages) {
|
||||
addPlugin(resolve(distDir, 'app/plugins/router'))
|
||||
addTemplate({
|
||||
|
@ -345,6 +345,18 @@ export default defineUntypedSchema({
|
||||
].concat(val).filter(Boolean)
|
||||
},
|
||||
|
||||
/**
|
||||
* The watch property lets you define patterns that will restart the Nuxt dev server when changed.
|
||||
*
|
||||
* It is an array of strings or regular expressions, which will be matched against the file path
|
||||
* relative to the project `srcDir`.
|
||||
*
|
||||
* @type {Array<string | RegExp>}
|
||||
*/
|
||||
watch: {
|
||||
$resolve: val => [].concat(val).filter((b: unknown) => typeof b === 'string' || b instanceof RegExp),
|
||||
},
|
||||
|
||||
/**
|
||||
* The watchers property lets you overwrite watchers configuration in your `nuxt.config`.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user