mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 21:55:11 +00:00
feat: support server directory (#132)
* feat: support server directory * fix sorting and global * lazy load api * pretty print opts * fix: hide table when no middleware
This commit is contained in:
parent
27aef1489f
commit
85da52d390
@ -1,12 +1,12 @@
|
|||||||
import { resolve, join } from 'upath'
|
import { resolve, join } from 'upath'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import { rollup, watch as rollupWatch } from 'rollup'
|
import { rollup, watch as rollupWatch } from 'rollup'
|
||||||
import ora from 'ora'
|
|
||||||
import { readFile, emptyDir, copy } from 'fs-extra'
|
import { readFile, emptyDir, copy } from 'fs-extra'
|
||||||
import { printFSTree } from './utils/tree'
|
import { printFSTree } from './utils/tree'
|
||||||
import { getRollupConfig } from './rollup/config'
|
import { getRollupConfig } from './rollup/config'
|
||||||
import { hl, prettyPath, serializeTemplate, writeFile, isDirectory } from './utils'
|
import { hl, prettyPath, serializeTemplate, writeFile, isDirectory } from './utils'
|
||||||
import { NitroContext } from './context'
|
import { NitroContext } from './context'
|
||||||
|
import { scanMiddleware } from './server/middleware'
|
||||||
|
|
||||||
export async function prepare (nitroContext: NitroContext) {
|
export async function prepare (nitroContext: NitroContext) {
|
||||||
consola.info(`Nitro preset is ${hl(nitroContext.preset)}`)
|
consola.info(`Nitro preset is ${hl(nitroContext.preset)}`)
|
||||||
@ -28,8 +28,7 @@ async function cleanupDir (dir: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function generate (nitroContext: NitroContext) {
|
export async function generate (nitroContext: NitroContext) {
|
||||||
const spinner = ora()
|
consola.start('Generating public...')
|
||||||
spinner.start('Generating public...')
|
|
||||||
|
|
||||||
const clientDist = resolve(nitroContext._nuxt.buildDir, 'dist/client')
|
const clientDist = resolve(nitroContext._nuxt.buildDir, 'dist/client')
|
||||||
if (await isDirectory(clientDist)) {
|
if (await isDirectory(clientDist)) {
|
||||||
@ -41,7 +40,7 @@ export async function generate (nitroContext: NitroContext) {
|
|||||||
await copy(staticDir, nitroContext.output.publicDir)
|
await copy(staticDir, nitroContext.output.publicDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
spinner.succeed('Generated public ' + prettyPath(nitroContext.output.publicDir))
|
consola.success('Generated public ' + prettyPath(nitroContext.output.publicDir))
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function build (nitroContext: NitroContext) {
|
export async function build (nitroContext: NitroContext) {
|
||||||
@ -60,18 +59,18 @@ export async function build (nitroContext: NitroContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function _build (nitroContext: NitroContext) {
|
async function _build (nitroContext: NitroContext) {
|
||||||
const spinner = ora()
|
nitroContext.scannedMiddleware = await scanMiddleware(nitroContext._nuxt.serverDir)
|
||||||
|
|
||||||
spinner.start('Building server...')
|
consola.start('Building server...')
|
||||||
const build = await rollup(nitroContext.rollupConfig).catch((error) => {
|
const build = await rollup(nitroContext.rollupConfig).catch((error) => {
|
||||||
spinner.fail('Rollup error: ' + error.message)
|
consola.error('Rollup error: ' + error.message)
|
||||||
throw error
|
throw error
|
||||||
})
|
})
|
||||||
|
|
||||||
spinner.start('Writing server bundle...')
|
consola.start('Writing server bundle...')
|
||||||
await build.write(nitroContext.rollupConfig.output)
|
await build.write(nitroContext.rollupConfig.output)
|
||||||
|
|
||||||
spinner.succeed('Server built')
|
consola.success('Server built')
|
||||||
await printFSTree(nitroContext.output.serverDir)
|
await printFSTree(nitroContext.output.serverDir)
|
||||||
await nitroContext._internal.hooks.callHook('nitro:compiled', nitroContext)
|
await nitroContext._internal.hooks.callHook('nitro:compiled', nitroContext)
|
||||||
|
|
||||||
@ -80,11 +79,16 @@ async function _build (nitroContext: NitroContext) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _watch (nitroContext: NitroContext) {
|
async function _watch (nitroContext: NitroContext) {
|
||||||
const spinner = ora()
|
|
||||||
|
|
||||||
const watcher = rollupWatch(nitroContext.rollupConfig)
|
const watcher = rollupWatch(nitroContext.rollupConfig)
|
||||||
|
|
||||||
|
nitroContext.scannedMiddleware = await scanMiddleware(nitroContext._nuxt.serverDir,
|
||||||
|
(middleware, event, file) => {
|
||||||
|
nitroContext.scannedMiddleware = middleware
|
||||||
|
watcher.emit(event, file)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
let start
|
let start
|
||||||
|
|
||||||
watcher.on('event', (event) => {
|
watcher.on('event', (event) => {
|
||||||
@ -96,17 +100,17 @@ function _watch (nitroContext: NitroContext) {
|
|||||||
// Building an individual bundle
|
// Building an individual bundle
|
||||||
case 'BUNDLE_START':
|
case 'BUNDLE_START':
|
||||||
start = Date.now()
|
start = Date.now()
|
||||||
spinner.start('Building Nitro...')
|
|
||||||
return
|
return
|
||||||
|
|
||||||
// Finished building all bundles
|
// Finished building all bundles
|
||||||
case 'END':
|
case 'END':
|
||||||
nitroContext._internal.hooks.callHook('nitro:compiled', nitroContext)
|
nitroContext._internal.hooks.callHook('nitro:compiled', nitroContext)
|
||||||
return spinner.succeed(`Nitro built in ${Date.now() - start} ms`)
|
consola.success('Nitro built', start ? `in ${Date.now() - start} ms` : '')
|
||||||
|
return
|
||||||
|
|
||||||
// Encountered an error while bundling
|
// Encountered an error while bundling
|
||||||
case 'ERROR':
|
case 'ERROR':
|
||||||
spinner.fail('Rollup error: ' + event.error)
|
consola.error('Rollup error: ' + event.error)
|
||||||
// consola.error(event.error)
|
// consola.error(event.error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -2,9 +2,9 @@ import fetch from 'node-fetch'
|
|||||||
import { resolve } from 'upath'
|
import { resolve } from 'upath'
|
||||||
import { build, generate, prepare } from './build'
|
import { build, generate, prepare } from './build'
|
||||||
import { getNitroContext, NitroContext } from './context'
|
import { getNitroContext, NitroContext } from './context'
|
||||||
import { createDevServer } from './server'
|
import { createDevServer } from './server/dev'
|
||||||
import { wpfs } from './utils/wpfs'
|
import { wpfs } from './utils/wpfs'
|
||||||
import { resolveMiddleware } from './middleware'
|
import { resolveMiddleware } from './server/middleware'
|
||||||
|
|
||||||
export default function nuxt2CompatModule () {
|
export default function nuxt2CompatModule () {
|
||||||
const { nuxt } = this
|
const { nuxt } = this
|
||||||
|
@ -6,13 +6,7 @@ import type { Preset } from '@nuxt/un'
|
|||||||
import { tryImport, resolvePath, detectTarget, extendPreset } from './utils'
|
import { tryImport, resolvePath, detectTarget, extendPreset } from './utils'
|
||||||
import * as PRESETS from './presets'
|
import * as PRESETS from './presets'
|
||||||
import type { NodeExternalsOptions } from './rollup/plugins/externals'
|
import type { NodeExternalsOptions } from './rollup/plugins/externals'
|
||||||
|
import type { ServerMiddleware } from './server/middleware'
|
||||||
export interface ServerMiddleware {
|
|
||||||
route: string
|
|
||||||
handle: string
|
|
||||||
lazy?: boolean // Default is true
|
|
||||||
promisify?: boolean // Default is true
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NitroContext {
|
export interface NitroContext {
|
||||||
timing: boolean
|
timing: boolean
|
||||||
@ -28,6 +22,7 @@ export interface NitroContext {
|
|||||||
renderer: string
|
renderer: string
|
||||||
serveStatic: boolean
|
serveStatic: boolean
|
||||||
middleware: ServerMiddleware[]
|
middleware: ServerMiddleware[]
|
||||||
|
scannedMiddleware: ServerMiddleware[]
|
||||||
hooks: configHooksT
|
hooks: configHooksT
|
||||||
nuxtHooks: configHooksT
|
nuxtHooks: configHooksT
|
||||||
ignore: string[]
|
ignore: string[]
|
||||||
@ -45,6 +40,7 @@ export interface NitroContext {
|
|||||||
buildDir: string
|
buildDir: string
|
||||||
generateDir: string
|
generateDir: string
|
||||||
staticDir: string
|
staticDir: string
|
||||||
|
serverDir: string
|
||||||
routerBase: string
|
routerBase: string
|
||||||
publicPath: string
|
publicPath: string
|
||||||
isStatic: boolean
|
isStatic: boolean
|
||||||
@ -79,6 +75,7 @@ export function getNitroContext (nuxtOptions: NuxtOptions, input: NitroInput): N
|
|||||||
renderer: undefined,
|
renderer: undefined,
|
||||||
serveStatic: false,
|
serveStatic: false,
|
||||||
middleware: [],
|
middleware: [],
|
||||||
|
scannedMiddleware: [],
|
||||||
ignore: [],
|
ignore: [],
|
||||||
env: {},
|
env: {},
|
||||||
hooks: {},
|
hooks: {},
|
||||||
@ -96,6 +93,7 @@ export function getNitroContext (nuxtOptions: NuxtOptions, input: NitroInput): N
|
|||||||
buildDir: nuxtOptions.buildDir,
|
buildDir: nuxtOptions.buildDir,
|
||||||
generateDir: nuxtOptions.generate.dir,
|
generateDir: nuxtOptions.generate.dir,
|
||||||
staticDir: nuxtOptions.dir.static,
|
staticDir: nuxtOptions.dir.static,
|
||||||
|
serverDir: resolve(nuxtOptions.srcDir, (nuxtOptions.dir as any).server || 'server'),
|
||||||
routerBase: nuxtOptions.router.base,
|
routerBase: nuxtOptions.router.base,
|
||||||
publicPath: nuxtOptions.build.publicPath,
|
publicPath: nuxtOptions.build.publicPath,
|
||||||
isStatic: nuxtOptions.target === 'static' && !nuxtOptions.dev,
|
isStatic: nuxtOptions.target === 'static' && !nuxtOptions.dev,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
export * from './build'
|
export * from './build'
|
||||||
export * from './context'
|
export * from './context'
|
||||||
export * from './middleware'
|
export * from './server/middleware'
|
||||||
export * from './server'
|
export * from './server/dev'
|
||||||
export * from './types'
|
export * from './types'
|
||||||
export { wpfs } from './utils/wpfs'
|
export { wpfs } from './utils/wpfs'
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
export interface Middleware {
|
|
||||||
handle: string
|
|
||||||
route: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resolveMiddleware (serverMiddleware: any[], resolvePath: (string) => string) {
|
|
||||||
const middleware: Middleware[] = []
|
|
||||||
const legacyMiddleware: Middleware[] = []
|
|
||||||
|
|
||||||
for (let m of serverMiddleware) {
|
|
||||||
if (typeof m === 'string') { m = { handler: m } }
|
|
||||||
const route = m.path || m.route || '/'
|
|
||||||
const handle = m.handler || m.handle
|
|
||||||
if (typeof handle !== 'string' || typeof route !== 'string') {
|
|
||||||
legacyMiddleware.push(m)
|
|
||||||
} else {
|
|
||||||
middleware.push({
|
|
||||||
...m,
|
|
||||||
handle: resolvePath(handle),
|
|
||||||
route
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
middleware,
|
|
||||||
legacyMiddleware
|
|
||||||
}
|
|
||||||
}
|
|
@ -148,11 +148,16 @@ export const getRollupConfig = (nitroContext: NitroContext) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Middleware
|
// Middleware
|
||||||
const _middleware = [...nitroContext.middleware]
|
rollupConfig.plugins.push(middleware(() => {
|
||||||
|
const _middleware = [
|
||||||
|
...nitroContext.scannedMiddleware,
|
||||||
|
...nitroContext.middleware
|
||||||
|
]
|
||||||
if (nitroContext.serveStatic) {
|
if (nitroContext.serveStatic) {
|
||||||
_middleware.unshift({ route: '/', handle: '~runtime/server/static' })
|
_middleware.unshift({ route: '/', handle: '~runtime/server/static' })
|
||||||
}
|
}
|
||||||
rollupConfig.plugins.push(middleware(_middleware))
|
return _middleware
|
||||||
|
}))
|
||||||
|
|
||||||
// Polyfill
|
// Polyfill
|
||||||
rollupConfig.plugins.push(virtual({
|
rollupConfig.plugins.push(virtual({
|
||||||
@ -187,7 +192,8 @@ export const getRollupConfig = (nitroContext: NitroContext) => {
|
|||||||
ignore: [
|
ignore: [
|
||||||
nitroContext._internal.runtimeDir,
|
nitroContext._internal.runtimeDir,
|
||||||
...(nitroContext._nuxt.dev ? [] : [nitroContext._nuxt.buildDir]),
|
...(nitroContext._nuxt.dev ? [] : [nitroContext._nuxt.buildDir]),
|
||||||
...nitroContext.middleware.map(m => m.handle)
|
...nitroContext.middleware.map(m => m.handle),
|
||||||
|
nitroContext._nuxt.serverDir
|
||||||
],
|
],
|
||||||
traceOptions: {
|
traceOptions: {
|
||||||
base: nitroContext._nuxt.rootDir
|
base: nitroContext._nuxt.rootDir
|
||||||
|
@ -1,12 +1,26 @@
|
|||||||
import hasha from 'hasha'
|
import hasha from 'hasha'
|
||||||
import virtual from '@rollup/plugin-virtual'
|
import { relative } from 'upath'
|
||||||
import type { ServerMiddleware } from '../../context'
|
import { table, getBorderCharacters } from 'table'
|
||||||
|
import isPrimitive from 'is-primitive'
|
||||||
|
import type { ServerMiddleware } from '../../server/middleware'
|
||||||
|
import virtual from './virtual'
|
||||||
|
|
||||||
export function middleware (middleware: ServerMiddleware[]) {
|
export function middleware (getMiddleware: () => ServerMiddleware[]) {
|
||||||
const getImportId = p => '_' + hasha(p).substr(0, 6)
|
const getImportId = p => '_' + hasha(p).substr(0, 6)
|
||||||
|
|
||||||
|
let lastDump = ''
|
||||||
|
|
||||||
return virtual({
|
return virtual({
|
||||||
'~serverMiddleware': `
|
'~serverMiddleware': () => {
|
||||||
|
const middleware = getMiddleware()
|
||||||
|
const dumped = dumpMiddleware(middleware)
|
||||||
|
if (dumped !== lastDump) {
|
||||||
|
lastDump = dumped
|
||||||
|
if (middleware.length) {
|
||||||
|
console.log('\n\nNitro middleware:\n' + dumped)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return `
|
||||||
${middleware.filter(m => m.lazy === false).map(m => `import ${getImportId(m.handle)} from '${m.handle}';`).join('\n')}
|
${middleware.filter(m => m.lazy === false).map(m => `import ${getImportId(m.handle)} from '${m.handle}';`).join('\n')}
|
||||||
|
|
||||||
${middleware.filter(m => m.lazy !== false).map(m => `const ${getImportId(m.handle)} = () => import('${m.handle}');`).join('\n')}
|
${middleware.filter(m => m.lazy !== false).map(m => `const ${getImportId(m.handle)} = () => import('${m.handle}');`).join('\n')}
|
||||||
@ -17,5 +31,31 @@ const middleware = [
|
|||||||
|
|
||||||
export default middleware
|
export default middleware
|
||||||
`
|
`
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function dumpMiddleware (middleware: ServerMiddleware[]) {
|
||||||
|
const data = middleware.map(({ route, handle, ...props }) => {
|
||||||
|
return [
|
||||||
|
(route && route !== '/') ? route : '[global]',
|
||||||
|
relative(process.cwd(), handle),
|
||||||
|
dumpObject(props)
|
||||||
|
]
|
||||||
|
})
|
||||||
|
return table([
|
||||||
|
['Route', 'Handle', 'Options'],
|
||||||
|
...data
|
||||||
|
], {
|
||||||
|
border: getBorderCharacters('norc')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function dumpObject (obj: any) {
|
||||||
|
const items = []
|
||||||
|
for (const key in obj) {
|
||||||
|
const val = obj[key]
|
||||||
|
items.push(`${key}: ${isPrimitive(val) ? val : JSON.stringify(val)}`)
|
||||||
|
}
|
||||||
|
return items.join(', ')
|
||||||
|
}
|
||||||
|
49
packages/nitro/src/rollup/plugins/virtual.ts
Normal file
49
packages/nitro/src/rollup/plugins/virtual.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// Based on https://github.com/rollup/plugins/blob/master/packages/virtual/src/index.ts
|
||||||
|
import * as path from 'path'
|
||||||
|
|
||||||
|
import { Plugin } from 'rollup'
|
||||||
|
|
||||||
|
type UnresolvedModule = string | (() => string)
|
||||||
|
export interface RollupVirtualOptions {
|
||||||
|
[id: string]: UnresolvedModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PREFIX = '\0virtual:'
|
||||||
|
|
||||||
|
const resolveModule = (m: UnresolvedModule) => typeof m === 'function' ? m() : m
|
||||||
|
|
||||||
|
export default function virtual (modules: RollupVirtualOptions): Plugin {
|
||||||
|
const resolvedIds = new Map<string, string |(() => string)>()
|
||||||
|
|
||||||
|
Object.keys(modules).forEach((id) => {
|
||||||
|
resolvedIds.set(path.resolve(id), modules[id])
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: 'virtual',
|
||||||
|
|
||||||
|
resolveId (id, importer) {
|
||||||
|
if (id in modules) { return PREFIX + id }
|
||||||
|
|
||||||
|
if (importer) {
|
||||||
|
const importerNoPrefix = importer.startsWith(PREFIX)
|
||||||
|
? importer.slice(PREFIX.length)
|
||||||
|
: importer
|
||||||
|
const resolved = path.resolve(path.dirname(importerNoPrefix), id)
|
||||||
|
if (resolvedIds.has(resolved)) { return PREFIX + resolved }
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
|
||||||
|
load (id) {
|
||||||
|
if (!id.startsWith(PREFIX)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const idNoPrefix = id.slice(PREFIX.length)
|
||||||
|
return idNoPrefix in modules
|
||||||
|
? resolveModule(modules[idNoPrefix])
|
||||||
|
: resolveModule(resolvedIds.get(idNoPrefix))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,7 @@ import serveStatic from 'serve-static'
|
|||||||
import servePlaceholder from 'serve-placeholder'
|
import servePlaceholder from 'serve-placeholder'
|
||||||
import { createProxy } from 'http-proxy'
|
import { createProxy } from 'http-proxy'
|
||||||
import { stat } from 'fs-extra'
|
import { stat } from 'fs-extra'
|
||||||
import type { NitroContext } from './context'
|
import type { NitroContext } from '../context'
|
||||||
|
|
||||||
export function createDevServer (nitroContext: NitroContext) {
|
export function createDevServer (nitroContext: NitroContext) {
|
||||||
// Worker
|
// Worker
|
76
packages/nitro/src/server/middleware.ts
Normal file
76
packages/nitro/src/server/middleware.ts
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import { resolve, join, extname } from 'upath'
|
||||||
|
import { joinURL } from 'ufo'
|
||||||
|
import globby from 'globby'
|
||||||
|
import { watch } from 'chokidar'
|
||||||
|
|
||||||
|
export interface ServerMiddleware {
|
||||||
|
route: string
|
||||||
|
handle: string
|
||||||
|
lazy?: boolean // Default is true
|
||||||
|
promisify?: boolean // Default is true
|
||||||
|
}
|
||||||
|
|
||||||
|
function filesToMiddleware (files: string[], baseDir: string, basePath: string, overrides?: Partial<ServerMiddleware>): ServerMiddleware[] {
|
||||||
|
return files.map((file) => {
|
||||||
|
const route = joinURL(basePath, file.substr(0, file.length - extname(file).length))
|
||||||
|
const handle = resolve(baseDir, file)
|
||||||
|
return {
|
||||||
|
route,
|
||||||
|
handle
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.sort((a, b) => a.route.localeCompare(b.route))
|
||||||
|
.map(m => ({ ...m, ...overrides }))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function scanMiddleware (serverDir: string, onChange?: Function): Promise<ServerMiddleware[]> {
|
||||||
|
const pattern = '**/*.{js,ts}'
|
||||||
|
const globalDir = resolve(serverDir, 'middleware')
|
||||||
|
const apiDir = resolve(serverDir, 'api')
|
||||||
|
|
||||||
|
const scan = async () => {
|
||||||
|
const globalFiles = await globby(pattern, { cwd: globalDir })
|
||||||
|
const apiFiles = await globby(pattern, { cwd: apiDir })
|
||||||
|
return [
|
||||||
|
...filesToMiddleware(globalFiles, globalDir, '/', { route: '/' }),
|
||||||
|
...filesToMiddleware(apiFiles, apiDir, '/api', { lazy: true })
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof onChange === 'function') {
|
||||||
|
const watcher = watch([
|
||||||
|
join(globalDir, pattern),
|
||||||
|
join(apiDir, pattern)
|
||||||
|
], { ignoreInitial: true })
|
||||||
|
watcher.on('all', async (event, file) => {
|
||||||
|
onChange(await scan(), event, file)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return scan()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveMiddleware (serverMiddleware: any[], resolvePath: (string) => string) {
|
||||||
|
const middleware: ServerMiddleware[] = []
|
||||||
|
const legacyMiddleware: ServerMiddleware[] = []
|
||||||
|
|
||||||
|
for (let m of serverMiddleware) {
|
||||||
|
if (typeof m === 'string') { m = { handler: m } }
|
||||||
|
const route = m.path || m.route || '/'
|
||||||
|
const handle = m.handler || m.handle
|
||||||
|
if (typeof handle !== 'string' || typeof route !== 'string') {
|
||||||
|
legacyMiddleware.push(m)
|
||||||
|
} else {
|
||||||
|
middleware.push({
|
||||||
|
...m,
|
||||||
|
handle: resolvePath(handle),
|
||||||
|
route
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
middleware,
|
||||||
|
legacyMiddleware
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user