From b5f5f7d5bace9bfe8bc691ab3786b3f39da200fa Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Wed, 6 Jul 2022 20:15:00 +0100 Subject: [PATCH] perf(nuxt)!: remove legacy app context (#5630) --- packages/nuxt/src/app/compat/legacy-app.ts | 215 ------------------ .../nuxt/src/app/composables/component.ts | 7 +- packages/nuxt/src/app/nuxt.ts | 21 +- packages/nuxt/src/components/templates.ts | 5 +- packages/schema/src/config/experimental.ts | 2 +- 5 files changed, 8 insertions(+), 242 deletions(-) delete mode 100644 packages/nuxt/src/app/compat/legacy-app.ts diff --git a/packages/nuxt/src/app/compat/legacy-app.ts b/packages/nuxt/src/app/compat/legacy-app.ts deleted file mode 100644 index 0be4de2d8b..0000000000 --- a/packages/nuxt/src/app/compat/legacy-app.ts +++ /dev/null @@ -1,215 +0,0 @@ -import type { IncomingMessage, ServerResponse } from 'node:http' -import type { App } from 'vue' -import type { Component } from '@vue/runtime-core' -import mockContext from 'unenv/runtime/mock/proxy' -import type { RouteLocationNormalized, Router } from 'vue-router' -import { NuxtApp, useRuntimeConfig } from '../nuxt' - -type Store = any - -export type LegacyApp = App & { - $root: LegacyApp - constructor: LegacyApp - $router?: Router -} - -export interface LegacyContext { - // -> $config - $config: Record - env: Record - // -> app - app: Component - // -> unsupported - isClient: boolean - isServer: boolean - isStatic: boolean - // TODO: needs app implementation - isDev: boolean - isHMR: boolean - // -> unsupported - store: Store - // vue-router integration - route: RouteLocationNormalized - params: RouteLocationNormalized['params'] - query: RouteLocationNormalized['query'] - base: string /** TODO: */ - payload: any /** TODO: */ - from: RouteLocationNormalized /** TODO: */ - // -> nuxt.payload.data - nuxtState: Record - // TODO: needs app implementation - beforeNuxtRender (fn: (params: { Components: any, nuxtState: Record }) => void): void - beforeSerialize (fn: (nuxtState: Record) => void): void - // TODO: needs app implementation - enablePreview?: (previewData?: Record) => void - $preview?: Record - // -> ssrContext.{req,res} - req: IncomingMessage - res: ServerResponse - /** TODO: */ - next?: (err?: any) => any - error (params: any): void - redirect (status: number, path: string, query?: RouteLocationNormalized['query']): void - redirect (path: string, query?: RouteLocationNormalized['query']): void - redirect (location: Location): void - redirect (status: number, location: Location): void - ssrContext?: { - // -> ssrContext.{req,res,url,runtimeConfig} - req: LegacyContext['req'] - res: LegacyContext['res'] - url: string - runtimeConfig: { - public: Record - private: Record - } - // -> unsupported - target: string - spa?: boolean - modern: boolean - fetchCounters: Record - // TODO: - next: LegacyContext['next'] - redirected: boolean - beforeRenderFns: Array<() => any> - beforeSerializeFns: Array<() => any> - // -> nuxt.payload - nuxt: { - serverRendered: boolean - // TODO: - layout: string - data: Array> - fetch: Array> - error: any - state: Array> - routePath: string - config: Record - } - } -} - -function mock (warning: string) { - console.warn(warning) - return mockContext -} - -const unsupported = new Set([ - 'store', - 'spa', - 'fetchCounters' -]) - -const todo = new Set([ - 'isHMR', - // Routing handlers - needs implementation or deprecation - 'base', - 'payload', - 'from', - 'next', - 'error', - 'redirect', - 'redirected', - // needs app implementation - 'enablePreview', - '$preview', - 'beforeNuxtRender', - 'beforeSerialize' -]) - -const serverProperties = new Set([ - 'req', - 'res', - 'ssrContext' -]) - -const routerKeys: Array = ['route', 'params', 'query'] - -const staticFlags = { - isClient: process.client, - isServer: process.server, - isDev: process.dev, - isStatic: undefined, - target: 'server', - modern: false -} - -export const legacyPlugin = (nuxtApp: NuxtApp) => { - nuxtApp._legacyContext = new Proxy(nuxtApp, { - get (nuxt, p: keyof LegacyContext | keyof LegacyContext['ssrContext']) { - // Unsupported keys - if (unsupported.has(p)) { - return mock(`Accessing ${p} is not supported in Nuxt 3.`) - } - - if (todo.has(p)) { - return mock(`Accessing ${p} is not yet supported in Nuxt 3.`) - } - - // vue-router implementation - if (routerKeys.includes(p)) { - if (!('$router' in nuxtApp)) { - return mock('vue-router is not being used in this project.') - } - switch (p) { - case 'route': - return nuxt.$router.currentRoute.value - case 'params': - case 'query': - return nuxt.$router.currentRoute.value[p] - } - } - - if (p === '$config' || p === 'env') { - return useRuntimeConfig() - } - - if (p in staticFlags) { - return staticFlags[p] - } - - if (process.client && serverProperties.has(p)) { - return undefined - } - - if (p === 'ssrContext') { - return nuxt._legacyContext - } - - if (nuxt.ssrContext && p in nuxt.ssrContext) { - return nuxt.ssrContext[p] - } - - if (p === 'nuxt') { - return nuxt.payload - } - - if (p === 'nuxtState') { - return nuxt.payload.data - } - - if (p in nuxtApp.vueApp) { - return nuxtApp.vueApp[p] - } - - if (p in nuxtApp) { - return nuxtApp[p] - } - - return mock(`Accessing ${p} is not supported in Nuxt3.`) - } - }) as unknown as LegacyContext - - if (process.client) { - nuxtApp.hook('app:created', () => { - const legacyApp = new Proxy(nuxtApp.vueApp as LegacyApp, { - get (source, p: keyof LegacyApp) { - // TODO: https://github.com/nuxt/framework/issues/244 - if (['$root', 'constructor'].includes(p)) { - return legacyApp - } - return source[p] || nuxtApp[p] - } - }) - window[`$${nuxtApp.globalName}`] = legacyApp - }) - } -} diff --git a/packages/nuxt/src/app/composables/component.ts b/packages/nuxt/src/app/composables/component.ts index b331671764..32b1449705 100644 --- a/packages/nuxt/src/app/composables/component.ts +++ b/packages/nuxt/src/app/composables/component.ts @@ -1,19 +1,18 @@ import { defineComponent, getCurrentInstance, reactive, toRefs } from 'vue' import type { DefineComponent } from 'vue' import { useRoute } from 'vue-router' -import type { LegacyContext } from '../compat/legacy-app' -import { useNuxtApp } from '../nuxt' +import { NuxtApp, useNuxtApp } from '../nuxt' import { useAsyncData } from './asyncData' export const NuxtComponentIndicator = '__nuxt_component' -async function runLegacyAsyncData (res: Record | Promise>, fn: (context: LegacyContext) => Promise>) { +async function runLegacyAsyncData (res: Record | Promise>, fn: (nuxtApp: NuxtApp) => Promise>) { const nuxt = useNuxtApp() const route = useRoute() const vm = getCurrentInstance() const { fetchKey } = vm.proxy.$options const key = typeof fetchKey === 'function' ? fetchKey(() => '') : fetchKey || route.fullPath - const { data } = await useAsyncData(`options:asyncdata:${key}`, () => fn(nuxt._legacyContext)) + const { data } = await useAsyncData(`options:asyncdata:${key}`, () => fn(nuxt)) if (data.value && typeof data.value === 'object') { Object.assign(await res, toRefs(reactive(data.value))) } else if (process.dev) { diff --git a/packages/nuxt/src/app/nuxt.ts b/packages/nuxt/src/app/nuxt.ts index 616a77a8c1..e24f425684 100644 --- a/packages/nuxt/src/app/nuxt.ts +++ b/packages/nuxt/src/app/nuxt.ts @@ -6,7 +6,6 @@ import type { RuntimeConfig } from '@nuxt/schema' import { getContext } from 'unctx' import type { SSRContext } from 'vue-bundle-renderer' import type { CompatibilityEvent } from 'h3' -import { legacyPlugin, LegacyContext } from './compat/legacy-app' const nuxtAppCtx = getContext('nuxt-app') @@ -48,7 +47,6 @@ interface _NuxtApp { [key: string]: any _asyncDataPromises?: Record> - _legacyContext?: LegacyContext ssrContext?: SSRContext & { url: string @@ -83,9 +81,6 @@ export interface Plugin = Record | Promise<{ provide?: Injections }> | void | { provide?: Injections } [NuxtPluginIndicator]?: true } -export interface LegacyPlugin { - (context: LegacyContext, provide: NuxtApp['provide']): Promise | void -} export interface CreateOptions { vueApp: NuxtApp['vueApp'] @@ -185,24 +180,14 @@ export async function applyPlugins (nuxtApp: NuxtApp, plugins: Plugin[]) { } } -export function normalizePlugins (_plugins: Array) { - let needsLegacyContext = false - +export function normalizePlugins (_plugins: Plugin[]) { const plugins = _plugins.map((plugin) => { if (typeof plugin !== 'function') { return () => {} } - if (isLegacyPlugin(plugin)) { - needsLegacyContext = true - return (nuxtApp: NuxtApp) => plugin(nuxtApp._legacyContext!, nuxtApp.provide) - } return plugin }) - if (needsLegacyContext) { - plugins.unshift(legacyPlugin) - } - return plugins as Plugin[] } @@ -211,10 +196,6 @@ export function defineNuxtPlugin (plugin: Plugin) { return plugin } -export function isLegacyPlugin (plugin: unknown): plugin is LegacyPlugin { - return !plugin[NuxtPluginIndicator] -} - /** * Ensures that the setup function passed in has access to the Nuxt instance via `useNuxt`. * diff --git a/packages/nuxt/src/components/templates.ts b/packages/nuxt/src/components/templates.ts index 29ffdeaceb..915697f82f 100644 --- a/packages/nuxt/src/components/templates.ts +++ b/packages/nuxt/src/components/templates.ts @@ -27,6 +27,7 @@ export const componentsPluginTemplate = { filename: 'components.plugin.mjs', getContents ({ options }: { options: ComponentsTemplateOptions }) { return `import { defineAsyncComponent } from 'vue' +import { defineNuxtPlugin } from '#app' const components = ${genObjectFromRawEntries(options.components.filter(c => c.global === true).map((c) => { const exp = c.export === 'default' ? 'c.default || c' : `c['${c.export}']` @@ -35,12 +36,12 @@ const components = ${genObjectFromRawEntries(options.components.filter(c => c.gl return [c.pascalName, `defineAsyncComponent(${genDynamicImport(c.filePath, { comment })}.then(c => ${exp}))`] }))} -export default function (nuxtApp) { +export default defineNuxtPlugin(nuxtApp => { for (const name in components) { nuxtApp.vueApp.component(name, components[name]) nuxtApp.vueApp.component('Lazy' + name, components[name]) } -} +}) ` } } diff --git a/packages/schema/src/config/experimental.ts b/packages/schema/src/config/experimental.ts index e80d749b1e..38ea46164c 100644 --- a/packages/schema/src/config/experimental.ts +++ b/packages/schema/src/config/experimental.ts @@ -23,6 +23,6 @@ export default { * Externalize `vue`, `@vue/*` and `vue-router` when build * @see https://github.com/nuxt/framework/issues/4084 */ - externalVue: false + externalVue: false, } }