feat(kit,nuxt): add component priority to allow overriding (#19252)

This commit is contained in:
Daniel Roe 2023-03-06 11:33:40 +00:00 committed by GitHub
parent a7d75a8465
commit 129bb4fa3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 48 additions and 7 deletions

View File

@ -40,14 +40,24 @@ export async function addComponent (opts: AddComponentOptions) {
preload: false, preload: false,
mode: 'all', mode: 'all',
shortPath: opts.filePath, shortPath: opts.filePath,
priority: 0,
...opts ...opts
} }
nuxt.hook('components:extend', (components: Component[]) => { nuxt.hook('components:extend', (components: Component[]) => {
const existingComponent = components.find(c => (c.pascalName === component.pascalName || c.kebabName === component.kebabName) && c.mode === component.mode) const existingComponent = components.find(c => (c.pascalName === component.pascalName || c.kebabName === component.kebabName) && c.mode === component.mode)
if (existingComponent) { if (existingComponent) {
const name = existingComponent.pascalName || existingComponent.kebabName const existingPriority = existingComponent.priority ?? 0
console.warn(`Overriding ${name} component.`) const newPriority = component.priority ?? 0
if (newPriority < existingPriority) { return }
// We override where new component priority is equal or higher
// but we warn if they are equal.
if (newPriority === existingPriority) {
const name = existingComponent.pascalName || existingComponent.kebabName
console.warn(`Overriding ${name} component. You can specify a \`priority\` option when calling \`addComponent\` to avoid this warning.`)
}
Object.assign(existingComponent, component) Object.assign(existingComponent, component)
} else { } else {
components.push(component) components.push(component)

View File

@ -118,7 +118,9 @@ export async function scanComponents (dirs: ComponentsDir[], srcDir: string): Pr
kebabName, kebabName,
chunkName, chunkName,
shortPath, shortPath,
export: 'default' export: 'default',
// by default, give priority to scanned components
priority: 1
} }
if (typeof dir.extendComponent === 'function') { if (typeof dir.extendComponent === 'function') {

View File

@ -158,47 +158,55 @@ async function initNuxt (nuxt: Nuxt) {
// Add <NuxtWelcome> // Add <NuxtWelcome>
addComponent({ addComponent({
name: 'NuxtWelcome', name: 'NuxtWelcome',
priority: 10, // built-in that we do not expect the user to override
filePath: tryResolveModule('@nuxt/ui-templates/templates/welcome.vue')! filePath: tryResolveModule('@nuxt/ui-templates/templates/welcome.vue')!
}) })
addComponent({ addComponent({
name: 'NuxtLayout', name: 'NuxtLayout',
priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/layout') filePath: resolve(nuxt.options.appDir, 'components/layout')
}) })
// Add <NuxtErrorBoundary> // Add <NuxtErrorBoundary>
addComponent({ addComponent({
name: 'NuxtErrorBoundary', name: 'NuxtErrorBoundary',
priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/nuxt-error-boundary') filePath: resolve(nuxt.options.appDir, 'components/nuxt-error-boundary')
}) })
// Add <ClientOnly> // Add <ClientOnly>
addComponent({ addComponent({
name: 'ClientOnly', name: 'ClientOnly',
priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/client-only') filePath: resolve(nuxt.options.appDir, 'components/client-only')
}) })
// Add <DevOnly> // Add <DevOnly>
addComponent({ addComponent({
name: 'DevOnly', name: 'DevOnly',
priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/dev-only') filePath: resolve(nuxt.options.appDir, 'components/dev-only')
}) })
// Add <ServerPlaceholder> // Add <ServerPlaceholder>
addComponent({ addComponent({
name: 'ServerPlaceholder', name: 'ServerPlaceholder',
priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/server-placeholder') filePath: resolve(nuxt.options.appDir, 'components/server-placeholder')
}) })
// Add <NuxtLink> // Add <NuxtLink>
addComponent({ addComponent({
name: 'NuxtLink', name: 'NuxtLink',
priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/nuxt-link') filePath: resolve(nuxt.options.appDir, 'components/nuxt-link')
}) })
// Add <NuxtLoadingIndicator> // Add <NuxtLoadingIndicator>
addComponent({ addComponent({
name: 'NuxtLoadingIndicator', name: 'NuxtLoadingIndicator',
priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/nuxt-loading-indicator') filePath: resolve(nuxt.options.appDir, 'components/nuxt-loading-indicator')
}) })
@ -206,6 +214,7 @@ async function initNuxt (nuxt: Nuxt) {
if (nuxt.options.experimental.componentIslands) { if (nuxt.options.experimental.componentIslands) {
addComponent({ addComponent({
name: 'NuxtIsland', name: 'NuxtIsland',
priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/nuxt-island') filePath: resolve(nuxt.options.appDir, 'components/nuxt-island')
}) })
} }

View File

@ -24,6 +24,8 @@ export default defineNuxtModule({
name: componentName, name: componentName,
filePath: componentsPath, filePath: componentsPath,
export: componentName, export: componentName,
// built-in that we do not expect the user to override
priority: 10,
// kebab case version of these tags is not valid // kebab case version of these tags is not valid
kebabName: componentName kebabName: componentName
}) })

View File

@ -43,6 +43,7 @@ export default defineNuxtModule({
}) })
addComponent({ addComponent({
name: 'NuxtPage', name: 'NuxtPage',
priority: 10, // built-in that we do not expect the user to override
filePath: resolve(distDir, 'pages/runtime/page-placeholder') filePath: resolve(distDir, 'pages/runtime/page-placeholder')
}) })
return return
@ -256,6 +257,7 @@ export default defineNuxtModule({
// Add <NuxtPage> // Add <NuxtPage>
addComponent({ addComponent({
name: 'NuxtPage', name: 'NuxtPage',
priority: 10, // built-in that we do not expect the user to override
filePath: resolve(distDir, 'pages/runtime/page') filePath: resolve(distDir, 'pages/runtime/page')
}) })

View File

@ -97,6 +97,7 @@ const expectedComponents = [
pascalName: 'Isle', pascalName: 'Isle',
prefetch: false, prefetch: false,
preload: false, preload: false,
priority: 1,
shortPath: 'components/islands/Isle.vue' shortPath: 'components/islands/Isle.vue'
}, },
{ {
@ -109,6 +110,7 @@ const expectedComponents = [
pascalName: 'Glob', pascalName: 'Glob',
prefetch: false, prefetch: false,
preload: false, preload: false,
priority: 1,
shortPath: 'components/global/Glob.vue' shortPath: 'components/global/Glob.vue'
}, },
{ {
@ -121,7 +123,8 @@ const expectedComponents = [
global: undefined, global: undefined,
island: undefined, island: undefined,
prefetch: false, prefetch: false,
preload: false preload: false,
priority: 1
}, },
{ {
mode: 'client', mode: 'client',
@ -133,7 +136,8 @@ const expectedComponents = [
global: undefined, global: undefined,
island: undefined, island: undefined,
prefetch: false, prefetch: false,
preload: false preload: false,
priority: 1
}, },
{ {
mode: 'server', mode: 'server',
@ -145,7 +149,8 @@ const expectedComponents = [
global: undefined, global: undefined,
island: undefined, island: undefined,
prefetch: false, prefetch: false,
preload: false preload: false,
priority: 1
}, },
{ {
chunkName: 'components/client-component-with-props', chunkName: 'components/client-component-with-props',
@ -157,6 +162,7 @@ const expectedComponents = [
pascalName: 'ClientComponentWithProps', pascalName: 'ClientComponentWithProps',
prefetch: false, prefetch: false,
preload: false, preload: false,
priority: 1,
shortPath: 'components/client/ComponentWithProps.vue' shortPath: 'components/client/ComponentWithProps.vue'
}, },
{ {
@ -169,6 +175,7 @@ const expectedComponents = [
pascalName: 'ClientWithClientOnlySetup', pascalName: 'ClientWithClientOnlySetup',
prefetch: false, prefetch: false,
preload: false, preload: false,
priority: 1,
shortPath: 'components/client/WithClientOnlySetup.vue' shortPath: 'components/client/WithClientOnlySetup.vue'
}, },
{ {
@ -181,7 +188,8 @@ const expectedComponents = [
global: undefined, global: undefined,
island: undefined, island: undefined,
prefetch: false, prefetch: false,
preload: false preload: false,
priority: 1
}, },
{ {
chunkName: 'components/some-glob', chunkName: 'components/some-glob',
@ -193,6 +201,7 @@ const expectedComponents = [
pascalName: 'SomeGlob', pascalName: 'SomeGlob',
prefetch: false, prefetch: false,
preload: false, preload: false,
priority: 1,
shortPath: 'components/some-glob.global.vue' shortPath: 'components/some-glob.global.vue'
}, },
{ {
@ -205,6 +214,7 @@ const expectedComponents = [
pascalName: 'Some', pascalName: 'Some',
prefetch: false, prefetch: false,
preload: false, preload: false,
priority: 1,
shortPath: 'components/some.island.vue' shortPath: 'components/some.island.vue'
} }
] ]

View File

@ -10,6 +10,12 @@ export interface Component {
global?: boolean global?: boolean
island?: boolean island?: boolean
mode?: 'client' | 'server' | 'all' mode?: 'client' | 'server' | 'all'
/**
* This number allows configuring the behavior of overriding Nuxt components.
* If multiple components are provided with the same name, then higher priority
* components will be used instead of lower priority components.
*/
priority?: number
} }
export interface ScanDir { export interface ScanDir {