mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 13:45:18 +00:00
feat(nuxt): auto-register modules in ~/modules
(#19394)
This commit is contained in:
parent
a420369c90
commit
3681bddfd5
48
docs/2.guide/2.directory-structure/1.modules.md
Normal file
48
docs/2.guide/2.directory-structure/1.modules.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
navigation.icon: IconDirectory
|
||||||
|
title: 'modules'
|
||||||
|
head.title: 'modules/'
|
||||||
|
description: Use the modules/ directory to automatically register local modules within your application.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Modules Directory
|
||||||
|
|
||||||
|
Nuxt scans the `modules/` directory and loads them before starting. It is a good place to place any local modules you develop while building your application.
|
||||||
|
|
||||||
|
The auto-registered files patterns are:
|
||||||
|
- `modules/*/index.ts`
|
||||||
|
- `modules/*.ts`
|
||||||
|
|
||||||
|
You don't need to add those local modules to your [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt.config) separately.
|
||||||
|
|
||||||
|
::code-group
|
||||||
|
```ts [modules/hello/index.ts]
|
||||||
|
// `nuxt/kit` is a helper subpath import you can use when defining local modules
|
||||||
|
// that means you do not need to add `@nuxt/kit` to your project's dependencies
|
||||||
|
import { createResolver, defineNuxtModule, addServerHandler } from 'nuxt/kit'
|
||||||
|
|
||||||
|
export default defineNuxtModule({
|
||||||
|
meta: {
|
||||||
|
name: 'hello'
|
||||||
|
},
|
||||||
|
setup () {
|
||||||
|
const { resolve } = createResolver(import.meta.url)
|
||||||
|
|
||||||
|
// Add an API route
|
||||||
|
addServerHandler({
|
||||||
|
route: '/api/hello',
|
||||||
|
handler: resolve('./runtime/api-route')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
```ts [modules/hello/runtime/api-route.ts]
|
||||||
|
export default defineEventHandler(() => {
|
||||||
|
return { hello: 'world' }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
::
|
||||||
|
|
||||||
|
When starting Nuxt, the `hello` module will be registered and the `/api/hello` route will be available.
|
||||||
|
|
||||||
|
:ReadMore{link="/docs/guide/going-further/modules"}
|
@ -1,7 +1,7 @@
|
|||||||
import { join, normalize, resolve } from 'pathe'
|
import { join, normalize, relative, resolve } from 'pathe'
|
||||||
import { createHooks, createDebugger } from 'hookable'
|
import { createHooks, createDebugger } from 'hookable'
|
||||||
import type { LoadNuxtOptions } from '@nuxt/kit'
|
import type { LoadNuxtOptions } from '@nuxt/kit'
|
||||||
import { loadNuxtConfig, nuxtCtx, installModule, addComponent, addVitePlugin, addWebpackPlugin, tryResolveModule, addPlugin } from '@nuxt/kit'
|
import { resolvePath, resolveAlias, resolveFiles, loadNuxtConfig, nuxtCtx, installModule, addComponent, addVitePlugin, addWebpackPlugin, tryResolveModule, addPlugin } from '@nuxt/kit'
|
||||||
|
|
||||||
import escapeRE from 'escape-string-regexp'
|
import escapeRE from 'escape-string-regexp'
|
||||||
import fse from 'fs-extra'
|
import fse from 'fs-extra'
|
||||||
@ -122,10 +122,38 @@ async function initNuxt (nuxt: Nuxt) {
|
|||||||
|
|
||||||
// Init user modules
|
// Init user modules
|
||||||
await nuxt.callHook('modules:before')
|
await nuxt.callHook('modules:before')
|
||||||
const modulesToInstall = [
|
const modulesToInstall = []
|
||||||
...nuxt.options.modules,
|
|
||||||
...nuxt.options._modules
|
const watchedPaths = new Set<string>()
|
||||||
]
|
const specifiedModules = new Set<string>()
|
||||||
|
|
||||||
|
for (const _mod of nuxt.options.modules) {
|
||||||
|
const mod = Array.isArray(_mod) ? _mod[0] : _mod
|
||||||
|
if (typeof mod !== 'string') { continue }
|
||||||
|
const modPath = await resolvePath(resolveAlias(mod))
|
||||||
|
specifiedModules.add(modPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Automatically register user modules
|
||||||
|
for (const config of nuxt.options._layers.map(layer => layer.config).reverse()) {
|
||||||
|
const layerModules = await resolveFiles(config.srcDir, [
|
||||||
|
`${config.dir?.modules || 'modules'}/*{${nuxt.options.extensions.join(',')}}`,
|
||||||
|
`${config.dir?.modules || 'modules'}/*/index{${nuxt.options.extensions.join(',')}}`
|
||||||
|
])
|
||||||
|
for (const mod of layerModules) {
|
||||||
|
watchedPaths.add(relative(config.srcDir, mod))
|
||||||
|
if (specifiedModules.has(mod)) { continue }
|
||||||
|
specifiedModules.add(mod)
|
||||||
|
modulesToInstall.push(mod)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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>
|
// Add <NuxtWelcome>
|
||||||
addComponent({
|
addComponent({
|
||||||
|
@ -219,6 +219,11 @@ export default defineUntypedSchema({
|
|||||||
*/
|
*/
|
||||||
middleware: 'middleware',
|
middleware: 'middleware',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The modules directory, each file in which will be auto-registered as a Nuxt module.
|
||||||
|
*/
|
||||||
|
modules: 'modules',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The directory which will be processed to auto-generate your application page routes.
|
* The directory which will be processed to auto-generate your application page routes.
|
||||||
*/
|
*/
|
||||||
|
@ -46,6 +46,13 @@ describe('route rules', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('modules', () => {
|
||||||
|
it('should auto-register modules in ~/modules', async () => {
|
||||||
|
const result = await $fetch('/auto-registered-module')
|
||||||
|
expect(result).toEqual('handler added by auto-registered module')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('pages', () => {
|
describe('pages', () => {
|
||||||
it('render index', async () => {
|
it('render index', async () => {
|
||||||
const html = await $fetch('/')
|
const html = await $fetch('/')
|
||||||
|
15
test/fixtures/basic/modules/auto-registered/index.ts
vendored
Normal file
15
test/fixtures/basic/modules/auto-registered/index.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { createResolver, defineNuxtModule, addServerHandler } from 'nuxt/kit'
|
||||||
|
|
||||||
|
export default defineNuxtModule({
|
||||||
|
meta: {
|
||||||
|
name: 'auto-registered-module'
|
||||||
|
},
|
||||||
|
setup () {
|
||||||
|
const resolver = createResolver(import.meta.url)
|
||||||
|
|
||||||
|
addServerHandler({
|
||||||
|
handler: resolver.resolve('./runtime/handler'),
|
||||||
|
route: '/auto-registered-module'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
1
test/fixtures/basic/modules/auto-registered/runtime/handler.ts
vendored
Normal file
1
test/fixtures/basic/modules/auto-registered/runtime/handler.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
export default defineEventHandler(() => 'handler added by auto-registered module')
|
9
test/fixtures/basic/modules/example.ts
vendored
9
test/fixtures/basic/modules/example.ts
vendored
@ -1,5 +1,4 @@
|
|||||||
import { fileURLToPath } from 'node:url'
|
import { defineNuxtModule, createResolver, addPlugin, useNuxt } from 'nuxt/kit'
|
||||||
import { defineNuxtModule, addPlugin, useNuxt } from '@nuxt/kit'
|
|
||||||
|
|
||||||
export default defineNuxtModule({
|
export default defineNuxtModule({
|
||||||
defaults: {
|
defaults: {
|
||||||
@ -11,11 +10,13 @@ export default defineNuxtModule({
|
|||||||
configKey: 'sampleModule'
|
configKey: 'sampleModule'
|
||||||
},
|
},
|
||||||
setup () {
|
setup () {
|
||||||
addPlugin(fileURLToPath(new URL('./runtime/plugin', import.meta.url)))
|
const resolver = createResolver(import.meta.url)
|
||||||
|
|
||||||
|
addPlugin(resolver.resolve('./runtime/plugin'))
|
||||||
useNuxt().hook('app:resolve', (app) => {
|
useNuxt().hook('app:resolve', (app) => {
|
||||||
app.middleware.push({
|
app.middleware.push({
|
||||||
name: 'unctx-test',
|
name: 'unctx-test',
|
||||||
path: fileURLToPath(new URL('./runtime/middleware', import.meta.url)),
|
path: resolver.resolve('./runtime/middleware'),
|
||||||
global: true
|
global: true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user