-
-
Notifications
You must be signed in to change notification settings - Fork 31
Expand file tree
/
Copy pathloader.ts
More file actions
166 lines (148 loc) Β· 5.74 KB
/
loader.ts
File metadata and controls
166 lines (148 loc) Β· 5.74 KB
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import { normalize, resolve } from 'node:path'
import type { Nuxt } from '@nuxt/schema'
import defu from 'defu'
import { debounce } from 'perfect-debounce'
import { addVitePlugin, isIgnored } from '@nuxt/kit'
import type { ModuleNode } from 'vite'
import { watch as chokidarWatch } from 'chokidar'
import type { VOptions, VuetifyModuleOptions } from '../types'
import { RESOLVED_VIRTUAL_MODULES } from '../vite/constants'
import { mergeVuetifyModules } from './layers'
import { cleanupBlueprint, detectDate, resolveVuetifyComponents } from './module'
import { prepareIcons } from './icons'
import type { VuetifyNuxtContext } from './config'
import { prepareSSRClientHints } from './ssr-client-hints'
export async function load(
options: VuetifyModuleOptions,
nuxt: Nuxt,
ctx: VuetifyNuxtContext,
) {
const {
configuration,
vuetifyConfigurationFilesToWatch,
} = await mergeVuetifyModules(options, nuxt)
// we only need to load json files once
if (typeof ctx.componentsPromise === 'undefined') {
const {
componentsPromise,
labComponentsPromise,
} = resolveVuetifyComponents(ctx.resolver)
ctx.componentsPromise = componentsPromise
ctx.labComponentsPromise = labComponentsPromise
}
const { vuetifyOptions = {} } = configuration
const {
directives: _directives,
labComponents: _labComponents,
...vOptions
} = vuetifyOptions
// Prepare options for the runtime plugin
const vuetifyAppOptions = <VOptions>defu(vOptions, {})
cleanupBlueprint(vuetifyAppOptions)
ctx.dateAdapter = undefined
const dateOptions = vuetifyOptions.date
if (dateOptions) {
const adapter = dateOptions.adapter
const date = detectDate()
if (!adapter && date.length > 1)
throw new Error(`Multiple date adapters found: ${date.map(d => `@date-io/${d[0]}`).join(', ')}, please specify the adapter to use in the "vuetifyOptions.date.adapter" option.`)
if (adapter) {
if (adapter === 'vuetify' || adapter === 'custom') {
ctx.dateAdapter = adapter
}
else {
if (date.find(d => d === adapter) === undefined)
ctx.logger.warn(`[vuetify-nuxt-module] Ignoring Vuetify Date configuration, date adapter "@date-io/${adapter}" not installed!`)
else
ctx.dateAdapter = adapter
}
}
else if (date.length === 0) {
ctx.dateAdapter = 'vuetify'
}
else {
ctx.dateAdapter = date[0]
}
}
/* handle old stuff */
const oldIcons = ctx.icons
if (oldIcons && oldIcons.cdn?.length && nuxt.options.app.head.link)
nuxt.options.app.head.link = nuxt.options.app.head.link.filter(link => !link.key || !oldIcons.cdn.some(([key]) => link.key === key))
/* handle new stuff */
ctx.moduleOptions = configuration.moduleOptions!
ctx.vuetifyOptions = configuration.vuetifyOptions!
ctx.vuetifyFilesToWatch = Array.from(vuetifyConfigurationFilesToWatch).map(f => normalize(f))
ctx.icons = prepareIcons(ctx.unocss, ctx.logger, vuetifyAppOptions)
ctx.ssrClientHints = prepareSSRClientHints(nuxt.options.app.baseURL ?? '/', ctx)
if (ctx.icons.enabled) {
ctx.icons.local?.forEach(css => nuxt.options.css.push(css))
if (ctx.icons.cdn?.length) {
nuxt.options.app.head.link ??= []
ctx.icons.cdn.forEach(([key, href]) => nuxt.options.app.head.link!.push({
key,
rel: 'stylesheet',
href,
type: 'text/css',
crossorigin: 'anonymous',
}))
}
}
}
export function registerWatcher(options: VuetifyModuleOptions, nuxt: Nuxt, ctx: VuetifyNuxtContext) {
if (nuxt.options.dev) {
let pageReload: (() => Promise<void>) | undefined
// setup watcher when using compatibilityVersion - files outside srcDir are not watched
if (nuxt.options.future?.compatibilityVersion === 4) {
const watcher = chokidarWatch(
ctx.vuetifyFilesToWatch.map(f => normalize(resolve(nuxt.options.srcDir, f))),
{
awaitWriteFinish: true,
ignoreInitial: true,
ignored: [isIgnored, 'node_modules'],
},
)
const ssr = nuxt.options.ssr
watcher.on('all', (event, path) => nuxt.callHook('builder:watch', event, normalize(path)))
nuxt.hook('close', () => watcher?.close())
nuxt.hooks.hook('builder:watch', (_event, path) => {
path = normalize(path)
if (ctx.vuetifyFilesToWatch.includes(path))
return !ssr && typeof pageReload === 'function' ? pageReload() : nuxt.callHook('restart')
})
}
else {
nuxt.hooks.hook('builder:watch', (_event, path) => {
path = normalize(resolve(nuxt.options.srcDir, path))
if (!pageReload && ctx.vuetifyFilesToWatch.includes(path))
return nuxt.callHook('restart')
})
// on v4 this is not called
addVitePlugin({
name: 'vuetify:configuration:watch',
enforce: 'pre',
handleHotUpdate({ file }) {
if (pageReload && ctx.vuetifyFilesToWatch.includes(normalize(file)))
return pageReload()
},
})
}
nuxt.hook('vite:serverCreated', (server, { isClient }) => {
if (!server.ws || !isClient)
return
pageReload = debounce(async () => {
const modules: ModuleNode[] = []
for (const v of RESOLVED_VIRTUAL_MODULES) {
const module = server.moduleGraph.getModuleById(v)
if (module)
modules.push(module)
}
// reload configuration always
await load(options, nuxt, ctx)
// TODO: try to change the logic here with custom event and using the moduleGraph + client invalidation
// server.reloadModule will send at least 2 or 3 full page reloads in a row: it is better than server restart
if (modules.length)
await Promise.all(modules.map(m => server.reloadModule(m)))
}, 50, { trailing: false })
})
}
}