perf: don't add global component plugin if not used

This commit is contained in:
Julien Huang 2024-04-04 20:03:15 +02:00
parent 08b656a047
commit 2e705fb289
4 changed files with 64 additions and 48 deletions

View File

@ -0,0 +1,52 @@
import { NuxtApp, NuxtPluginTemplate } from "@nuxt/schema"
interface GetGlobalComponentsType {
lazyGlobalComponents: Set<string>
syncGlobalComponents: Set<string>
}
export function getGlobalComponents(app: NuxtApp): GetGlobalComponentsType | null {
const lazyGlobalComponents = new Set<string>()
const syncGlobalComponents = new Set<string>()
for (const component of app.components) {
if (component.global === 'sync') {
syncGlobalComponents.add(component.pascalName)
} else if (component.global) {
lazyGlobalComponents.add(component.pascalName)
}
}
// will not be imported and be treeshaken
if (!lazyGlobalComponents.size && !syncGlobalComponents.size) { return null }
return {
lazyGlobalComponents,
syncGlobalComponents
}
}
export const getComponentsPluginTemplate: (components: GetGlobalComponentsType) => NuxtPluginTemplate = ({lazyGlobalComponents, syncGlobalComponents}) => ({
filename: 'components.plugin.mjs',
write: true,
getContents () {
const lazyComponents = [...lazyGlobalComponents]
const syncComponents = [...syncGlobalComponents]
return `import { defineNuxtPlugin } from '#app/nuxt'
import { ${[...lazyComponents.map(c => 'Lazy' + c), ...syncComponents].join(', ')} } from '#components'
const lazyGlobalComponents = [
${lazyComponents.map(c => `["${c}", Lazy${c}]`).join(',\n')},
${syncComponents.map(c => `["${c}", ${c}]`).join(',\n')}
]
export default defineNuxtPlugin({
name: 'nuxt:global-components',
setup (nuxtApp) {
for (const [name, component] of lazyGlobalComponents) {
nuxtApp.vueApp.component(name, component)
nuxtApp.vueApp.component('Lazy' + name, component)
}
}
})
`
}
})

View File

@ -5,12 +5,13 @@ import type { Component, ComponentsDir, ComponentsOptions } from 'nuxt/schema'
import { distDir } from '../dirs'
import { clientFallbackAutoIdPlugin } from './client-fallback-auto-id'
import { componentNamesTemplate, componentsIslandsTemplate, componentsPluginTemplate, componentsTypeTemplate } from './templates'
import { componentNamesTemplate, componentsIslandsTemplate, componentsTypeTemplate } from './templates'
import { scanComponents } from './scan'
import { loaderPlugin } from './loader'
import { TreeShakeTemplatePlugin } from './tree-shake'
import { componentsChunkPlugin, islandsTransform } from './islandsTransform'
import { createTransformPlugin } from './transform'
import { getComponentsPluginTemplate, getGlobalComponents } from './global-components'
const isPureObjectOrString = (val: any) => (!Array.isArray(val) && typeof val === 'object') || typeof val === 'string'
const isDirectory = (p: string) => { try { return statSync(p).isDirectory() } catch (_e) { return false } }
@ -117,7 +118,6 @@ export default defineNuxtModule<ComponentsOptions>({
// components.d.ts
addTemplate(componentsTypeTemplate)
// components.plugin.mjs
addPluginTemplate(componentsPluginTemplate)
// component-names.mjs
addTemplate(componentNamesTemplate)
// components.islands.mjs
@ -179,6 +179,12 @@ export default defineNuxtModule<ComponentsOptions>({
}
context.components = newComponents
app.components = newComponents
const globalComponents = getGlobalComponents(app)
if (globalComponents) {
console.log('!!', getComponentsPluginTemplate(globalComponents))
addPluginTemplate(getComponentsPluginTemplate(globalComponents))
}
})
nuxt.hook('prepare:types', ({ references, tsConfig }) => {

View File

@ -1,6 +1,6 @@
import { isAbsolute, relative } from 'pathe'
import { genDynamicImport } from 'knitwork'
import type { NuxtPluginTemplate, NuxtTemplate } from 'nuxt/schema'
import type { NuxtTemplate } from 'nuxt/schema'
type ImportMagicCommentsOptions = {
chunkName: string
@ -17,50 +17,6 @@ const createImportMagicComments = (options: ImportMagicCommentsOptions) => {
].filter(Boolean).join(', ')
}
const emptyComponentsPlugin = `
import { defineNuxtPlugin } from '#app/nuxt'
export default defineNuxtPlugin({
name: 'nuxt:global-components',
})
`
export const componentsPluginTemplate: NuxtPluginTemplate = {
filename: 'components.plugin.mjs',
getContents ({ app }) {
const lazyGlobalComponents = new Set<string>()
const syncGlobalComponents = new Set<string>()
for (const component of app.components) {
if (component.global === 'sync') {
syncGlobalComponents.add(component.pascalName)
} else if (component.global) {
lazyGlobalComponents.add(component.pascalName)
}
}
if (!lazyGlobalComponents.size && !syncGlobalComponents.size) { return emptyComponentsPlugin }
const lazyComponents = [...lazyGlobalComponents]
const syncComponents = [...syncGlobalComponents]
return `import { defineNuxtPlugin } from '#app/nuxt'
import { ${[...lazyComponents.map(c => 'Lazy' + c), ...syncComponents].join(', ')} } from '#components'
const lazyGlobalComponents = [
${lazyComponents.map(c => `["${c}", Lazy${c}]`).join(',\n')},
${syncComponents.map(c => `["${c}", ${c}]`).join(',\n')}
]
export default defineNuxtPlugin({
name: 'nuxt:global-components',
setup (nuxtApp) {
for (const [name, component] of lazyGlobalComponents) {
nuxtApp.vueApp.component(name, component)
nuxtApp.vueApp.component('Lazy' + name, component)
}
}
})
`
}
}
export const componentNamesTemplate: NuxtTemplate = {
filename: 'component-names.mjs',
getContents ({ app }) {

View File

@ -1,3 +1,5 @@
export default defineNuxtConfig({
devtools: {
enabled:true
}
})