feat(nuxt): add pages:routerOptions hook (#24922)

This commit is contained in:
Daniel Roe 2024-01-18 16:06:00 +00:00 committed by GitHub
parent 951ffd6e01
commit 807ead6f1a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 38 additions and 16 deletions

View File

@ -50,6 +50,7 @@ Hook | Arguments | Description
`builder:generateApp` | `options` | Called before generating the app. `builder:generateApp` | `options` | Called before generating the app.
`builder:watch` | `event, path` | Called at build time in development when the watcher spots a change to a file or directory in the project. `builder:watch` | `event, path` | Called at build time in development when the watcher spots a change to a file or directory in the project.
`pages:extend` | `pages` | Called after pages routes are resolved. `pages:extend` | `pages` | Called after pages routes are resolved.
`pages:routerOptions` | `{ files: Array<{ path: string, optional?: boolean }> }` | Called when resolving `router.options` files.
`server:devHandler` | `handler` | Called when the dev middleware is being registered on the Nitro dev server. `server:devHandler` | `handler` | Called when the dev middleware is being registered on the Nitro dev server.
`imports:sources` | `presets` | Called at setup allowing modules to extend sources. `imports:sources` | `presets` | Called at setup allowing modules to extend sources.
`imports:extend` | `imports` | Called at setup allowing modules to extend imports. `imports:extend` | `imports` | Called at setup allowing modules to extend imports.

View File

@ -26,11 +26,27 @@ export default defineNuxtModule({
}, },
async setup (_options, nuxt) { async setup (_options, nuxt) {
const useExperimentalTypedPages = nuxt.options.experimental.typedPages const useExperimentalTypedPages = nuxt.options.experimental.typedPages
const runtimeDir = resolve(distDir, 'pages/runtime')
const pagesDirs = nuxt.options._layers.map( const pagesDirs = nuxt.options._layers.map(
layer => resolve(layer.config.srcDir, (layer.config.rootDir === nuxt.options.rootDir ? nuxt.options : layer.config).dir?.pages || 'pages') layer => resolve(layer.config.srcDir, (layer.config.rootDir === nuxt.options.rootDir ? nuxt.options : layer.config).dir?.pages || 'pages')
) )
async function resolveRouterOptions () {
const context = {
files: [] as Array<{ path: string, optional?: boolean }>
}
// Add default options
context.files.push({ path: resolve(runtimeDir, 'router.options'), optional: true })
await Promise.all(nuxt.options._layers.map(async layer => {
const path = await findPath(resolve(layer.config.srcDir, 'app/router.options'))
if (path) { context.files.push({ path }) }
}))
await nuxt.callHook('pages:routerOptions', context)
return context.files
}
// Disable module (and use universal router) if pages dir do not exists or user has disabled it // 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 isNonEmptyDir = (dir: string) => existsSync(dir) && readdirSync(dir).length
const userPreference = nuxt.options.pages const userPreference = nuxt.options.pages
@ -38,7 +54,8 @@ export default defineNuxtModule({
if (typeof userPreference === 'boolean') { if (typeof userPreference === 'boolean') {
return userPreference return userPreference
} }
if (nuxt.options._layers.some(layer => existsSync(resolve(layer.config.srcDir, 'app/router.options.ts')))) { const routerOptionsFiles = await resolveRouterOptions()
if (routerOptionsFiles.filter(p => !p.optional).length > 0) {
return true return true
} }
if (pagesDirs.some(dir => isNonEmptyDir(dir))) { if (pagesDirs.some(dir => isNonEmptyDir(dir))) {
@ -176,8 +193,6 @@ export default defineNuxtModule({
}) })
} }
const runtimeDir = resolve(distDir, 'pages/runtime')
// Add $router types // Add $router types
nuxt.hook('prepare:types', ({ references }) => { nuxt.hook('prepare:types', ({ references }) => {
references.push({ types: useExperimentalTypedPages ? 'vue-router/auto' : 'vue-router' }) references.push({ types: useExperimentalTypedPages ? 'vue-router/auto' : 'vue-router' })
@ -392,18 +407,13 @@ export default defineNuxtModule({
filename: 'router.options.mjs', filename: 'router.options.mjs',
getContents: async () => { getContents: async () => {
// Scan and register app/router.options files // Scan and register app/router.options files
const routerOptionsFiles = (await Promise.all(nuxt.options._layers.map( const routerOptionsFiles = await resolveRouterOptions()
async layer => await findPath(resolve(layer.config.srcDir, 'app/router.options'))
))).filter(Boolean) as string[]
// Add default options
routerOptionsFiles.push(resolve(runtimeDir, 'router.options'))
const configRouterOptions = genObjectFromRawEntries(Object.entries(nuxt.options.router.options) const configRouterOptions = genObjectFromRawEntries(Object.entries(nuxt.options.router.options)
.map(([key, value]) => [key, genString(value as string)])) .map(([key, value]) => [key, genString(value as string)]))
return [ return [
...routerOptionsFiles.map((file, index) => genImport(file, `routerOptions${index}`)), ...routerOptionsFiles.map((file, index) => genImport(file.path, `routerOptions${index}`)),
`const configRouterOptions = ${configRouterOptions}`, `const configRouterOptions = ${configRouterOptions}`,
'export default {', 'export default {',
'...configRouterOptions,', '...configRouterOptions,',

View File

@ -170,6 +170,17 @@ export interface NuxtHooks {
*/ */
'pages:extend': (pages: NuxtPage[]) => HookResult 'pages:extend': (pages: NuxtPage[]) => HookResult
/**
* Called when resolving `app/router.options` files. It allows modifying the detected router options files
* and adding new ones.
*
* Adding a router options file will switch on page-based routing, unless `optional` is set, in which case
* it will only apply when page-based routing is already enabled.
* @param context An object with `files` containing an array of router options files.
* @returns Promise
*/
'pages:routerOptions': (context: { files: Array<{ path: string, optional?: boolean }> }) => HookResult
/** /**
* Called when the dev middleware is being registered on the Nitro dev server. * Called when the dev middleware is being registered on the Nitro dev server.
* @param handler the Vite or Webpack event handler * @param handler the Vite or Webpack event handler