-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
/
templates.ts
132 lines (116 loc) · 4.71 KB
/
templates.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import { isAbsolute, relative } from 'pathe'
import { genDynamicImport } from 'knitwork'
import type { NuxtPluginTemplate, NuxtTemplate } from 'nuxt/schema'
type ImportMagicCommentsOptions = {
chunkName: string
prefetch?: boolean | number
preload?: boolean | number
}
const createImportMagicComments = (options: ImportMagicCommentsOptions) => {
const { chunkName, prefetch, preload } = options
return [
`webpackChunkName: "${chunkName}"`,
prefetch === true || typeof prefetch === 'number' ? `webpackPrefetch: ${prefetch}` : false,
preload === true || typeof preload === 'number' ? `webpackPreload: ${preload}` : false
].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 }) {
return `export const componentNames = ${JSON.stringify(app.components.filter(c => !c.island).map(c => c.pascalName))}`
}
}
export const componentsIslandsTemplate: NuxtTemplate = {
// components.islands.mjs'
getContents ({ app }) {
const components = app.components
const pages = app.pages
const islands = components.filter(component =>
component.island ||
// .server components without a corresponding .client component will need to be rendered as an island
(component.mode === 'server' && !components.some(c => c.pascalName === component.pascalName && c.mode === 'client'))
)
const pageExports = pages?.filter(p => (p.mode === 'server' && p.file && p.name)).map((p) => {
return `"page:${p.name}": defineAsyncComponent(${genDynamicImport(p.file!)}.then(c => c.default || c))`
}) || []
return [
'import { defineAsyncComponent } from \'vue\'',
'export const islandComponents = import.meta.client ? {} : {',
islands.map(
(c) => {
const exp = c.export === 'default' ? 'c.default || c' : `c['${c.export}']`
const comment = createImportMagicComments(c)
return ` "${c.pascalName}": defineAsyncComponent(${genDynamicImport(c.filePath, { comment })}.then(c => ${exp}))`
}
).concat(pageExports).join(',\n'),
'}'
].join('\n')
}
}
export const componentsTypeTemplate = {
filename: 'components.d.ts' as const,
getContents: ({ app, nuxt }) => {
const buildDir = nuxt.options.buildDir
const componentTypes = app.components.filter(c => !c.island).map(c => [
c.pascalName,
`typeof ${genDynamicImport(isAbsolute(c.filePath)
? relative(buildDir, c.filePath).replace(/(?<=\w)\.(?!vue)\w+$/g, '')
: c.filePath.replace(/(?<=\w)\.(?!vue)\w+$/g, ''), { wrapper: false })}['${c.export}']`
])
return `// Generated by components discovery
declare module 'vue' {
export interface GlobalComponents {
${componentTypes.map(([pascalName, type]) => ` '${pascalName}': ${type}`).join('\n')}
${componentTypes.map(([pascalName, type]) => ` 'Lazy${pascalName}': ${type}`).join('\n')}
}
}
${componentTypes.map(([pascalName, type]) => `export const ${pascalName}: ${type}`).join('\n')}
${componentTypes.map(([pascalName, type]) => `export const Lazy${pascalName}: ${type}`).join('\n')}
export const componentNames: string[]
`
}
} satisfies NuxtTemplate
export const componentsMetadataTemplate: NuxtTemplate = {
filename: 'components.json',
write: true,
getContents: ({ app }) => JSON.stringify(app.components, null, 2)
}