perf: allow using @parcel/watcher for dev watcher (#20179)

This commit is contained in:
Daniel Roe 2023-04-19 22:02:52 +01:00 committed by GitHub
parent 83f0103a47
commit a086af9692
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 104 additions and 7 deletions

View File

@ -99,6 +99,7 @@
"vue-router": "^4.1.6"
},
"devDependencies": {
"@parcel/watcher": "^2.1.0",
"@types/estree": "^1.0.1",
"@types/fs-extra": "^11.0.1",
"@types/prompts": "^2.4.4",
@ -109,8 +110,14 @@
"vitest": "^0.30.1"
},
"peerDependencies": {
"@parcel/watcher": "^2.1.0",
"@types/node": "^14.18.0 || ^16.10.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@parcel/watcher": {
"optional": true
}
},
"engines": {
"node": "^14.18.0 || ^16.10.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}

View File

@ -1,6 +1,8 @@
import { pathToFileURL } from 'node:url'
import type { EventType } from '@parcel/watcher'
import chokidar from 'chokidar'
import { isIgnored, tryResolveModule } from '@nuxt/kit'
import { interopDefault } from 'mlly'
import { debounce } from 'perfect-debounce'
import { normalize } from 'pathe'
import type { Nuxt } from 'nuxt/schema'
@ -43,7 +45,45 @@ export async function build (nuxt: Nuxt) {
}
}
function watch (nuxt: Nuxt) {
const watchEvents: Record<EventType, 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir'> = {
create: 'add',
delete: 'unlink',
update: 'change'
}
async function watch (nuxt: Nuxt) {
if (nuxt.options.experimental.watcher === 'parcel') {
if (nuxt.options.debug) {
console.time('[nuxt] builder:parcel:watch')
}
const watcherPath = await tryResolveModule('@parcel/watcher', [nuxt.options.rootDir, ...nuxt.options.modulesDir])
if (watcherPath) {
const { subscribe } = await import(pathToFileURL(watcherPath).href).then(interopDefault) as typeof import('@parcel/watcher')
for (const layer of nuxt.options._layers) {
if (!layer.config.srcDir) { continue }
const watcher = subscribe(layer.config.srcDir, (err, events) => {
if (err) { return }
for (const event of events) {
if (isIgnored(event.path)) { continue }
nuxt.callHook('builder:watch', watchEvents[event.type], normalize(event.path))
}
}, {
ignore: [
...nuxt.options.ignore,
'.nuxt',
'node_modules'
]
})
watcher.then((subscription) => {
console.timeEnd('[nuxt] builder:parcel:watch')
nuxt.hook('close', () => subscription.unsubscribe())
})
}
return
}
console.warn('[nuxt] falling back to `chokidar` as `@parcel/watcher` cannot be resolved in your project.')
}
if (nuxt.options.debug) {
console.time('[nuxt] builder:chokidar:watch')
}
@ -65,7 +105,6 @@ function watch (nuxt: Nuxt) {
watcher.on('all', (event, path) => nuxt.callHook('builder:watch', event, normalize(path)))
nuxt.hook('close', () => watcher.close())
return watcher
}
async function bundle (nuxt: Nuxt) {

View File

@ -1,10 +1,12 @@
import { existsSync } from 'node:fs'
import { mkdir, writeFile } from 'node:fs/promises'
import { pathToFileURL } from 'node:url'
import { dirname, resolve } from 'pathe'
import chokidar from 'chokidar'
import { interopDefault } from 'mlly'
import { defu } from 'defu'
import { debounce } from 'perfect-debounce'
import { createResolver, defineNuxtModule } from '@nuxt/kit'
import { createResolver, defineNuxtModule, tryResolveModule } from '@nuxt/kit'
import {
generateTypes,
resolveSchema as resolveUntypedSchema
@ -57,6 +59,26 @@ export default defineNuxtModule({
// Watch for schema changes in development mode
if (nuxt.options.dev) {
const onChange = debounce(async () => {
schema = await resolveSchema()
await writeSchema(schema)
})
if (nuxt.options.experimental.watcher === 'parcel') {
const watcherPath = await tryResolveModule('@parcel/watcher', [nuxt.options.rootDir, ...nuxt.options.modulesDir])
if (watcherPath) {
const { subscribe } = await import(pathToFileURL(watcherPath).href).then(interopDefault) as typeof import('@parcel/watcher')
for (const layer of nuxt.options._layers) {
const subscription = await subscribe(layer.config.rootDir, onChange, {
ignore: ['!nuxt.schema.*']
})
nuxt.hook('close', () => subscription.unsubscribe())
}
return
}
console.warn('[nuxt] falling back to `chokidar` as `@parcel/watcher` cannot be resolved in your project.')
}
const filesToWatch = await Promise.all(nuxt.options._layers.map(layer =>
resolver.resolve(layer.config.rootDir, 'nuxt.schema.*')
))
@ -64,10 +86,6 @@ export default defineNuxtModule({
...nuxt.options.watchers.chokidar,
ignoreInitial: true
})
const onChange = debounce(async () => {
schema = await resolveSchema()
await writeSchema(schema)
})
watcher.on('all', onChange)
nuxt.hook('close', () => watcher.close())
}

View File

@ -345,6 +345,7 @@ export default defineUntypedSchema({
'**/*.{spec,test}.{js,ts,jsx,tsx}', // ignore tests
'**/*.d.ts', // ignore type declarations
'.output',
'.git',
await get('ignorePrefix') && `**/${await get('ignorePrefix')}*.*`
].concat(val).filter(Boolean)
},

View File

@ -161,5 +161,19 @@ export default defineUntypedSchema({
/** Resolve `~`, `~~`, `@` and `@@` aliases located within layers with respect to their layer source and root directories. */
localLayerAliases: true,
/**
* Set an alternative watcher that will be used as the watching service for Nuxt.
*
* Nuxt uses 'chokidar' by default, but by setting this to `parcel` it will use
* `@parcel/watcher` instead. This may improve performance in large projects or
* on Windows platforms.
*
* @see https://github.com/paulmillr/chokidar
* @see https://github.com/parcel-bundler/watcher
* @default chokidar
* @type {'chokidar' | 'parcel'}
*/
watcher: 'chokidar'
}
})

View File

@ -687,6 +687,9 @@ importers:
specifier: ^4.1.6
version: 4.1.6(vue@3.2.47)
devDependencies:
'@parcel/watcher':
specifier: ^2.1.0
version: 2.1.0
'@types/estree':
specifier: ^1.0.1
version: 1.0.1
@ -2133,6 +2136,17 @@ packages:
- supports-color
dev: true
/@parcel/watcher@2.1.0:
resolution: {integrity: sha512-8s8yYjd19pDSsBpbkOHnT6Z2+UJSuLQx61pCFM0s5wSRvKCEMDjd/cHY3/GI1szHIWbpXpsJdg3V6ISGGx9xDw==}
engines: {node: '>= 10.0.0'}
requiresBuild: true
dependencies:
is-glob: 4.0.3
micromatch: 4.0.5
node-addon-api: 3.2.1
node-gyp-build: 4.6.0
dev: true
/@pkgr/utils@2.3.1:
resolution: {integrity: sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
@ -7238,6 +7252,10 @@ packages:
resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==}
dev: false
/node-addon-api@3.2.1:
resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==}
dev: true
/node-domexception@1.0.0:
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
engines: {node: '>=10.5.0'}