mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 13:45:18 +00:00
feat(nuxt3): middleware type generation improvements (#2945)
This commit is contained in:
parent
6e06d2b4c9
commit
965f2abaee
@ -33,6 +33,7 @@
|
||||
"cookie-es": "^0.5.0",
|
||||
"defu": "^5.0.1",
|
||||
"destr": "^1.1.0",
|
||||
"escape-string-regexp": "^5.0.0",
|
||||
"globby": "^13.1.0",
|
||||
"h3": "^0.3.9",
|
||||
"hash-sum": "^2.0.0",
|
||||
|
@ -1,4 +1,5 @@
|
||||
import type { AutoImport } from '@nuxt/schema'
|
||||
import escapeRE from 'escape-string-regexp'
|
||||
|
||||
export interface AutoImportContext {
|
||||
autoImports: AutoImport[]
|
||||
@ -36,7 +37,7 @@ export function updateAutoImportContext (ctx: AutoImportContext) {
|
||||
ctx.autoImports = ctx.autoImports.filter(i => i.disabled !== true)
|
||||
|
||||
// Create regex
|
||||
ctx.matchRE = new RegExp(`\\b(${ctx.autoImports.map(i => i.as).join('|')})\\b`, 'g')
|
||||
ctx.matchRE = new RegExp(`\\b(${ctx.autoImports.map(i => escapeRE(i.as)).join('|')})\\b`, 'g')
|
||||
|
||||
// Create map
|
||||
ctx.map.clear()
|
||||
|
@ -3,6 +3,7 @@ import { createUnplugin } from 'unplugin'
|
||||
import consola from 'consola'
|
||||
import { isAbsolute, relative, resolve } from 'pathe'
|
||||
import type { Nuxt } from '@nuxt/schema'
|
||||
import escapeRE from 'escape-string-regexp'
|
||||
|
||||
const _require = createRequire(import.meta.url)
|
||||
|
||||
@ -11,8 +12,6 @@ interface ImportProtectionOptions {
|
||||
patterns: [importPattern: string | RegExp, warning?: string][]
|
||||
}
|
||||
|
||||
const escapeRE = (str: string) => str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
|
||||
|
||||
export const vueAppPatterns = (nuxt: Nuxt) => [
|
||||
[/^(nuxt3|nuxt)/, '`nuxt3`/`nuxt` cannot be imported directly. Instead, import runtime Nuxt composables from `#app` or `#imports`.'],
|
||||
[/nuxt\.config/, 'Importing directly from a `nuxt.config` file is not allowed. Instead, use runtime config or a module.'],
|
||||
|
@ -2,6 +2,7 @@ import { templateUtils } from '@nuxt/kit'
|
||||
import type { Nuxt, NuxtApp } from '@nuxt/schema'
|
||||
|
||||
import { relative } from 'pathe'
|
||||
import escapeRE from 'escape-string-regexp'
|
||||
|
||||
type TemplateContext = {
|
||||
nuxt: Nuxt;
|
||||
@ -94,7 +95,7 @@ export const pluginsDeclaration = {
|
||||
filename: 'plugins.d.ts',
|
||||
write: true,
|
||||
getContents: (ctx: TemplateContext) => {
|
||||
const EXTENSION_RE = new RegExp(`(?<=\\w)(${ctx.nuxt.options.extensions.map(e => `\\${e}`).join('|')})$`, 'g')
|
||||
const EXTENSION_RE = new RegExp(`(?<=\\w)(${ctx.nuxt.options.extensions.map(e => `\\${escapeRE(e)}`).join('|')})$`, 'g')
|
||||
const tsImports = ctx.app.plugins.map(p => relative(ctx.nuxt.options.buildDir, p.src).replace(EXTENSION_RE, ''))
|
||||
|
||||
return `// Generated by Nuxt3'
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { existsSync } from 'fs'
|
||||
import { defineNuxtModule, addTemplate, addPlugin, templateUtils, addVitePlugin, addWebpackPlugin } from '@nuxt/kit'
|
||||
import { resolve } from 'pathe'
|
||||
import escapeRE from 'escape-string-regexp'
|
||||
import { distDir } from '../dirs'
|
||||
import { resolveLayouts, resolvePagesRoutes, normalizeRoutes, resolveMiddleware, getImportName } from './utils'
|
||||
import { TransformMacroPlugin, TransformMacroPluginOptions } from './macros'
|
||||
@ -25,7 +26,13 @@ export default defineNuxtModule({
|
||||
|
||||
// Regenerate templates when adding or removing pages
|
||||
nuxt.hook('builder:watch', async (event, path) => {
|
||||
const pathPattern = new RegExp(`^(${nuxt.options.dir.pages}|${nuxt.options.dir.layouts})/`)
|
||||
const dirs = [
|
||||
nuxt.options.dir.pages,
|
||||
nuxt.options.dir.layouts,
|
||||
nuxt.options.dir.middleware
|
||||
].filter(Boolean)
|
||||
|
||||
const pathPattern = new RegExp(`^(${dirs.map(escapeRE).join('|')})/`)
|
||||
if (event !== 'change' && path.match(pathPattern)) {
|
||||
await nuxt.callHook('builder:generateApp')
|
||||
}
|
||||
@ -83,13 +90,13 @@ export default defineNuxtModule({
|
||||
filename: 'middleware.mjs',
|
||||
async getContents () {
|
||||
const middleware = await resolveMiddleware()
|
||||
await nuxt.callHook('pages:middleware:extend', middleware)
|
||||
const middlewareObject = Object.fromEntries(middleware.map(mw => [mw.name, `{() => import('${mw.path}')}`]))
|
||||
const globalMiddleware = middleware.filter(mw => mw.global)
|
||||
const namedMiddleware = middleware.filter(mw => !mw.global)
|
||||
const namedMiddlewareObject = Object.fromEntries(namedMiddleware.map(mw => [mw.name, `{() => import('${mw.path}')}`]))
|
||||
return [
|
||||
...globalMiddleware.map(mw => `import ${getImportName(mw.name)} from '${mw.path}'`),
|
||||
`export const globalMiddleware = [${globalMiddleware.map(mw => getImportName(mw.name)).join(', ')}]`,
|
||||
`export const namedMiddleware = ${templateUtils.serialize(middlewareObject)}`
|
||||
`export const namedMiddleware = ${templateUtils.serialize(namedMiddlewareObject)}`
|
||||
].join('\n')
|
||||
}
|
||||
})
|
||||
@ -100,9 +107,10 @@ export default defineNuxtModule({
|
||||
getContents: async () => {
|
||||
const composablesFile = resolve(runtimeDir, 'composables')
|
||||
const middleware = await resolveMiddleware()
|
||||
const namedMiddleware = middleware.filter(mw => !mw.global)
|
||||
return [
|
||||
'import type { NavigationGuard } from \'vue-router\'',
|
||||
`export type MiddlewareKey = ${middleware.map(mw => `"${mw.name}"`).join(' | ') || 'string'}`,
|
||||
`export type MiddlewareKey = ${namedMiddleware.map(mw => `"${mw.name}"`).join(' | ') || 'string'}`,
|
||||
`declare module '${composablesFile}' {`,
|
||||
' interface PageMeta {',
|
||||
' middleware?: MiddlewareKey | NavigationGuard | Array<MiddlewareKey | NavigationGuard>',
|
||||
@ -130,11 +138,6 @@ export default defineNuxtModule({
|
||||
}
|
||||
})
|
||||
|
||||
nuxt.hook('prepare:types', ({ references }) => {
|
||||
references.push({ path: resolve(nuxt.options.buildDir, 'middleware.d.ts') })
|
||||
references.push({ path: resolve(nuxt.options.buildDir, 'layouts.d.ts') })
|
||||
})
|
||||
|
||||
// Add layouts template
|
||||
addTemplate({
|
||||
filename: 'layouts.mjs',
|
||||
@ -149,5 +152,11 @@ export default defineNuxtModule({
|
||||
].join('\n')
|
||||
}
|
||||
})
|
||||
|
||||
// Add declarations for middleware and layout keys
|
||||
nuxt.hook('prepare:types', ({ references }) => {
|
||||
references.push({ path: resolve(nuxt.options.buildDir, 'middleware.d.ts') })
|
||||
references.push({ path: resolve(nuxt.options.buildDir, 'layouts.d.ts') })
|
||||
})
|
||||
}
|
||||
})
|
||||
|
@ -3,6 +3,7 @@ import { encodePath } from 'ufo'
|
||||
import type { Nuxt, NuxtMiddleware, NuxtPage } from '@nuxt/schema'
|
||||
import { resolveFiles, useNuxt } from '@nuxt/kit'
|
||||
import { kebabCase, pascalCase } from 'scule'
|
||||
import escapeRE from 'escape-string-regexp'
|
||||
|
||||
enum SegmentParserState {
|
||||
initial,
|
||||
@ -37,7 +38,7 @@ export function generateRoutesFromFiles (files: string[], pagesDir: string): Nux
|
||||
|
||||
for (const file of files) {
|
||||
const segments = relative(pagesDir, file)
|
||||
.replace(new RegExp(`${extname(file)}$`), '')
|
||||
.replace(new RegExp(`${escapeRE(extname(file))}$`), '')
|
||||
.split('/')
|
||||
|
||||
const route: NuxtPage = {
|
||||
@ -219,7 +220,9 @@ export async function resolveLayouts (nuxt: Nuxt) {
|
||||
const layoutDir = resolve(nuxt.options.srcDir, nuxt.options.dir.layouts)
|
||||
const files = await resolveFiles(layoutDir, `*{${nuxt.options.extensions.join(',')}}`)
|
||||
|
||||
return files.map(file => ({ name: getNameFromPath(file), file }))
|
||||
const layouts = files.map(file => ({ name: getNameFromPath(file), file }))
|
||||
await nuxt.callHook('pages:layouts:extend', layouts)
|
||||
return layouts
|
||||
}
|
||||
|
||||
export function normalizeRoutes (routes: NuxtPage[], metaImports: Set<string> = new Set()): { imports: Set<string>, routes: NuxtPage[]} {
|
||||
@ -243,7 +246,9 @@ export async function resolveMiddleware (): Promise<NuxtMiddleware[]> {
|
||||
const nuxt = useNuxt()
|
||||
const middlewareDir = resolve(nuxt.options.srcDir, nuxt.options.dir.middleware)
|
||||
const files = await resolveFiles(middlewareDir, `*{${nuxt.options.extensions.join(',')}}`)
|
||||
return files.map(path => ({ name: getNameFromPath(path), path, global: hasSuffix(path, '.global') }))
|
||||
const middleware = files.map(path => ({ name: getNameFromPath(path), path, global: hasSuffix(path, '.global') }))
|
||||
await nuxt.callHook('pages:middleware:extend', middleware)
|
||||
return middleware
|
||||
}
|
||||
|
||||
function getNameFromPath (path: string) {
|
||||
|
@ -433,6 +433,7 @@ export default {
|
||||
layouts: 'layouts',
|
||||
/**
|
||||
* The middleware directory, each file of which will be auto-registered as a Nuxt middleware.
|
||||
* @version 3
|
||||
* @version 2
|
||||
*/
|
||||
middleware: 'middleware',
|
||||
|
@ -47,6 +47,11 @@ export type NuxtMiddleware = {
|
||||
global?: boolean
|
||||
}
|
||||
|
||||
export type NuxtLayout = {
|
||||
name: string
|
||||
file: string
|
||||
}
|
||||
|
||||
export interface NuxtHooks {
|
||||
// Kit
|
||||
'kit:compatibility': (compatibility: NuxtCompatibility, issues: NuxtCompatibilityIssues) => HookResult
|
||||
@ -58,6 +63,7 @@ export interface NuxtHooks {
|
||||
'builder:generateApp': () => HookResult
|
||||
'pages:extend': (pages: NuxtPage[]) => HookResult
|
||||
'pages:middleware:extend': (middleware: NuxtMiddleware[]) => HookResult
|
||||
'pages:layouts:extend': (layouts: NuxtLayout[]) => HookResult
|
||||
|
||||
// Auto imports
|
||||
'autoImports:sources': (autoImportSources: AutoImportSource[]) => HookResult
|
||||
|
@ -26,6 +26,7 @@
|
||||
"consola": "^2.15.3",
|
||||
"defu": "^5.0.1",
|
||||
"esbuild": "^0.14.14",
|
||||
"escape-string-regexp": "^5.0.0",
|
||||
"externality": "^0.1.6",
|
||||
"fs-extra": "^10.0.0",
|
||||
"magic-string": "^0.25.7",
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { createUnplugin } from 'unplugin'
|
||||
import escapeRE from 'escape-string-regexp'
|
||||
import type { Plugin } from 'vite'
|
||||
|
||||
interface DynamicBasePluginOptions {
|
||||
@ -7,8 +8,6 @@ interface DynamicBasePluginOptions {
|
||||
globalPublicPath?: string
|
||||
}
|
||||
|
||||
const escapeRE = (str: string) => str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
|
||||
|
||||
export const RelativeAssetPlugin = function (): Plugin {
|
||||
return {
|
||||
name: 'nuxt:vite-relative-asset',
|
||||
|
@ -27,6 +27,7 @@
|
||||
"css-minimizer-webpack-plugin": "^3.4.1",
|
||||
"cssnano": "^5.0.16",
|
||||
"esbuild-loader": "^2.18.0",
|
||||
"escape-string-regexp": "^5.0.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"glob": "^7.2.0",
|
||||
|
@ -4,7 +4,7 @@ import WebpackBar from 'webpackbar'
|
||||
import consola from 'consola'
|
||||
import webpack from 'webpack'
|
||||
import FriendlyErrorsWebpackPlugin from '@nuxt/friendly-errors-webpack-plugin'
|
||||
import { escapeRegExp } from 'lodash-es'
|
||||
import escapeRegExp from 'escape-string-regexp'
|
||||
import { joinURL } from 'ufo'
|
||||
import WarningIgnorePlugin from '../plugins/warning-ignore'
|
||||
import { WebpackConfigContext, applyPresets, fileName } from '../utils/config'
|
||||
|
10
yarn.lock
10
yarn.lock
@ -3182,6 +3182,7 @@ __metadata:
|
||||
consola: ^2.15.3
|
||||
defu: ^5.0.1
|
||||
esbuild: ^0.14.14
|
||||
escape-string-regexp: ^5.0.0
|
||||
externality: ^0.1.6
|
||||
fs-extra: ^10.0.0
|
||||
magic-string: ^0.25.7
|
||||
@ -3298,6 +3299,7 @@ __metadata:
|
||||
css-minimizer-webpack-plugin: ^3.4.1
|
||||
cssnano: ^5.0.16
|
||||
esbuild-loader: ^2.18.0
|
||||
escape-string-regexp: ^5.0.0
|
||||
file-loader: ^6.2.0
|
||||
fs-extra: ^10.0.0
|
||||
glob: ^7.2.0
|
||||
@ -9556,6 +9558,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"escape-string-regexp@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "escape-string-regexp@npm:5.0.0"
|
||||
checksum: 20daabe197f3cb198ec28546deebcf24b3dbb1a5a269184381b3116d12f0532e06007f4bc8da25669d6a7f8efb68db0758df4cd981f57bc5b57f521a3e12c59e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-config-standard@npm:^16.0.3":
|
||||
version: 16.0.3
|
||||
resolution: "eslint-config-standard@npm:16.0.3"
|
||||
@ -14841,6 +14850,7 @@ __metadata:
|
||||
cookie-es: ^0.5.0
|
||||
defu: ^5.0.1
|
||||
destr: ^1.1.0
|
||||
escape-string-regexp: ^5.0.0
|
||||
globby: ^13.1.0
|
||||
h3: ^0.3.9
|
||||
hash-sum: ^2.0.0
|
||||
|
Loading…
Reference in New Issue
Block a user