From f1afae99cd7bce5d859ff2a90043ecc79477543e Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Wed, 12 Apr 2023 15:55:23 +0200 Subject: [PATCH 01/52] feat: add experimental typedPages option --- packages/nuxt/src/core/nuxt.ts | 7 +- packages/nuxt/src/pages/module-typed.ts | 290 +++++++++++++++++++++ packages/schema/src/config/experimental.ts | 3 + 3 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 packages/nuxt/src/pages/module-typed.ts diff --git a/packages/nuxt/src/core/nuxt.ts b/packages/nuxt/src/core/nuxt.ts index 638fd6a29ba2..1f4978b7a744 100644 --- a/packages/nuxt/src/core/nuxt.ts +++ b/packages/nuxt/src/core/nuxt.ts @@ -9,6 +9,7 @@ import fse from 'fs-extra' import { withoutLeadingSlash } from 'ufo' /* eslint-disable import/no-restricted-paths */ import pagesModule from '../pages/module' +import typedPagesModule from '../pages/module-typed' import metaModule from '../head/module' import componentsModule from '../components/module' import importsModule from '../imports/module' @@ -358,7 +359,11 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise { // Temporary until finding better placement for each options.appDir = options.alias['#app'] = resolve(distDir, 'app') options._majorVersion = 3 - options._modules.push(pagesModule, metaModule, componentsModule) + options._modules.push( + options.experimental.typedPages ? typedPagesModule : pagesModule, + metaModule, + componentsModule + ); options._modules.push([importsModule, { transform: { include: options._layers diff --git a/packages/nuxt/src/pages/module-typed.ts b/packages/nuxt/src/pages/module-typed.ts new file mode 100644 index 000000000000..8997954d9a03 --- /dev/null +++ b/packages/nuxt/src/pages/module-typed.ts @@ -0,0 +1,290 @@ +import { existsSync, readdirSync } from 'node:fs' +import { addComponent, addPlugin, addTemplate, addVitePlugin, addWebpackPlugin, defineNuxtModule, findPath, updateTemplates } from '@nuxt/kit' +import { join, relative, resolve } from 'pathe' +import { genImport, genObjectFromRawEntries, genString } from 'knitwork' +import escapeRE from 'escape-string-regexp' +import { joinURL } from 'ufo' +import type { NuxtApp, NuxtPage } from 'nuxt/schema' + +import { distDir } from '../dirs' +import { normalizeRoutes, resolvePagesRoutes } from './utils' +import type { PageMetaPluginOptions } from './page-meta' +import { PageMetaPlugin } from './page-meta' + +export default defineNuxtModule({ + meta: { + name: 'pages' + }, + setup (_options, nuxt) { + const pagesDirs = nuxt.options._layers.map( + layer => resolve(layer.config.srcDir, layer.config.dir?.pages || 'pages') + ) + + // 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 userPreference = nuxt.options.pages + const isPagesEnabled = () => { + if (typeof userPreference === 'boolean') { + return userPreference + } + if (nuxt.options._layers.some(layer => existsSync(resolve(layer.config.srcDir, 'app/router.options.ts')))) { + return true + } + if (pagesDirs.some(dir => isNonEmptyDir(dir))) { + return true + } + return false + } + nuxt.options.pages = isPagesEnabled() + + // Restart Nuxt when pages dir is added or removed + const restartPaths = nuxt.options._layers.flatMap(layer => [ + join(layer.config.srcDir, 'app/router.options.ts'), + join(layer.config.srcDir, layer.config.dir?.pages || 'pages') + ]) + nuxt.hooks.hook('builder:watch', (event, path) => { + const fullPath = join(nuxt.options.srcDir, path) + if (restartPaths.some(path => path === fullPath || fullPath.startsWith(path + '/'))) { + const newSetting = isPagesEnabled() + if (nuxt.options.pages !== newSetting) { + console.info('Pages', newSetting ? 'enabled' : 'disabled') + return nuxt.callHook('restart') + } + } + }) + + if (!nuxt.options.pages) { + addPlugin(resolve(distDir, 'app/plugins/router')) + addTemplate({ + filename: 'pages.mjs', + getContents: () => 'export { useRoute } from \'#app\'' + }) + addComponent({ + name: 'NuxtPage', + priority: 10, // built-in that we do not expect the user to override + filePath: resolve(distDir, 'pages/runtime/page-placeholder') + }) + return + } + + const runtimeDir = resolve(distDir, 'pages/runtime') + + // Add $router types + nuxt.hook('prepare:types', ({ references }) => { + references.push({ types: 'vue-router' }) + }) + + // Add vue-router route guard imports + nuxt.hook('imports:sources', (sources) => { + const routerImports = sources.find(s => s.from === '#app' && s.imports.includes('onBeforeRouteLeave')) + if (routerImports) { + routerImports.from = 'vue-router' + } + }) + + // Regenerate templates when adding or removing pages + nuxt.hook('builder:watch', async (event, path) => { + 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 updateTemplates({ + filter: template => template.filename === 'routes.mjs' + }) + } + }) + + nuxt.hook('app:resolve', (app) => { + // Add default layout for pages + if (app.mainComponent!.includes('@nuxt/ui-templates')) { + app.mainComponent = resolve(runtimeDir, 'app.vue') + } + app.middleware.unshift({ + name: 'validate', + path: resolve(runtimeDir, 'validate'), + global: true + }) + }) + + // Prerender all non-dynamic page routes when generating app + if (!nuxt.options.dev && nuxt.options._generate) { + const prerenderRoutes = new Set() + nuxt.hook('modules:done', () => { + nuxt.hook('pages:extend', (pages) => { + prerenderRoutes.clear() + const processPages = (pages: NuxtPage[], currentPath = '/') => { + for (const page of pages) { + // Add root of optional dynamic paths and catchalls + if (page.path.match(/^\/?:.*(\?|\(\.\*\)\*)$/) && !page.children?.length) { prerenderRoutes.add(currentPath) } + // Skip dynamic paths + if (page.path.includes(':')) { continue } + const route = joinURL(currentPath, page.path) + prerenderRoutes.add(route) + if (page.children) { processPages(page.children, route) } + } + } + processPages(pages) + }) + }) + nuxt.hook('nitro:build:before', (nitro) => { + for (const route of nitro.options.prerender.routes || []) { + // Skip default route value as we only generate it if it is already + // in the detected routes from `~/pages`. + if (route === '/') { continue } + prerenderRoutes.add(route) + } + nitro.options.prerender.routes = Array.from(prerenderRoutes) + }) + } + + nuxt.hook('imports:extend', (imports) => { + imports.push( + { name: 'definePageMeta', as: 'definePageMeta', from: resolve(runtimeDir, 'composables') }, + { name: 'useLink', as: 'useLink', from: 'vue-router' } + ) + }) + + // Extract macros from pages + const pageMetaOptions: PageMetaPluginOptions = { + dev: nuxt.options.dev, + sourcemap: nuxt.options.sourcemap.server || nuxt.options.sourcemap.client, + dirs: nuxt.options._layers.map( + layer => resolve(layer.config.srcDir, layer.config.dir?.pages || 'pages') + ) + } + nuxt.hook('modules:done', () => { + addVitePlugin(PageMetaPlugin.vite(pageMetaOptions)) + addWebpackPlugin(PageMetaPlugin.webpack(pageMetaOptions)) + }) + + // Add prefetching support for middleware & layouts + addPlugin(resolve(runtimeDir, 'plugins/prefetch.client')) + + // Add router plugin + addPlugin(resolve(runtimeDir, 'plugins/router')) + + const getSources = (pages: NuxtPage[]): string[] => pages + .filter(p => Boolean(p.file)) + .flatMap(p => + [relative(nuxt.options.srcDir, p.file as string), ...getSources(p.children || [])] + ) + + // Do not prefetch page chunks + nuxt.hook('build:manifest', async (manifest) => { + if (nuxt.options.dev) { return } + const pages = await resolvePagesRoutes() + await nuxt.callHook('pages:extend', pages) + + const sourceFiles = getSources(pages) + for (const key in manifest) { + if (manifest[key].isEntry) { + manifest[key].dynamicImports = + manifest[key].dynamicImports?.filter(i => !sourceFiles.includes(i)) + } + } + }) + + // Add routes template + addTemplate({ + filename: 'routes.mjs', + async getContents () { + const pages = await resolvePagesRoutes() + await nuxt.callHook('pages:extend', pages) + const { routes, imports } = normalizeRoutes(pages) + return [...imports, `export default ${routes}`].join('\n') + } + }) + + // Add vue-router import for `` integration + addTemplate({ + filename: 'pages.mjs', + getContents: () => 'export { useRoute } from \'vue-router\'' + }) + + // Optimize vue-router to ensure we share the same injection symbol + nuxt.options.vite.optimizeDeps = nuxt.options.vite.optimizeDeps || {} + nuxt.options.vite.optimizeDeps.include = nuxt.options.vite.optimizeDeps.include || [] + nuxt.options.vite.optimizeDeps.include.push('vue-router') + + nuxt.options.vite.resolve = nuxt.options.vite.resolve || {} + nuxt.options.vite.resolve.dedupe = nuxt.options.vite.resolve.dedupe || [] + nuxt.options.vite.resolve.dedupe.push('vue-router') + + // Add router options template + addTemplate({ + filename: 'router.options.mjs', + getContents: async () => { + // Scan and register app/router.options files + const routerOptionsFiles = (await Promise.all(nuxt.options._layers.map( + 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) + .map(([key, value]) => [key, genString(value as string)])) + + return [ + ...routerOptionsFiles.map((file, index) => genImport(file, `routerOptions${index}`)), + `const configRouterOptions = ${configRouterOptions}`, + 'export default {', + '...configRouterOptions,', + // We need to reverse spreading order to respect layers priority + ...routerOptionsFiles.map((_, index) => `...routerOptions${index},`).reverse(), + '}' + ].join('\n') + } + }) + + addTemplate({ + filename: 'types/middleware.d.ts', + getContents: ({ app }: { app: NuxtApp }) => { + const composablesFile = resolve(runtimeDir, 'composables') + const namedMiddleware = app.middleware.filter(mw => !mw.global) + return [ + 'import type { NavigationGuard } from \'vue-router\'', + `export type MiddlewareKey = ${namedMiddleware.map(mw => genString(mw.name)).join(' | ') || 'string'}`, + `declare module ${genString(composablesFile)} {`, + ' interface PageMeta {', + ' middleware?: MiddlewareKey | NavigationGuard | Array', + ' }', + '}' + ].join('\n') + } + }) + + addTemplate({ + filename: 'types/layouts.d.ts', + getContents: ({ app }: { app: NuxtApp }) => { + const composablesFile = resolve(runtimeDir, 'composables') + return [ + 'import { ComputedRef, Ref } from \'vue\'', + `export type LayoutKey = ${Object.keys(app.layouts).map(name => genString(name)).join(' | ') || 'string'}`, + `declare module ${genString(composablesFile)} {`, + ' interface PageMeta {', + ' layout?: false | LayoutKey | Ref | ComputedRef', + ' }', + '}' + ].join('\n') + } + }) + + // Add + addComponent({ + name: 'NuxtPage', + priority: 10, // built-in that we do not expect the user to override + filePath: resolve(distDir, 'pages/runtime/page') + }) + + // Add declarations for middleware keys + nuxt.hook('prepare:types', ({ references }) => { + references.push({ path: resolve(nuxt.options.buildDir, 'types/middleware.d.ts') }) + references.push({ path: resolve(nuxt.options.buildDir, 'types/layouts.d.ts') }) + }) + } +}) diff --git a/packages/schema/src/config/experimental.ts b/packages/schema/src/config/experimental.ts index 005110a0b4d0..ddfa18d1f879 100644 --- a/packages/schema/src/config/experimental.ts +++ b/packages/schema/src/config/experimental.ts @@ -161,5 +161,8 @@ export default defineUntypedSchema({ /** Resolve `~`, `~~`, `@` and `@@` aliases located within layers with respect to their layer source and root directories. */ localLayerAliases: true, + + /** Enable the new experimental typed router using [unplugin-vue-router](https://github.com/posva/unplugin-vue-router). */ + typedPages: false } }) From 316a288607ddf87a1b7c6d2cae17562296c7e9d1 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Wed, 12 Apr 2023 16:34:55 +0200 Subject: [PATCH 02/52] refactor: contain changes within pages --- packages/nuxt/src/core/nuxt.ts | 3 +- packages/nuxt/src/pages/module-typed.ts | 290 ------------------------ 2 files changed, 1 insertion(+), 292 deletions(-) delete mode 100644 packages/nuxt/src/pages/module-typed.ts diff --git a/packages/nuxt/src/core/nuxt.ts b/packages/nuxt/src/core/nuxt.ts index 1f4978b7a744..5c38493bafc8 100644 --- a/packages/nuxt/src/core/nuxt.ts +++ b/packages/nuxt/src/core/nuxt.ts @@ -9,7 +9,6 @@ import fse from 'fs-extra' import { withoutLeadingSlash } from 'ufo' /* eslint-disable import/no-restricted-paths */ import pagesModule from '../pages/module' -import typedPagesModule from '../pages/module-typed' import metaModule from '../head/module' import componentsModule from '../components/module' import importsModule from '../imports/module' @@ -360,7 +359,7 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise { options.appDir = options.alias['#app'] = resolve(distDir, 'app') options._majorVersion = 3 options._modules.push( - options.experimental.typedPages ? typedPagesModule : pagesModule, + pagesModule, metaModule, componentsModule ); diff --git a/packages/nuxt/src/pages/module-typed.ts b/packages/nuxt/src/pages/module-typed.ts deleted file mode 100644 index 8997954d9a03..000000000000 --- a/packages/nuxt/src/pages/module-typed.ts +++ /dev/null @@ -1,290 +0,0 @@ -import { existsSync, readdirSync } from 'node:fs' -import { addComponent, addPlugin, addTemplate, addVitePlugin, addWebpackPlugin, defineNuxtModule, findPath, updateTemplates } from '@nuxt/kit' -import { join, relative, resolve } from 'pathe' -import { genImport, genObjectFromRawEntries, genString } from 'knitwork' -import escapeRE from 'escape-string-regexp' -import { joinURL } from 'ufo' -import type { NuxtApp, NuxtPage } from 'nuxt/schema' - -import { distDir } from '../dirs' -import { normalizeRoutes, resolvePagesRoutes } from './utils' -import type { PageMetaPluginOptions } from './page-meta' -import { PageMetaPlugin } from './page-meta' - -export default defineNuxtModule({ - meta: { - name: 'pages' - }, - setup (_options, nuxt) { - const pagesDirs = nuxt.options._layers.map( - layer => resolve(layer.config.srcDir, layer.config.dir?.pages || 'pages') - ) - - // 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 userPreference = nuxt.options.pages - const isPagesEnabled = () => { - if (typeof userPreference === 'boolean') { - return userPreference - } - if (nuxt.options._layers.some(layer => existsSync(resolve(layer.config.srcDir, 'app/router.options.ts')))) { - return true - } - if (pagesDirs.some(dir => isNonEmptyDir(dir))) { - return true - } - return false - } - nuxt.options.pages = isPagesEnabled() - - // Restart Nuxt when pages dir is added or removed - const restartPaths = nuxt.options._layers.flatMap(layer => [ - join(layer.config.srcDir, 'app/router.options.ts'), - join(layer.config.srcDir, layer.config.dir?.pages || 'pages') - ]) - nuxt.hooks.hook('builder:watch', (event, path) => { - const fullPath = join(nuxt.options.srcDir, path) - if (restartPaths.some(path => path === fullPath || fullPath.startsWith(path + '/'))) { - const newSetting = isPagesEnabled() - if (nuxt.options.pages !== newSetting) { - console.info('Pages', newSetting ? 'enabled' : 'disabled') - return nuxt.callHook('restart') - } - } - }) - - if (!nuxt.options.pages) { - addPlugin(resolve(distDir, 'app/plugins/router')) - addTemplate({ - filename: 'pages.mjs', - getContents: () => 'export { useRoute } from \'#app\'' - }) - addComponent({ - name: 'NuxtPage', - priority: 10, // built-in that we do not expect the user to override - filePath: resolve(distDir, 'pages/runtime/page-placeholder') - }) - return - } - - const runtimeDir = resolve(distDir, 'pages/runtime') - - // Add $router types - nuxt.hook('prepare:types', ({ references }) => { - references.push({ types: 'vue-router' }) - }) - - // Add vue-router route guard imports - nuxt.hook('imports:sources', (sources) => { - const routerImports = sources.find(s => s.from === '#app' && s.imports.includes('onBeforeRouteLeave')) - if (routerImports) { - routerImports.from = 'vue-router' - } - }) - - // Regenerate templates when adding or removing pages - nuxt.hook('builder:watch', async (event, path) => { - 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 updateTemplates({ - filter: template => template.filename === 'routes.mjs' - }) - } - }) - - nuxt.hook('app:resolve', (app) => { - // Add default layout for pages - if (app.mainComponent!.includes('@nuxt/ui-templates')) { - app.mainComponent = resolve(runtimeDir, 'app.vue') - } - app.middleware.unshift({ - name: 'validate', - path: resolve(runtimeDir, 'validate'), - global: true - }) - }) - - // Prerender all non-dynamic page routes when generating app - if (!nuxt.options.dev && nuxt.options._generate) { - const prerenderRoutes = new Set() - nuxt.hook('modules:done', () => { - nuxt.hook('pages:extend', (pages) => { - prerenderRoutes.clear() - const processPages = (pages: NuxtPage[], currentPath = '/') => { - for (const page of pages) { - // Add root of optional dynamic paths and catchalls - if (page.path.match(/^\/?:.*(\?|\(\.\*\)\*)$/) && !page.children?.length) { prerenderRoutes.add(currentPath) } - // Skip dynamic paths - if (page.path.includes(':')) { continue } - const route = joinURL(currentPath, page.path) - prerenderRoutes.add(route) - if (page.children) { processPages(page.children, route) } - } - } - processPages(pages) - }) - }) - nuxt.hook('nitro:build:before', (nitro) => { - for (const route of nitro.options.prerender.routes || []) { - // Skip default route value as we only generate it if it is already - // in the detected routes from `~/pages`. - if (route === '/') { continue } - prerenderRoutes.add(route) - } - nitro.options.prerender.routes = Array.from(prerenderRoutes) - }) - } - - nuxt.hook('imports:extend', (imports) => { - imports.push( - { name: 'definePageMeta', as: 'definePageMeta', from: resolve(runtimeDir, 'composables') }, - { name: 'useLink', as: 'useLink', from: 'vue-router' } - ) - }) - - // Extract macros from pages - const pageMetaOptions: PageMetaPluginOptions = { - dev: nuxt.options.dev, - sourcemap: nuxt.options.sourcemap.server || nuxt.options.sourcemap.client, - dirs: nuxt.options._layers.map( - layer => resolve(layer.config.srcDir, layer.config.dir?.pages || 'pages') - ) - } - nuxt.hook('modules:done', () => { - addVitePlugin(PageMetaPlugin.vite(pageMetaOptions)) - addWebpackPlugin(PageMetaPlugin.webpack(pageMetaOptions)) - }) - - // Add prefetching support for middleware & layouts - addPlugin(resolve(runtimeDir, 'plugins/prefetch.client')) - - // Add router plugin - addPlugin(resolve(runtimeDir, 'plugins/router')) - - const getSources = (pages: NuxtPage[]): string[] => pages - .filter(p => Boolean(p.file)) - .flatMap(p => - [relative(nuxt.options.srcDir, p.file as string), ...getSources(p.children || [])] - ) - - // Do not prefetch page chunks - nuxt.hook('build:manifest', async (manifest) => { - if (nuxt.options.dev) { return } - const pages = await resolvePagesRoutes() - await nuxt.callHook('pages:extend', pages) - - const sourceFiles = getSources(pages) - for (const key in manifest) { - if (manifest[key].isEntry) { - manifest[key].dynamicImports = - manifest[key].dynamicImports?.filter(i => !sourceFiles.includes(i)) - } - } - }) - - // Add routes template - addTemplate({ - filename: 'routes.mjs', - async getContents () { - const pages = await resolvePagesRoutes() - await nuxt.callHook('pages:extend', pages) - const { routes, imports } = normalizeRoutes(pages) - return [...imports, `export default ${routes}`].join('\n') - } - }) - - // Add vue-router import for `` integration - addTemplate({ - filename: 'pages.mjs', - getContents: () => 'export { useRoute } from \'vue-router\'' - }) - - // Optimize vue-router to ensure we share the same injection symbol - nuxt.options.vite.optimizeDeps = nuxt.options.vite.optimizeDeps || {} - nuxt.options.vite.optimizeDeps.include = nuxt.options.vite.optimizeDeps.include || [] - nuxt.options.vite.optimizeDeps.include.push('vue-router') - - nuxt.options.vite.resolve = nuxt.options.vite.resolve || {} - nuxt.options.vite.resolve.dedupe = nuxt.options.vite.resolve.dedupe || [] - nuxt.options.vite.resolve.dedupe.push('vue-router') - - // Add router options template - addTemplate({ - filename: 'router.options.mjs', - getContents: async () => { - // Scan and register app/router.options files - const routerOptionsFiles = (await Promise.all(nuxt.options._layers.map( - 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) - .map(([key, value]) => [key, genString(value as string)])) - - return [ - ...routerOptionsFiles.map((file, index) => genImport(file, `routerOptions${index}`)), - `const configRouterOptions = ${configRouterOptions}`, - 'export default {', - '...configRouterOptions,', - // We need to reverse spreading order to respect layers priority - ...routerOptionsFiles.map((_, index) => `...routerOptions${index},`).reverse(), - '}' - ].join('\n') - } - }) - - addTemplate({ - filename: 'types/middleware.d.ts', - getContents: ({ app }: { app: NuxtApp }) => { - const composablesFile = resolve(runtimeDir, 'composables') - const namedMiddleware = app.middleware.filter(mw => !mw.global) - return [ - 'import type { NavigationGuard } from \'vue-router\'', - `export type MiddlewareKey = ${namedMiddleware.map(mw => genString(mw.name)).join(' | ') || 'string'}`, - `declare module ${genString(composablesFile)} {`, - ' interface PageMeta {', - ' middleware?: MiddlewareKey | NavigationGuard | Array', - ' }', - '}' - ].join('\n') - } - }) - - addTemplate({ - filename: 'types/layouts.d.ts', - getContents: ({ app }: { app: NuxtApp }) => { - const composablesFile = resolve(runtimeDir, 'composables') - return [ - 'import { ComputedRef, Ref } from \'vue\'', - `export type LayoutKey = ${Object.keys(app.layouts).map(name => genString(name)).join(' | ') || 'string'}`, - `declare module ${genString(composablesFile)} {`, - ' interface PageMeta {', - ' layout?: false | LayoutKey | Ref | ComputedRef', - ' }', - '}' - ].join('\n') - } - }) - - // Add - addComponent({ - name: 'NuxtPage', - priority: 10, // built-in that we do not expect the user to override - filePath: resolve(distDir, 'pages/runtime/page') - }) - - // Add declarations for middleware keys - nuxt.hook('prepare:types', ({ references }) => { - references.push({ path: resolve(nuxt.options.buildDir, 'types/middleware.d.ts') }) - references.push({ path: resolve(nuxt.options.buildDir, 'types/layouts.d.ts') }) - }) - } -}) From 628922324586588030dc50745c1fa675854cfba0 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Wed, 12 Apr 2023 16:35:11 +0200 Subject: [PATCH 03/52] feat: allow vite plugins to be prepended --- packages/kit/src/build.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/kit/src/build.ts b/packages/kit/src/build.ts index e5678da2e6a7..e6c6ff073881 100644 --- a/packages/kit/src/build.ts +++ b/packages/kit/src/build.ts @@ -32,7 +32,14 @@ export interface ExtendConfigOptions { export interface ExtendWebpackConfigOptions extends ExtendConfigOptions { } -export interface ExtendViteConfigOptions extends ExtendConfigOptions {} +export interface ExtendViteConfigOptions extends ExtendConfigOptions { + /** + * Prepends the plugin to the array with `unshit()` instead of `push()`. In practice this shouldn't be necessary, but + * it's needed by unplugin-vue-router until vue exposes an API to parse files. + * @internal + */ + prepend?: boolean +} /** * Extend webpack config @@ -119,11 +126,12 @@ export function addWebpackPlugin (plugin: WebpackPluginInstance | WebpackPluginI */ export function addVitePlugin (plugin: VitePlugin | VitePlugin[], options?: ExtendViteConfigOptions) { extendViteConfig((config) => { + const method: 'push' | 'unshift' = options?.prepend ? 'unshift' : 'push' config.plugins = config.plugins || [] if (Array.isArray(plugin)) { - config.plugins.push(...plugin) + config.plugins[method](...plugin) } else { - config.plugins.push(plugin) + config.plugins[method](plugin) } }, options) } From 2f543251d778b4d933effbc56f638207218ba19a Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Wed, 12 Apr 2023 16:37:20 +0200 Subject: [PATCH 04/52] chore: add temporary playground to test --- packages/nuxt/package.json | 1 + playground/app.vue | 23 ++++++++++++++++++++--- playground/nuxt.config.ts | 19 ++++++++++++++++++- playground/pages/about.vue | 6 ++++++ playground/pages/index.vue | 16 ++++++++++++++++ playground/pages/users/[id].vue | 9 +++++++++ 6 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 playground/pages/about.vue create mode 100644 playground/pages/index.vue create mode 100644 playground/pages/users/[id].vue diff --git a/packages/nuxt/package.json b/packages/nuxt/package.json index c04ee9ad639e..153bba8c9daf 100644 --- a/packages/nuxt/package.json +++ b/packages/nuxt/package.json @@ -98,6 +98,7 @@ "unenv": "^1.3.1", "unimport": "^3.0.6", "unplugin": "^1.3.1", + "unplugin-vue-router": "file:.yalc/unplugin-vue-router", "untyped": "^1.3.2", "vue": "^3.2.47", "vue-bundle-renderer": "^1.0.3", diff --git a/playground/app.vue b/playground/app.vue index 17d631007a1b..eb4bb3d735be 100644 --- a/playground/app.vue +++ b/playground/app.vue @@ -1,11 +1,28 @@