vuetify-nuxt-module 0.19.5 → 1.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/module.mjs CHANGED
@@ -1,23 +1,23 @@
1
- import { addVitePlugin, addPluginTemplate, extendWebpackConfig, isNuxtMajorVersion, addImports, addPlugin, useLogger, defineNuxtModule, getNuxtVersion, hasNuxtModule, createResolver } from '@nuxt/kit';
1
+ import { addPluginTemplate, addTemplate, resolvePath, extendWebpackConfig, isNuxtMajorVersion, addImports, addPlugin, addVitePlugin, useLogger, defineNuxtModule, getNuxtVersion, hasNuxtModule, createResolver } from '@nuxt/kit';
2
2
  import { isPackageExists, getPackageInfo } from 'local-pkg';
3
3
  import semver from 'semver';
4
4
  import { createFilter, version as version$1 } from 'vite';
5
- import { resolve, dirname, relative } from 'node:path';
6
5
  import defu from 'defu';
7
- import { debounce } from 'perfect-debounce';
6
+ import { transformAssetUrls } from 'vite-plugin-vuetify';
7
+ import { pathToFileURL } from 'node:url';
8
+ import { generateImports, resolveVuetifyBase, isObject, normalizePath } from '@vuetify/loader-shared';
9
+ import destr from 'destr';
10
+ import { isAbsolute, relative } from 'pathe';
11
+ import { parseQuery, parseURL } from 'ufo';
8
12
  import fs, { existsSync, statSync } from 'node:fs';
9
- import process from 'node:process';
10
- import { createConfigLoader } from 'unconfig';
11
13
  import fsp, { readFile } from 'node:fs/promises';
12
- import { resolveVuetifyBase, isObject, normalizePath, generateImports } from '@vuetify/loader-shared';
13
- import { pathToFileURL } from 'node:url';
14
- import { relative as relative$1, isAbsolute } from 'pathe';
15
14
  import path from 'upath';
16
- import { transformAssetUrls } from 'vite-plugin-vuetify';
17
- import { parseQuery, parseURL } from 'ufo';
18
- import destr from 'destr';
15
+ import { resolve, dirname, relative as relative$1 } from 'node:path';
16
+ import { debounce } from 'perfect-debounce';
17
+ import process from 'node:process';
18
+ import { createConfigLoader } from 'unconfig';
19
19
 
20
- const version = "0.19.5";
20
+ const version = "1.0.0-alpha.2";
21
21
 
22
22
  const VIRTUAL_VUETIFY_CONFIGURATION = "virtual:vuetify-configuration";
23
23
  const RESOLVED_VIRTUAL_VUETIFY_CONFIGURATION = `\0${VIRTUAL_VUETIFY_CONFIGURATION}`;
@@ -34,675 +34,280 @@ const RESOLVED_VIRTUAL_MODULES = [
34
34
  RESOLVED_VIRTUAL_VUETIFY_SSR_CLIENT_HINTS_CONFIGURATION
35
35
  ];
36
36
 
37
- async function loadVuetifyConfiguration(cwd = process.cwd(), configOrPath = cwd, defaults = {}, extraConfigSources = []) {
38
- let inlineConfig = {};
39
- if (typeof configOrPath !== "string") {
40
- inlineConfig = configOrPath;
41
- configOrPath = process.cwd();
37
+ function toKebabCase(str = "") {
38
+ if (toKebabCase.cache.has(str)) {
39
+ return toKebabCase.cache.get(str);
42
40
  }
43
- const resolved = resolve(cwd, configOrPath);
44
- let isFile = false;
45
- if (existsSync(resolved) && statSync(resolved).isFile()) {
46
- isFile = true;
47
- cwd = dirname(resolved).replace(/\\/g, "/");
41
+ const kebab = str.replace(/[^a-z]/gi, "-").replace(/\B([A-Z])/g, "-$1").toLowerCase();
42
+ toKebabCase.cache.set(str, kebab);
43
+ return kebab;
44
+ }
45
+ toKebabCase.cache = /* @__PURE__ */ new Map();
46
+ function camelize(str) {
47
+ if (camelize.cache.has(str)) {
48
+ return camelize.cache.get(str);
48
49
  }
49
- const rewrite = (config) => {
50
- if (typeof config === "function")
51
- return config();
52
- return config;
53
- };
54
- const loader = createConfigLoader({
55
- sources: isFile ? [
56
- {
57
- files: resolved,
58
- extensions: [],
59
- rewrite
60
- }
61
- ] : [
62
- {
63
- files: [
64
- "vuetify.config"
65
- ],
66
- // we don't want `package.json` to be loaded
67
- extensions: ["mts", "cts", "ts", "mjs", "cjs", "js"],
68
- rewrite
69
- },
70
- ...extraConfigSources
71
- ],
72
- cwd,
73
- defaults: inlineConfig,
74
- merge: false
75
- });
76
- const result = await loader.load();
77
- if (result.config?.config === false)
78
- result.config = Object.assign(defaults, inlineConfig);
79
- else
80
- result.config = Object.assign(defaults, result.config || inlineConfig);
81
- delete result.config.config;
82
- return result;
50
+ const camel = str.replace(/-([a-z0-9])/g, (g) => g[1].toUpperCase());
51
+ camelize.cache.set(str, camel);
52
+ return camel;
83
53
  }
84
-
85
- async function mergeVuetifyModules(options, nuxt) {
86
- const moduleOptions = [];
87
- const vuetifyConfigurationFilesToWatch = /* @__PURE__ */ new Set();
88
- await nuxt.callHook("vuetify:registerModule", (layerModuleOptions) => moduleOptions.push(layerModuleOptions));
89
- if (nuxt.options._layers.length > 1) {
90
- for (let i = 1; i < nuxt.options._layers.length; i++) {
91
- const layer = nuxt.options._layers[i];
92
- const resolvedOptions2 = await loadVuetifyConfiguration(
93
- layer.config.rootDir,
94
- layer.config.vuetify?.vuetifyOptions
95
- );
96
- if (resolvedOptions2.sources.length) {
97
- resolvedOptions2.sources.map((s) => s.replace(/\\/g, "/")).filter((s) => !s.includes("/node_modules/")).forEach((s) => vuetifyConfigurationFilesToWatch.add(s));
98
- }
99
- moduleOptions.push({
100
- moduleOptions: layer.config.vuetify?.moduleOptions,
101
- vuetifyOptions: resolvedOptions2.config
102
- });
103
- }
54
+ camelize.cache = /* @__PURE__ */ new Map();
55
+ function pascalize(str) {
56
+ if (pascalize.cache.has(str)) {
57
+ return pascalize.cache.get(str);
104
58
  }
105
- const resolvedOptions = await loadVuetifyConfiguration(
106
- nuxt.options.rootDir,
107
- options.vuetifyOptions
108
- );
109
- if (nuxt.options.dev && resolvedOptions.sources.length) {
110
- if (nuxt.options.ssr)
111
- resolvedOptions.sources.forEach((s) => nuxt.options.watch.push(s.replace(/\\/g, "/")));
112
- else
113
- resolvedOptions.sources.forEach((s) => vuetifyConfigurationFilesToWatch.add(s.replace(/\\/g, "/")));
59
+ let pascal = camelize(str);
60
+ pascal = pascal.slice(0, 1).toUpperCase() + pascal.slice(1);
61
+ pascalize.cache.set(str, pascal);
62
+ return pascal;
63
+ }
64
+ pascalize.cache = /* @__PURE__ */ new Map();
65
+ function createTransformAssetUrls(ctx, viteInlineConfig) {
66
+ const { includeTransformAssetsUrls } = ctx.moduleOptions;
67
+ if (!includeTransformAssetsUrls) {
68
+ return void 0;
114
69
  }
115
- moduleOptions.unshift({
116
- moduleOptions: options.moduleOptions,
117
- vuetifyOptions: resolvedOptions.config
118
- });
119
- if (moduleOptions.length > 1) {
120
- const [app, ...rest] = moduleOptions;
121
- const configuration = defu(app, ...rest);
122
- dedupeIcons(configuration, moduleOptions.reverse());
123
- return {
124
- configuration,
125
- vuetifyConfigurationFilesToWatch
126
- };
127
- } else {
128
- return {
129
- configuration: {
130
- moduleOptions: options.moduleOptions,
131
- vuetifyOptions: resolvedOptions.config
132
- },
133
- vuetifyConfigurationFilesToWatch
70
+ let existingTransformAssetUrls = viteInlineConfig.vue?.template?.transformAssetUrls ?? {};
71
+ let useURLOptions;
72
+ if (typeof existingTransformAssetUrls === "boolean") {
73
+ existingTransformAssetUrls = {};
74
+ } else if ("base" in existingTransformAssetUrls || "includeAbsolute" in existingTransformAssetUrls || "tags" in existingTransformAssetUrls) {
75
+ useURLOptions = {
76
+ base: existingTransformAssetUrls.base,
77
+ includeAbsolute: existingTransformAssetUrls.includeAbsolute
134
78
  };
79
+ existingTransformAssetUrls = existingTransformAssetUrls.tags ?? {};
135
80
  }
136
- }
137
- function dedupeIcons(configuration, moduleOptions) {
138
- const vuetifyOptions = configuration.vuetifyOptions;
139
- if (vuetifyOptions.icons) {
140
- if (vuetifyOptions.icons.sets) {
141
- const sets = /* @__PURE__ */ new Map();
142
- for (const { vuetifyOptions: vuetifyOptions2 } of moduleOptions) {
143
- if (vuetifyOptions2.icons && vuetifyOptions2.icons.sets) {
144
- const mSets = vuetifyOptions2.icons.sets;
145
- if (typeof mSets === "string") {
146
- sets.set(mSets, { name: mSets });
147
- } else {
148
- for (const set of mSets) {
149
- if (typeof set === "string")
150
- sets.set(set, { name: set });
151
- else
152
- sets.set(set.name, set);
153
- }
154
- }
155
- }
156
- }
157
- vuetifyOptions.icons.sets = Array.from(sets.values());
158
- }
81
+ const transformAssetUrls$1 = normalizeTransformAssetUrls(
82
+ typeof includeTransformAssetsUrls === "object" ? defu(existingTransformAssetUrls, transformAssetUrls, includeTransformAssetsUrls) : defu(existingTransformAssetUrls, transformAssetUrls)
83
+ );
84
+ if (!useURLOptions) {
85
+ return transformAssetUrls$1;
159
86
  }
87
+ useURLOptions.tags = transformAssetUrls$1;
88
+ return useURLOptions;
160
89
  }
161
-
162
- function detectDate() {
163
- const result = [];
164
- [
165
- "date-fns",
166
- "moment",
167
- "luxon",
168
- "dayjs",
169
- "js-joda",
170
- "date-fns-jalali",
171
- "jalaali",
172
- "hijri"
173
- ].forEach((adapter) => {
174
- if (isPackageExists(`@date-io/${adapter}`))
175
- result.push(adapter);
176
- });
177
- return result;
178
- }
179
- function cleanupBlueprint(vuetifyOptions) {
180
- const blueprint = vuetifyOptions.blueprint;
181
- if (blueprint) {
182
- delete blueprint.ssr;
183
- delete blueprint.components;
184
- delete blueprint.directives;
185
- delete blueprint.locale;
186
- delete blueprint.date;
187
- delete blueprint.icons;
188
- vuetifyOptions.blueprint = blueprint;
90
+ function normalizeTransformAssetUrls(transformAssetUrls) {
91
+ const names = new Set(Object.keys(transformAssetUrls));
92
+ let kebab;
93
+ let pascal;
94
+ for (const name of names) {
95
+ transformAssetUrls[name] = normalizeTransformAssetUrlsAttrs(transformAssetUrls[name]);
96
+ kebab = toKebabCase(name);
97
+ pascal = pascalize(name);
98
+ if (!names.has(kebab)) {
99
+ transformAssetUrls[kebab] = [...transformAssetUrls[name]];
100
+ }
101
+ if (!names.has(pascal)) {
102
+ transformAssetUrls[pascal] = [...transformAssetUrls[name]];
103
+ }
189
104
  }
105
+ return transformAssetUrls;
190
106
  }
191
- function checkVuetifyPlugins(config) {
192
- let plugin = config.plugins?.find((p) => p && typeof p === "object" && "name" in p && p.name === "vuetify:import");
193
- if (plugin)
194
- throw new Error("Remove vite-plugin-vuetify plugin from Vite Plugins entry in Nuxt config file!");
195
- plugin = config.plugins?.find((p) => p && typeof p === "object" && "name" in p && p.name === "vuetify:styles");
196
- if (plugin)
197
- throw new Error("Remove vite-plugin-vuetify plugin from Vite Plugins entry in Nuxt config file!");
198
- }
199
- function resolveVuetifyComponents(resolver) {
200
- const vuetifyBase = resolveVuetifyBase();
201
- const componentsPromise = importMapResolver();
202
- const labComponentsPromise = importMapLabResolver();
203
- return {
204
- vuetifyBase,
205
- componentsPromise,
206
- labComponentsPromise
207
- };
208
- async function importMapResolver() {
209
- return JSON.parse(await readFile(resolver.resolve(vuetifyBase, "dist/json/importMap.json"), "utf-8")).components;
210
- }
211
- async function importMapLabResolver() {
212
- return JSON.parse(await readFile(resolver.resolve(vuetifyBase, "dist/json/importMap-labs.json"), "utf-8")).components;
107
+ function normalizeTransformAssetUrlsAttrs(attrs) {
108
+ const result = /* @__PURE__ */ new Set();
109
+ let kebab;
110
+ let camel;
111
+ let bind;
112
+ let idx;
113
+ for (const attr of attrs) {
114
+ result.add(attr);
115
+ idx = attr.indexOf(":");
116
+ if (idx > 0) {
117
+ continue;
118
+ }
119
+ bind = idx === 0;
120
+ kebab = toKebabCase(bind ? attr.slice(1) : attr);
121
+ camel = camelize(bind ? attr.slice(1) : attr);
122
+ result.add(kebab);
123
+ result.add(camel);
124
+ result.add(`:${kebab}`);
125
+ result.add(`:${camel}`);
213
126
  }
127
+ return [...result];
214
128
  }
215
129
 
216
- const cssFonts = ["unocss-mdi", "mdi", "md", "fa", "fa4"];
217
- const iconsPackageNames = {
218
- "unocss-mdi": { name: "@mdi/font", css: "" },
219
- "mdi": { name: "@mdi/font", css: "@mdi/font/css/materialdesignicons.css" },
220
- "md": { name: "material-design-icons-iconfont", css: "@mdi/font/css/materialdesignicons.css" },
221
- "fa": { name: "@fortawesome/fontawesome-free", css: "@fortawesome/fontawesome-free/css/all.css" },
222
- "fa4": { name: "font-awesome@4.7.0", css: "font-awesome/css/font-awesome.min.css" }
223
- };
224
- const iconsCDN = {
225
- "unocss-mdi": "",
226
- "mdi": "https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css",
227
- "md": "https://fonts.googleapis.com/css?family=Material+Icons",
228
- "fa": "https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@latest/css/all.min.css",
229
- "fa4": "https://cdn.jsdelivr.net/npm/font-awesome@4.x/css/font-awesome.min.css"
230
- };
231
- const disabledResolvedIcons = Object.freeze({
232
- enabled: false,
233
- unocss: false,
234
- unocssAliases: false,
235
- unocssIconPrefix: "i-",
236
- unocssIcons: {},
237
- unocssAdditionalIcons: {},
238
- imports: [],
239
- aliases: [],
240
- aliasesImportPresent: false,
241
- sets: [],
242
- cdn: [],
243
- local: [],
244
- svg: {}
245
- });
246
- function prepareIcons(unocssPresent, logger, vuetifyOptions) {
247
- if (vuetifyOptions.icons === false)
248
- return disabledResolvedIcons;
249
- const icons = vuetifyOptions.icons || {};
250
- let { defaultSet = "mdi", sets } = icons;
251
- if (!defaultSet)
252
- defaultSet = icons.defaultSet = "mdi";
253
- if (!sets && defaultSet !== "mdi-svg" && defaultSet !== "fa-svg" && defaultSet !== "custom")
254
- sets = [{ name: defaultSet || "mdi" }];
255
- sets = sets ? convertFontSetsToObjectNotation(sets) : [];
256
- const resolvedIcons = {
257
- enabled: true,
258
- unocss: unocssPresent && (defaultSet === "unocss-mdi" || sets.some((s) => s.name === "unocss-mdi")),
259
- unocssAliases: defaultSet === "unocss-mdi",
260
- unocssIconPrefix: icons.unocssIconPrefix ?? "i-",
261
- unocssIcons: icons.unocssIcons ?? {},
262
- unocssAdditionalIcons: icons.unocssAdditionalIcons ?? {},
263
- defaultSet,
264
- sets: [],
265
- aliases: [],
266
- aliasesImportPresent: false,
267
- imports: [],
268
- cdn: [],
269
- local: [],
270
- svg: {
271
- mdi: false
272
- }
273
- };
274
- if (sets) {
275
- if (!unocssPresent && defaultSet === "unocss-mdi") {
276
- logger.warn("Configured unocss-mdi as default icon set and @unocss/nuxt is not installed, reverting configuration to use mdi icon set: install @unocss/nuxt module or change the default icon set!");
277
- defaultSet = "mdi";
278
- sets = sets.filter((s) => s.name !== "unocss-mdi");
279
- }
280
- sets.filter((s) => cssFonts.includes(s.name)).forEach(({ name, cdn }) => {
281
- resolvedIcons.aliasesImportPresent ||= name === defaultSet;
282
- if (name === "unocss-mdi")
283
- return;
284
- resolvedIcons.imports.push(`import {${name === defaultSet ? "aliases," : ""}${name}} from 'vuetify/iconsets/${name}'`);
285
- resolvedIcons.sets.push(name);
286
- if (isPackageExists(iconsPackageNames[name].name))
287
- resolvedIcons.local.push(iconsPackageNames[name].css);
288
- else
289
- resolvedIcons.cdn.push([name, cdn ?? iconsCDN[name]]);
290
- });
291
- if (resolvedIcons.unocss && defaultSet === "unocss-mdi") {
292
- if (!resolvedIcons.sets.includes("mdi")) {
293
- resolvedIcons.sets.push("mdi");
294
- resolvedIcons.imports.push("import {mdi} from 'vuetify/iconsets/mdi'");
130
+ function addVuetifyNuxtPlugins(nuxt, ctx) {
131
+ addVuetifyNuxtPlugin(nuxt, ctx, "client");
132
+ addVuetifyNuxtPlugin(nuxt, ctx, "server");
133
+ }
134
+ function addVuetifyNuxtPlugin(nuxt, ctx, mode) {
135
+ addPluginTemplate({
136
+ filename: `vuetify-nuxt-plugin.${mode}.mjs`,
137
+ name: `vuetify:nuxt:${mode}:plugin`,
138
+ write: false,
139
+ mode,
140
+ getContents() {
141
+ const dependsOn = ["vuetify:icons:plugin"];
142
+ if (ctx.ssrClientHints.enabled) {
143
+ if (mode === "client") {
144
+ dependsOn.push("vuetify:client-hints:client:plugin");
145
+ } else {
146
+ dependsOn.push("vuetify:client-hints:server:plugin");
147
+ }
295
148
  }
296
- resolvedIcons.defaultSet = "mdi";
297
- }
298
- }
299
- let faSvg = icons.svg?.fa;
300
- if (defaultSet === "fa-svg" || faSvg) {
301
- if (!faSvg)
302
- faSvg = {};
303
- let faSvgExists = isPackageExists("@fortawesome/fontawesome-svg-core");
304
- if (!faSvgExists)
305
- logger.warn("Missing @fortawesome/fontawesome-svg-core dependency, install it!");
306
- faSvgExists = isPackageExists("@fortawesome/vue-fontawesome");
307
- if (faSvgExists) {
308
- if (!faSvg.libraries?.length)
309
- faSvg.libraries = [[false, "fas", "@fortawesome/free-solid-svg-icons"]];
310
- for (const p in faSvg.libraries) {
311
- const [_defaultExport, _name, library] = faSvg.libraries[p];
312
- if (!isPackageExists(library)) {
313
- faSvgExists = false;
314
- logger.warn(`Missing library ${library} dependency, install it!`);
149
+ if (ctx.i18n) {
150
+ dependsOn.push("vuetify:i18n:plugin");
151
+ }
152
+ if (nuxt.options.dev || ctx.dateAdapter) {
153
+ if (ctx.i18n) {
154
+ dependsOn.push("vuetify:date-i18n:plugin");
155
+ } else {
156
+ dependsOn.push("vuetify:date:plugin");
315
157
  }
316
158
  }
317
- } else {
318
- logger.warn("Missing @fortawesome/vue-fontawesome dependency, install it!");
319
- }
320
- if (faSvgExists) {
321
- resolvedIcons.aliasesImportPresent ||= defaultSet === "fa-svg";
322
- resolvedIcons.imports.push(`import {${defaultSet === "fa-svg" ? "aliases," : ""}fa} from 'vuetify/iconsets/fa-svg'`);
323
- resolvedIcons.imports.push("import { library } from '@fortawesome/fontawesome-svg-core'");
324
- resolvedIcons.imports.push("import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'");
325
- resolvedIcons.imports.push("import { useNuxtApp } from '#imports'");
326
- resolvedIcons.svg.fa = ["useNuxtApp().vueApp.component('font-awesome-icon', FontAwesomeIcon)"];
327
- faSvg.libraries.forEach(([defaultExport, name, library]) => {
328
- resolvedIcons.imports.push(`import ${defaultExport ? name : `{${name}}`} from '${library}'`);
329
- resolvedIcons.svg.fa.push(`library.add(${name})`);
330
- });
331
- resolvedIcons.sets.push("fa");
332
- if (defaultSet === "fa-svg")
333
- resolvedIcons.defaultSet = "fa";
334
- }
335
- }
336
- let mdiSvg = icons.svg?.mdi;
337
- if (defaultSet === "mdi-svg" || mdiSvg) {
338
- if (!mdiSvg)
339
- mdiSvg = {};
340
- const mdiSvgExists = isPackageExists("@mdi/js");
341
- if (mdiSvgExists) {
342
- resolvedIcons.svg.mdi = true;
343
- resolvedIcons.aliasesImportPresent ||= defaultSet === "mdi-svg";
344
- resolvedIcons.imports.push(`import {${defaultSet === "mdi-svg" ? "aliases," : ""}mdi} from 'vuetify/iconsets/mdi-svg'`);
345
- if (mdiSvg && mdiSvg.aliases) {
346
- resolvedIcons.imports.push(`import {${Object.values(mdiSvg.aliases).join(",")}} from '@mdi/js'`);
347
- Object.entries(mdiSvg.aliases).forEach(([alias, icon]) => {
348
- resolvedIcons.aliases.push(`${alias}: ${icon}`);
349
- });
159
+ let rulesImports = "";
160
+ let rulesPlugin = "";
161
+ if (mode === "client" && ctx.enableRules) {
162
+ rulesImports = [
163
+ "",
164
+ `import { rulesOptions } from '#build/vuetify/${ctx.rulesConfiguration.fromLabs ? "labs-" : ""}rules-configuration.mjs'`,
165
+ `import { createRulesPlugin } from 'vuetify/${ctx.rulesConfiguration.fromLabs ? "labs/" : ""}rules'`
166
+ ].join("\n");
167
+ rulesPlugin = [
168
+ "",
169
+ " nuxtApp.vueApp.use(createRulesPlugin(rulesOptions, vuetify.locale))"
170
+ ].join("\n");
350
171
  }
351
- resolvedIcons.sets.push("mdi");
352
- if (defaultSet === "mdi-svg")
353
- resolvedIcons.defaultSet = "mdi";
354
- } else {
355
- resolvedIcons.svg.mdi = false;
356
- logger.warn("Missing @mdi/js dependency, install it!");
357
- }
358
- }
359
- if (defaultSet !== "custom" && !resolvedIcons.unocss && !resolvedIcons.local?.length && !resolvedIcons.cdn?.length && !resolvedIcons.svg?.mdi && !resolvedIcons.svg?.fa?.length) {
360
- logger.warn("No icons found, icons disabled!");
361
- return disabledResolvedIcons;
362
- }
363
- return resolvedIcons;
364
- }
365
- function convertFontSetsToObjectNotation(sets) {
366
- const result = [];
367
- if (typeof sets === "string") {
368
- result.push({ name: sets });
369
- } else {
370
- for (const set of sets) {
371
- if (typeof set === "string")
372
- result.push({ name: set });
373
- else
374
- result.push(set);
172
+ return `
173
+ import { defineNuxtPlugin } from '#imports'
174
+ import { isDev, vuetifyConfiguration } from 'virtual:vuetify-configuration'
175
+ import { createVuetify } from 'vuetify'${rulesImports}
176
+
177
+ export default defineNuxtPlugin({
178
+ name: 'vuetify:nuxt:${mode}:plugin',
179
+ order: 25,
180
+ dependsOn: ${JSON.stringify(dependsOn)},
181
+ parallel: true,
182
+ async setup(nuxtApp) {
183
+ const vuetifyOptions = vuetifyConfiguration()
184
+ await nuxtApp.hooks.callHook('vuetify:configuration', { isDev, vuetifyOptions })
185
+ await nuxtApp.hooks.callHook('vuetify:before-create', { isDev, vuetifyOptions })
186
+ const vuetify = createVuetify(vuetifyOptions)
187
+ nuxtApp.vueApp.use(vuetify)${rulesPlugin}
188
+ nuxtApp.provide('vuetify', vuetify)
189
+ await nuxtApp.hooks.callHook('vuetify:ready', vuetify)
190
+ },
191
+ })
192
+ `;
375
193
  }
376
- }
377
- return result;
194
+ });
378
195
  }
379
196
 
380
- const disabledClientHints = Object.freeze({
381
- enabled: false,
382
- reloadOnFirstRequest: false,
383
- viewportSize: false,
384
- prefersColorScheme: false,
385
- prefersReducedMotion: false
386
- });
387
- function prepareSSRClientHints(baseUrl, ctx) {
388
- if (!ctx.isSSR || ctx.isNuxtGenerate)
389
- return disabledClientHints;
390
- const { ssrClientHints: ssrClientHintsConfiguration } = ctx.moduleOptions;
391
- const clientHints = {
392
- enabled: false,
393
- reloadOnFirstRequest: ssrClientHintsConfiguration?.reloadOnFirstRequest ?? false,
394
- viewportSize: ssrClientHintsConfiguration?.viewportSize ?? false,
395
- prefersColorScheme: ssrClientHintsConfiguration?.prefersColorScheme ?? false,
396
- prefersReducedMotion: ssrClientHintsConfiguration?.prefersReducedMotion ?? false
397
- };
398
- clientHints.enabled = clientHints.viewportSize || clientHints.prefersColorScheme || clientHints.prefersReducedMotion;
399
- if (clientHints.enabled && clientHints.prefersColorScheme && ssrClientHintsConfiguration?.prefersColorSchemeOptions) {
400
- const theme = ctx.vuetifyOptions.theme;
401
- if (!theme)
402
- throw new Error("Vuetify theme is disabled");
403
- const themes = theme.themes;
404
- if (!themes)
405
- throw new Error("Vuetify themes is missing in theme!");
406
- const defaultTheme = theme.defaultTheme;
407
- if (!defaultTheme)
408
- throw new Error("Vuetify default theme is missing in theme!");
409
- if (!themes[defaultTheme])
410
- throw new Error(`Missing default theme ${defaultTheme} in the Vuetify themes!`);
411
- const darkThemeName = ssrClientHintsConfiguration.prefersColorSchemeOptions?.darkThemeName ?? "dark";
412
- if (!themes[darkThemeName])
413
- throw new Error(`Missing theme ${darkThemeName} in the Vuetify themes!`);
414
- const lightThemeName = ssrClientHintsConfiguration.prefersColorSchemeOptions?.lightThemeName ?? "light";
415
- if (!themes[lightThemeName])
416
- throw new Error(`Missing theme ${lightThemeName} in the Vuetify themes!`);
417
- if (darkThemeName === lightThemeName)
418
- throw new Error("Vuetify dark theme and light theme are the same, change darkThemeName or lightThemeName!");
419
- clientHints.prefersColorSchemeOptions = {
420
- baseUrl,
421
- defaultTheme,
422
- themeNames: Array.from(Object.keys(themes)),
423
- cookieName: ssrClientHintsConfiguration.prefersColorSchemeOptions?.cookieName ?? "color-scheme",
424
- darkThemeName,
425
- lightThemeName,
426
- useBrowserThemeOnly: ssrClientHintsConfiguration.prefersColorSchemeOptions?.useBrowserThemeOnly ?? false
427
- };
428
- }
429
- return clientHints;
197
+ function getTemplate(source, settings) {
198
+ return [settings ? `@use '${settings}';` : "", `@use '${source}';`].filter(Boolean).join("\n");
430
199
  }
431
-
432
- async function load(options, nuxt, ctx) {
200
+ async function configureNuxt(configKey, nuxt, ctx) {
433
201
  const {
434
- configuration,
435
- vuetifyConfigurationFilesToWatch
436
- } = await mergeVuetifyModules(options, nuxt);
437
- if (typeof ctx.componentsPromise === "undefined") {
438
- const {
439
- componentsPromise,
440
- labComponentsPromise
441
- } = resolveVuetifyComponents(ctx.resolver);
442
- ctx.componentsPromise = componentsPromise;
443
- ctx.labComponentsPromise = labComponentsPromise;
202
+ styles,
203
+ importComposables,
204
+ prefixComposables
205
+ } = ctx.moduleOptions;
206
+ const runtimeDir = ctx.resolver.resolve("./runtime");
207
+ if (ctx.enableRules !== void 0) {
208
+ ctx.enableRules = ctx.vuetifyGte("3.8.0");
444
209
  }
445
- const { vuetifyOptions = {} } = configuration;
446
- const {
447
- directives: _directives,
448
- labComponents: _labComponents,
449
- ...vOptions
450
- } = vuetifyOptions;
451
- const vuetifyAppOptions = defu(vOptions, {});
452
- cleanupBlueprint(vuetifyAppOptions);
453
- ctx.dateAdapter = void 0;
454
- const dateOptions = vuetifyOptions.date;
455
- if (dateOptions) {
456
- const adapter = dateOptions.adapter;
457
- const date = detectDate();
458
- if (!adapter && date.length > 1)
459
- 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.`);
460
- if (adapter) {
461
- if (adapter === "vuetify" || adapter === "custom") {
462
- ctx.dateAdapter = adapter;
463
- } else {
464
- if (date.find((d) => d === adapter) === void 0)
465
- ctx.logger.warn(`[vuetify-nuxt-module] Ignoring Vuetify Date configuration, date adapter "@date-io/${adapter}" not installed!`);
466
- else
467
- ctx.dateAdapter = adapter;
210
+ if (styles !== "none" && styles !== false) {
211
+ nuxt.options.css ??= [];
212
+ if (typeof styles === "object" && "configFile" in styles) {
213
+ const a = addTemplate({
214
+ filename: "vuetify.settings.scss",
215
+ getContents: async () => getTemplate("vuetify/styles", await resolvePath(styles.configFile))
216
+ });
217
+ nuxt.options.css.push(a.dst);
218
+ } else if (ctx.vuetifyGte("4.0.0")) {
219
+ nuxt.options.css.push(await resolvePath("vuetify/styles/core"));
220
+ if (typeof styles === "object" && styles?.utilities !== false) {
221
+ nuxt.options.css.push(await resolvePath("vuetify/styles/utilities"));
222
+ }
223
+ if (typeof styles === "object" && styles?.colors !== false) {
224
+ nuxt.options.css.push(await resolvePath("vuetify/styles/colors"));
468
225
  }
469
- } else if (date.length === 0) {
470
- ctx.dateAdapter = "vuetify";
471
226
  } else {
472
- ctx.dateAdapter = date[0];
227
+ nuxt.options.css.push(await resolvePath("vuetify/styles"));
473
228
  }
474
229
  }
475
- const oldIcons = ctx.icons;
476
- if (oldIcons && oldIcons.cdn?.length && nuxt.options.app.head.link)
477
- nuxt.options.app.head.link = nuxt.options.app.head.link.filter((link) => !link.key || !oldIcons.cdn.some(([key]) => link.key === key));
478
- ctx.moduleOptions = configuration.moduleOptions;
479
- ctx.vuetifyOptions = configuration.vuetifyOptions;
480
- ctx.enableRules = ctx.moduleOptions.enableRules;
481
- ctx.rulesConfiguration = ctx.moduleOptions.rulesConfiguration;
482
- ctx.vuetifyFilesToWatch = Array.from(vuetifyConfigurationFilesToWatch);
483
- ctx.icons = prepareIcons(ctx.unocss, ctx.logger, vuetifyAppOptions);
484
- ctx.ssrClientHints = prepareSSRClientHints(nuxt.options.app.baseURL ?? "/", ctx);
485
- if (ctx.icons.enabled) {
486
- ctx.icons.local?.forEach((css) => nuxt.options.css.push(css));
487
- if (ctx.icons.cdn?.length) {
488
- nuxt.options.app.head.link ??= [];
489
- ctx.icons.cdn.forEach(([key, href]) => nuxt.options.app.head.link.push({
490
- key,
491
- rel: "stylesheet",
492
- href,
493
- type: "text/css",
494
- crossorigin: "anonymous"
495
- }));
496
- }
230
+ nuxt.options.build.transpile.push(configKey, runtimeDir);
231
+ if (ctx.enableRules) {
232
+ nuxt.options.build.transpile.push(`#build/vuetify/${ctx.rulesConfiguration.fromLabs ? "labs-" : ""}rules-configuration.mjs`);
497
233
  }
498
- }
499
- function registerWatcher(options, nuxt, ctx) {
500
- if (nuxt.options.dev) {
501
- let pageReload;
502
- nuxt.hooks.hook("builder:watch", (_event, path) => {
503
- path = relative(nuxt.options.srcDir, resolve(nuxt.options.srcDir, path));
504
- if (!pageReload && ctx.vuetifyFilesToWatch.includes(path))
505
- return nuxt.callHook("restart");
506
- });
507
- nuxt.hook("vite:serverCreated", (server, { isClient }) => {
508
- if (!server.ws || !isClient)
509
- return;
510
- pageReload = debounce(async () => {
511
- const modules = [];
512
- for (const v of RESOLVED_VIRTUAL_MODULES) {
513
- const module = server.moduleGraph.getModuleById(v);
514
- if (module)
515
- modules.push(module);
516
- }
517
- await load(options, nuxt, ctx);
518
- if (modules.length)
519
- await Promise.all(modules.map((m) => server.reloadModule(m)));
520
- }, 50, { trailing: false });
521
- });
522
- addVitePlugin({
523
- name: "vuetify:configuration:watch",
524
- enforce: "pre",
525
- handleHotUpdate({ file }) {
526
- if (pageReload && ctx.vuetifyFilesToWatch.includes(file))
527
- return pageReload();
528
- }
529
- });
234
+ nuxt.options.build.transpile.push(/\/vuetify-nuxt-plugin\.(client|server)\.mjs$/);
235
+ nuxt.options.imports.transform ??= {};
236
+ nuxt.options.imports.transform.include ??= [];
237
+ for (const virtual of RESOLVED_VIRTUAL_MODULES) {
238
+ nuxt.options.imports.transform.include.push(new RegExp(`${virtual}$`));
530
239
  }
531
- }
532
-
533
- function vuetifyStylesPlugin(options, viteVersion, _logger) {
534
- let configFile;
535
- const vuetifyBase = resolveVuetifyBase();
536
- const noneFiles = /* @__PURE__ */ new Set();
537
- let isNone = false;
538
- let sassVariables = false;
539
- let fileImport = false;
540
- const PREFIX = "vuetify-styles/";
541
- const SSR_PREFIX = `/@${PREFIX}`;
542
- const resolveCss = resolveCssFactory();
543
- return {
544
- name: "vuetify:styles:nuxt",
545
- enforce: "pre",
546
- configResolved(config) {
547
- if (config.plugins.findIndex((plugin) => plugin.name === "vuetify:styles") > -1)
548
- throw new Error("Remove vite-plugin-vuetify from your Nuxt config file, this module registers a modified version.");
549
- if (isObject(options.styles)) {
550
- sassVariables = true;
551
- fileImport = semver.gt(viteVersion, "5.4.2");
552
- if (path.isAbsolute(options.styles.configFile))
553
- configFile = path.resolve(options.styles.configFile);
554
- else
555
- configFile = path.resolve(path.join(config.root || process.cwd(), options.styles.configFile));
556
- configFile = fileImport ? pathToFileURL(configFile).href : normalizePath(configFile);
557
- } else {
558
- isNone = options.styles === "none";
559
- }
560
- },
561
- async resolveId(source, importer, { custom, ssr }) {
562
- if (source.startsWith(PREFIX) || source.startsWith(SSR_PREFIX)) {
563
- if (source.match(/\.s[ca]ss$/))
564
- return source;
565
- const idx = source.indexOf("?");
566
- return idx > -1 ? source.slice(0, idx) : source;
567
- }
568
- if (source === "vuetify/styles" || importer && source.endsWith(".css") && isSubdir(vuetifyBase, path.isAbsolute(source) ? source : importer)) {
569
- if (options.styles === "sass")
570
- return this.resolve(await resolveCss(source), importer, { skipSelf: true, custom });
571
- const resolution = await this.resolve(source, importer, { skipSelf: true, custom });
572
- if (!resolution)
573
- return void 0;
574
- const target = await resolveCss(resolution.id);
575
- if (isNone) {
576
- noneFiles.add(target);
577
- return target;
578
- }
579
- return `${ssr ? SSR_PREFIX : PREFIX}${path.relative(vuetifyBase, target)}`;
580
- }
581
- return void 0;
582
- },
583
- load(id) {
584
- if (sassVariables) {
585
- const target = id.startsWith(PREFIX) ? path.resolve(vuetifyBase, id.slice(PREFIX.length)) : id.startsWith(SSR_PREFIX) ? path.resolve(vuetifyBase, id.slice(SSR_PREFIX.length)) : void 0;
586
- if (target) {
587
- const suffix = target.match(/\.scss/) ? ";\n" : "\n";
588
- return {
589
- code: `@use "${configFile}"${suffix}@use "${fileImport ? pathToFileURL(target).href : normalizePath(target)}"${suffix}`,
590
- map: {
591
- mappings: ""
592
- }
593
- };
594
- }
240
+ extendWebpackConfig(() => {
241
+ throw new Error("Webpack is not supported: vuetify-nuxt-module module can only be used with Vite!");
242
+ });
243
+ const v4Available = isNuxtMajorVersion(4, nuxt);
244
+ nuxt.hook("prepare:types", ({ references, nodeReferences }) => {
245
+ references.push({ types: "vuetify" }, { types: "vuetify-nuxt-module/custom-configuration" }, { types: "vuetify-nuxt-module/configuration" }, { path: ctx.resolver.resolve(runtimeDir, "plugins/types") });
246
+ if (ctx.enableRules) {
247
+ references.push({ types: `vuetify-nuxt-module/custom-${ctx.rulesConfiguration.fromLabs ? "labs-" : ""}rules-configuration` });
248
+ }
249
+ if (v4Available) {
250
+ nodeReferences.push({ types: "vuetify-nuxt-module/custom-configuration" });
251
+ if (ctx.enableRules) {
252
+ nodeReferences.push({ types: `vuetify-nuxt-module/custom-${ctx.rulesConfiguration.fromLabs ? "labs-" : ""}rules-configuration` });
595
253
  }
596
- return isNone && noneFiles.has(id) ? "" : void 0;
597
254
  }
598
- };
599
- }
600
- function resolveCssFactory() {
601
- const mappings = /* @__PURE__ */ new Map();
602
- return async (source) => {
603
- let mapping = mappings.get(source);
604
- if (!mapping) {
605
- try {
606
- mapping = source.replace(/\.css$/, ".sass");
607
- await fsp.access(mapping, fs.constants.R_OK);
608
- } catch (err) {
609
- if (!(err instanceof Error && "code" in err && err.code === "ENOENT"))
610
- throw err;
611
- mapping = source.replace(/\.css$/, ".scss");
255
+ });
256
+ if (importComposables) {
257
+ const composables = ["useDate", "useLocale", "useDefaults", "useDisplay", "useLayout", "useRtl", "useTheme"];
258
+ if (ctx.vuetifyGte("3.5.0")) {
259
+ composables.push("useGoTo");
260
+ }
261
+ if (ctx.vuetifyGte("3.8.0")) {
262
+ composables.push("useHotkey");
263
+ if (ctx.enableRules) {
264
+ composables.push("useRules");
612
265
  }
613
- mappings.set(source, mapping);
614
266
  }
615
- return mapping;
616
- };
617
- }
618
- function isSubdir(root, test) {
619
- const relative = relative$1(root, test);
620
- return relative && !relative.startsWith("..") && !isAbsolute(relative);
621
- }
622
-
623
- function toKebabCase(str = "") {
624
- if (toKebabCase.cache.has(str))
625
- return toKebabCase.cache.get(str);
626
- const kebab = str.replace(/[^a-z]/gi, "-").replace(/\B([A-Z])/g, "-$1").toLowerCase();
627
- toKebabCase.cache.set(str, kebab);
628
- return kebab;
629
- }
630
- toKebabCase.cache = /* @__PURE__ */ new Map();
631
- function camelize(str) {
632
- if (camelize.cache.has(str))
633
- return camelize.cache.get(str);
634
- const camel = str.replace(/-([a-z0-9])/g, (g) => g[1].toUpperCase());
635
- camelize.cache.set(str, camel);
636
- return camel;
637
- }
638
- camelize.cache = /* @__PURE__ */ new Map();
639
- function pascalize(str) {
640
- if (pascalize.cache.has(str))
641
- return pascalize.cache.get(str);
642
- let pascal = camelize(str);
643
- pascal = pascal.slice(0, 1).toUpperCase() + pascal.slice(1);
644
- pascalize.cache.set(str, pascal);
645
- return pascal;
646
- }
647
- pascalize.cache = /* @__PURE__ */ new Map();
648
- function createTransformAssetUrls(ctx, viteInlineConfig) {
649
- const { includeTransformAssetsUrls } = ctx.moduleOptions;
650
- if (!includeTransformAssetsUrls)
651
- return void 0;
652
- let existingTransformAssetUrls = viteInlineConfig.vue?.template?.transformAssetUrls ?? {};
653
- let useURLOptions;
654
- if (typeof existingTransformAssetUrls === "boolean") {
655
- existingTransformAssetUrls = {};
656
- } else if ("base" in existingTransformAssetUrls || "includeAbsolute" in existingTransformAssetUrls || "tags" in existingTransformAssetUrls) {
657
- useURLOptions = {
658
- base: existingTransformAssetUrls.base,
659
- includeAbsolute: existingTransformAssetUrls.includeAbsolute
660
- };
661
- existingTransformAssetUrls = existingTransformAssetUrls.tags ?? {};
267
+ if (ctx.vuetifyGte("3.10.0")) {
268
+ composables.push("useMask");
269
+ }
270
+ addImports(composables.map((name) => ({
271
+ name,
272
+ from: ctx.vuetifyGte("3.4.0") || name !== "useDate" ? "vuetify" : "vuetify/labs/date",
273
+ as: prefixComposables ? name.replace(/^use/, "useV") : void 0,
274
+ meta: { docsUrl: name === "useRules" ? "https://vuetifyjs.com/en/features/rules/" : `https://vuetifyjs.com/en/api/${toKebabCase(name)}/` }
275
+ })));
662
276
  }
663
- const transformAssetUrls$1 = normalizeTransformAssetUrls(
664
- typeof includeTransformAssetsUrls === "object" ? defu(existingTransformAssetUrls, transformAssetUrls, includeTransformAssetsUrls) : defu(existingTransformAssetUrls, transformAssetUrls)
665
- );
666
- if (!useURLOptions)
667
- return transformAssetUrls$1;
668
- useURLOptions.tags = transformAssetUrls$1;
669
- return useURLOptions;
670
- }
671
- function normalizeTransformAssetUrls(transformAssetUrls) {
672
- const names = new Set(Object.keys(transformAssetUrls));
673
- let kebab;
674
- let pascal;
675
- for (const name of names) {
676
- transformAssetUrls[name] = normalizeTransformAssetUrlsAttrs(transformAssetUrls[name]);
677
- kebab = toKebabCase(name);
678
- pascal = pascalize(name);
679
- if (!names.has(kebab))
680
- transformAssetUrls[kebab] = [...transformAssetUrls[name]];
681
- if (!names.has(pascal))
682
- transformAssetUrls[pascal] = [...transformAssetUrls[name]];
277
+ if (ctx.ssrClientHints.enabled) {
278
+ addPlugin({
279
+ src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-client-hints.client"),
280
+ mode: "client"
281
+ });
282
+ addPlugin({
283
+ src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-client-hints.server"),
284
+ mode: "server"
285
+ });
286
+ } else {
287
+ addPlugin({
288
+ src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-no-client-hints")
289
+ });
683
290
  }
684
- return transformAssetUrls;
685
- }
686
- function normalizeTransformAssetUrlsAttrs(attrs) {
687
- const result = /* @__PURE__ */ new Set();
688
- let kebab;
689
- let camel;
690
- let bind;
691
- let idx;
692
- for (const attr of attrs) {
693
- result.add(attr);
694
- idx = attr.indexOf(":");
695
- if (idx > 0)
696
- continue;
697
- bind = idx === 0;
698
- kebab = toKebabCase(bind ? attr.slice(1) : attr);
699
- camel = camelize(bind ? attr.slice(1) : attr);
700
- result.add(kebab);
701
- result.add(camel);
702
- result.add(`:${kebab}`);
703
- result.add(`:${camel}`);
291
+ addPlugin({
292
+ src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-icons")
293
+ });
294
+ if (ctx.i18n) {
295
+ addPlugin({
296
+ src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-i18n")
297
+ });
704
298
  }
705
- return [...result];
299
+ if (nuxt.options.dev || ctx.dateAdapter) {
300
+ if (ctx.i18n) {
301
+ addPlugin({
302
+ src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-i18n-date")
303
+ });
304
+ } else {
305
+ addPlugin({
306
+ src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-date")
307
+ });
308
+ }
309
+ }
310
+ addVuetifyNuxtPlugins(nuxt, ctx);
706
311
  }
707
312
 
708
313
  function vuetifyConfigurationPlugin(ctx) {
@@ -710,8 +315,9 @@ function vuetifyConfigurationPlugin(ctx) {
710
315
  name: "vuetify:configuration:nuxt",
711
316
  enforce: "pre",
712
317
  resolveId(id) {
713
- if (id === VIRTUAL_VUETIFY_CONFIGURATION)
318
+ if (id === VIRTUAL_VUETIFY_CONFIGURATION) {
714
319
  return RESOLVED_VIRTUAL_VUETIFY_CONFIGURATION;
320
+ }
715
321
  },
716
322
  async load(id) {
717
323
  if (id === RESOLVED_VIRTUAL_VUETIFY_CONFIGURATION) {
@@ -726,8 +332,9 @@ function vuetifyConfigurationPlugin(ctx) {
726
332
  aliases: _aliases,
727
333
  ...newVuetifyOptions
728
334
  } = ctx.vuetifyOptions;
729
- if (ctx.isSSR)
335
+ if (ctx.isSSR) {
730
336
  newVuetifyOptions.ssr = ssr ?? true;
337
+ }
731
338
  if (ctx.i18n && newVuetifyOptions.locale) {
732
339
  delete newVuetifyOptions.locale.rtl;
733
340
  delete newVuetifyOptions.locale.locale;
@@ -798,78 +405,85 @@ async function buildConfiguration(ctx) {
798
405
  }
799
406
  const importMapComponents = await componentsPromise;
800
407
  const componentsToImport = /* @__PURE__ */ new Map();
801
- config.components.forEach((component) => {
408
+ for (const component of config.components) {
802
409
  const { from } = importMapComponents[component];
803
410
  if (!from) {
804
411
  logger.warn(`Component ${component} not found in Vuetify.`);
805
- return;
412
+ continue;
806
413
  }
807
414
  const parts = from.split("/");
808
415
  if (parts.length < 2) {
809
416
  logger.warn(`Component ${component} not found in Vuetify, please report a new issue.`);
810
- return;
417
+ continue;
811
418
  }
812
- if (!componentsToImport.has(parts[1]))
419
+ if (!componentsToImport.has(parts[1])) {
813
420
  componentsToImport.set(parts[1], []);
421
+ }
814
422
  const componentsArray = componentsToImport.get(parts[1]);
815
- if (!componentsArray.includes(component))
423
+ if (!componentsArray.includes(component)) {
816
424
  componentsArray.push(component);
817
- });
818
- Object.entries(config.aliases).forEach(([key, component]) => {
425
+ }
426
+ }
427
+ for (const [key, component] of Object.entries(config.aliases)) {
819
428
  const { from } = importMapComponents[component];
820
429
  if (!from) {
821
430
  logger.warn(`Component ${component} not found in Vuetify.`);
822
- return;
431
+ continue;
823
432
  }
824
433
  const parts = from.split("/");
825
434
  if (parts.length < 2) {
826
435
  logger.warn(`Component ${component} not found in Vuetify, please report a new issue.`);
827
- return;
436
+ continue;
828
437
  }
829
- if (!componentsToImport.has(parts[1]))
438
+ if (!componentsToImport.has(parts[1])) {
830
439
  componentsToImport.set(parts[1], []);
440
+ }
831
441
  const componentsArray = componentsToImport.get(parts[1]);
832
- if (!componentsArray.includes(component))
442
+ if (!componentsArray.includes(component)) {
833
443
  componentsArray.push(component);
444
+ }
834
445
  config.aliasEntries.push(`'${key}': ${component}`);
835
- });
836
- componentsToImport.forEach((componentsArray, from) => {
446
+ }
447
+ for (const [from, componentsArray] of componentsToImport.entries()) {
837
448
  config.imports.push(`import {${Array.from(new Set(componentsArray)).join(",")}} from 'vuetify/components/${from}'`);
838
- });
449
+ }
839
450
  let addDatePicker = ctx.vuetifyGte("3.4.0") ? !Array.from(componentsToImport.values()).some((components2) => components2.includes("VDatePicker")) : true;
840
451
  if (labComponents) {
841
452
  const useLabComponents = [];
842
453
  if (typeof labComponents === "boolean") {
843
454
  config.imports.push("import * as labsComponents from 'vuetify/labs/components'");
844
455
  config.labComponents.add("*");
845
- if (!ctx.vuetifyGte("3.4.0"))
456
+ if (!ctx.vuetifyGte("3.4.0")) {
846
457
  addDatePicker = false;
458
+ }
847
459
  } else if (typeof labComponents === "string") {
848
460
  useLabComponents.push(labComponents);
849
461
  } else if (Array.isArray(labComponents)) {
850
462
  useLabComponents.push(...labComponents);
851
463
  }
852
- if (useLabComponents.length) {
464
+ if (useLabComponents.length > 0) {
853
465
  componentsToImport.clear();
854
466
  const importMapLabComponents = await labComponentsPromise;
855
- useLabComponents.forEach((component) => {
467
+ for (const component of useLabComponents) {
856
468
  const { from } = importMapLabComponents[component];
857
469
  if (!from) {
858
470
  logger.warn(`Lab Component ${component} not found in Vuetify.`);
859
- return;
471
+ continue;
860
472
  }
861
473
  const parts = from.split("/");
862
474
  if (parts.length < 2) {
863
475
  logger.warn(`Lab Component ${component} not found in Vuetify, please report a new issue.`);
864
- return;
476
+ continue;
865
477
  }
866
- if (!componentsToImport.has(parts[1]))
478
+ if (!componentsToImport.has(parts[1])) {
867
479
  componentsToImport.set(parts[1], []);
480
+ }
868
481
  const componentsArray = componentsToImport.get(parts[1]);
869
- if (!componentsArray.includes(component))
482
+ if (!componentsArray.includes(component)) {
870
483
  componentsArray.push(component);
484
+ }
871
485
  config.labComponents.add(component);
872
- });
486
+ }
873
487
  if (!ctx.vuetifyGte("3.4.0") && dateOptions && !addDatePicker) {
874
488
  const entry = componentsToImport.get("VDatePicker");
875
489
  if (entry) {
@@ -878,9 +492,9 @@ async function buildConfiguration(ctx) {
878
492
  addDatePicker = false;
879
493
  }
880
494
  }
881
- componentsToImport.forEach((componentsArray, from) => {
495
+ for (const [from, componentsArray] of componentsToImport.entries()) {
882
496
  config.imports.push(`import {${Array.from(new Set(componentsArray)).join(",")}} from 'vuetify/labs/${from}'`);
883
- });
497
+ }
884
498
  }
885
499
  }
886
500
  if (dateOptions && addDatePicker) {
@@ -898,20 +512,14 @@ async function buildConfiguration(ctx) {
898
512
  warn && logger.warn("Unable to load Vuetify version from package.json, add VDatePicker to components or labComponents");
899
513
  }
900
514
  let componentsEntry = "";
901
- if (config.components.size) {
902
- if (config.labComponents.size) {
903
- if (config.labComponents.has("*"))
904
- componentsEntry = `options.components = {${Array.from(config.components).join(",")},...labsComponents}`;
905
- else
906
- componentsEntry = `options.components = {${Array.from(config.components).join(",")},${Array.from(config.labComponents).join(",")}}`;
515
+ if (config.components.size > 0) {
516
+ if (config.labComponents.size > 0) {
517
+ componentsEntry = config.labComponents.has("*") ? `options.components = {${Array.from(config.components).join(",")},...labsComponents}` : `options.components = {${Array.from(config.components).join(",")},${Array.from(config.labComponents).join(",")}}`;
907
518
  } else {
908
519
  componentsEntry = `options.components = {${Array.from(config.components).join(",")}}`;
909
520
  }
910
- } else if (config.labComponents.size) {
911
- if (config.labComponents.has("*"))
912
- componentsEntry = "options.components = {...labsComponents}";
913
- else
914
- componentsEntry = `options.components = {${Array.from(config.labComponents).join(",")}}`;
521
+ } else if (config.labComponents.size > 0) {
522
+ componentsEntry = config.labComponents.has("*") ? "options.components = {...labsComponents}" : `options.components = {${Array.from(config.labComponents).join(",")}}`;
915
523
  }
916
524
  if (!ctx.i18n && localeMessages) {
917
525
  const useLocales = Array.isArray(localeMessages) ? [...new Set(localeMessages)] : [localeMessages];
@@ -930,24 +538,90 @@ ${useLocales.map((locale) => {
930
538
  `;
931
539
  }
932
540
  return {
933
- imports: config.imports.length ? config.imports.join("\n") : "",
541
+ imports: config.imports.length > 0 ? config.imports.join("\n") : "",
934
542
  components: componentsEntry,
935
- aliases: config.aliasEntries.length ? `options.aliases = {${config.aliasEntries.join(",")}}` : "",
543
+ aliases: config.aliasEntries.length > 0 ? `options.aliases = {${config.aliasEntries.join(",")}}` : "",
936
544
  directives: config.directives,
937
545
  messages: config.messages
938
546
  };
939
547
  }
940
548
 
941
- function vuetifyIconsPlugin(ctx) {
549
+ function vuetifyDateConfigurationPlugin(ctx) {
942
550
  return {
943
- name: "vuetify:icons-configuration:nuxt",
551
+ name: "vuetify:date-configuration:nuxt",
944
552
  enforce: "pre",
945
553
  resolveId(id) {
946
- if (id === VIRTUAL_VUETIFY_ICONS_CONFIGURATION)
947
- return RESOLVED_VIRTUAL_VUETIFY_ICONS_CONFIGURATION;
554
+ if (id === VIRTUAL_VUETIFY_DATE_CONFIGURATION) {
555
+ return RESOLVED_VIRTUAL_VUETIFY_DATE_CONFIGURATION;
556
+ }
948
557
  },
949
558
  async load(id) {
950
- if (id === RESOLVED_VIRTUAL_VUETIFY_ICONS_CONFIGURATION) {
559
+ if (id === RESOLVED_VIRTUAL_VUETIFY_DATE_CONFIGURATION) {
560
+ if (!ctx.dateAdapter) {
561
+ return `
562
+ export const enabled = false
563
+ export const isDev = ${ctx.isDev}
564
+ export const i18n = ${ctx.i18n}
565
+ export const adapter = 'custom'
566
+ export function dateConfiguration() {
567
+ return {}
568
+ }
569
+ `;
570
+ }
571
+ const { adapter: _adapter, ...newDateOptions } = ctx.vuetifyOptions.date ?? {};
572
+ return `${buildImports()}
573
+ export const enabled = true
574
+ export const isDev = ${ctx.isDev}
575
+ export const i18n = ${ctx.i18n}
576
+ export const adapter = '${ctx.dateAdapter}'
577
+ export function dateConfiguration() {
578
+ const options = JSON.parse('${JSON.stringify(newDateOptions)}')
579
+ ${buildAdapter()}
580
+ return options
581
+ }
582
+ `;
583
+ }
584
+ }
585
+ };
586
+ function buildAdapter() {
587
+ if (ctx.dateAdapter === "custom" || ctx.dateAdapter === "vuetify" && ctx.vuetifyGte("3.4.0")) {
588
+ return "";
589
+ }
590
+ if (ctx.dateAdapter === "vuetify") {
591
+ return "options.adapter = VuetifyDateAdapter";
592
+ }
593
+ const locale = ctx.vuetifyOptions.locale?.locale ?? "en";
594
+ if (ctx.dateAdapter === "date-fns") {
595
+ return `options.adapter = new Adapter({ locale: ${locale} })`;
596
+ }
597
+ return "options.adapter = Adapter";
598
+ }
599
+ function buildImports() {
600
+ if (ctx.dateAdapter === "custom" || ctx.dateAdapter === "vuetify" && ctx.vuetifyGte("3.4.0")) {
601
+ return "";
602
+ }
603
+ if (ctx.dateAdapter === "vuetify") {
604
+ return "import { VuetifyDateAdapter } from 'vuetify/labs/date/adapters/vuetify'";
605
+ }
606
+ const imports = [`import Adapter from '@date-io/${ctx.dateAdapter}'`];
607
+ if (ctx.dateAdapter === "date-fns") {
608
+ imports.push(`import { ${ctx.vuetifyOptions.locale?.locale ?? "en"} } from 'date-fns/locale'`);
609
+ }
610
+ return imports.join("\n");
611
+ }
612
+ }
613
+
614
+ function vuetifyIconsPlugin(ctx) {
615
+ return {
616
+ name: "vuetify:icons-configuration:nuxt",
617
+ enforce: "pre",
618
+ resolveId(id) {
619
+ if (id === VIRTUAL_VUETIFY_ICONS_CONFIGURATION) {
620
+ return RESOLVED_VIRTUAL_VUETIFY_ICONS_CONFIGURATION;
621
+ }
622
+ },
623
+ async load(id) {
624
+ if (id === RESOLVED_VIRTUAL_VUETIFY_ICONS_CONFIGURATION) {
951
625
  const {
952
626
  enabled,
953
627
  unocss,
@@ -1006,7 +680,7 @@ ${unocss}
1006
680
  aliases = "";
1007
681
  } else {
1008
682
  const alias = ctx.icons.aliases;
1009
- if (alias.length) {
683
+ if (alias.length > 0) {
1010
684
  aliases = `aliases: {
1011
685
  ...aliases,
1012
686
  ${alias.join(",\n")}
@@ -1095,371 +769,799 @@ ${unocss}
1095
769
  minus,
1096
770
  calendar
1097
771
  };
1098
- Object.entries(ctx.icons.unocssAdditionalIcons).forEach(([key, value]) => {
772
+ for (const [key, value] of Object.entries(ctx.icons.unocssAdditionalIcons)) {
1099
773
  useIcons[key] = value;
1100
- });
774
+ }
1101
775
  unocss = `const aliases = JSON.parse('${JSON.stringify(useIcons)}');
1102
776
  `;
1103
777
  }
1104
- return {
1105
- enabled: true,
1106
- unocss,
1107
- fa: ctx.icons.svg?.fa ?? [],
1108
- defaultSet: ctx.icons.defaultSet,
1109
- imports: Object.values(ctx.icons.imports).join("\n"),
1110
- sets: ctx.icons.sets.join(","),
1111
- aliases
1112
- };
778
+ return {
779
+ enabled: true,
780
+ unocss,
781
+ fa: ctx.icons.svg?.fa ?? [],
782
+ defaultSet: ctx.icons.defaultSet,
783
+ imports: Object.values(ctx.icons.imports).join("\n"),
784
+ sets: ctx.icons.sets.join(","),
785
+ aliases
786
+ };
787
+ }
788
+ }
789
+
790
+ function parseId2(id) {
791
+ id = id.replace(/^(virtual:nuxt:|virtual:)/, "");
792
+ return parseURL(decodeURIComponent(isAbsolute(id) ? pathToFileURL(id).href : id));
793
+ }
794
+ function parseId(id) {
795
+ const { search, pathname } = parseId2(id);
796
+ const query = parseQuery(search);
797
+ const urlProps = query.props ? destr(query.props) : void 0;
798
+ return {
799
+ query: urlProps,
800
+ path: pathname ?? id
801
+ };
802
+ }
803
+ function vuetifyImportPlugin(options) {
804
+ let filter;
805
+ return {
806
+ name: "vuetify:import:nuxt",
807
+ configResolved(config) {
808
+ if (config.plugins.some((plugin) => plugin.name === "vuetify:import")) {
809
+ throw new Error("Remove vite-plugin-vuetify from your Nuxt config file, this module registers a modified version.");
810
+ }
811
+ const vueIdx = config.plugins.findIndex((plugin) => plugin.name === "vite:vue");
812
+ const vueOptions = vueIdx === -1 ? {} : config.plugins[vueIdx].api?.options;
813
+ filter = createFilter(vueOptions.include, vueOptions.exclude);
814
+ },
815
+ async transform(code, id) {
816
+ const { query, path } = parseId(id);
817
+ const isVueVirtual = query && "vue" in query;
818
+ const isVueFile = !isVueVirtual && filter(path) && !/^import { render as _sfc_render } from ".*"$/m.test(code);
819
+ const isVueTemplate = isVueVirtual && (query.type === "template" || query.type === "script" && query.setup === "true");
820
+ if (isVueFile || isVueTemplate) {
821
+ const { code: imports, source } = generateImports(code, options);
822
+ return {
823
+ code: source + imports,
824
+ map: null
825
+ };
826
+ }
827
+ return null;
828
+ }
829
+ };
830
+ }
831
+
832
+ function vuetifySSRClientHintsPlugin(ctx) {
833
+ return {
834
+ name: "vuetify:ssr-client-hints:nuxt",
835
+ enforce: "pre",
836
+ resolveId(id) {
837
+ if (id === VIRTUAL_VUETIFY_SSR_CLIENT_HINTS_CONFIGURATION) {
838
+ return RESOLVED_VIRTUAL_VUETIFY_SSR_CLIENT_HINTS_CONFIGURATION;
839
+ }
840
+ },
841
+ async load(id) {
842
+ if (id === RESOLVED_VIRTUAL_VUETIFY_SSR_CLIENT_HINTS_CONFIGURATION) {
843
+ const data = {
844
+ reloadOnFirstRequest: ctx.ssrClientHints.reloadOnFirstRequest,
845
+ viewportSize: ctx.ssrClientHints.viewportSize,
846
+ prefersColorScheme: ctx.ssrClientHints.prefersColorScheme,
847
+ prefersReducedMotion: ctx.ssrClientHints.prefersReducedMotion,
848
+ clientWidth: ctx.vuetifyOptions.ssr?.clientWidth,
849
+ clientHeight: ctx.vuetifyOptions.ssr?.clientHeight,
850
+ prefersColorSchemeOptions: ctx.ssrClientHints.prefersColorSchemeOptions
851
+ };
852
+ return `export const ssrClientHintsConfiguration = JSON.parse('${JSON.stringify(data)}');`;
853
+ }
854
+ }
855
+ };
856
+ }
857
+
858
+ function vuetifyStylesPlugin(options, viteVersion, _logger) {
859
+ let configFile;
860
+ let useLoadCache = false;
861
+ const vuetifyBase = resolveVuetifyBase();
862
+ const noneFiles = /* @__PURE__ */ new Set();
863
+ const loadCache = /* @__PURE__ */ new Map();
864
+ let isNone = false;
865
+ let sassVariables = false;
866
+ let fileImport = false;
867
+ const PREFIX = "vuetify-styles/";
868
+ const SSR_PREFIX = `/@${PREFIX}`;
869
+ const resolveCss = resolveCssFactory();
870
+ return {
871
+ name: "vuetify:styles:nuxt",
872
+ enforce: "pre",
873
+ async configResolved(config) {
874
+ if (config.plugins.some((plugin) => plugin.name === "vuetify:styles")) {
875
+ throw new Error("Remove vite-plugin-vuetify from your Nuxt config file, this module registers a modified version.");
876
+ }
877
+ if (isObject(options.styles) && "configFile" in options.styles) {
878
+ sassVariables = true;
879
+ useLoadCache = !config.isProduction && !!options.styles.experimental?.cache;
880
+ fileImport = semver.gt(viteVersion, "5.4.2");
881
+ configFile = await resolvePath(options.styles.configFile);
882
+ } else {
883
+ isNone = options.styles === "none";
884
+ }
885
+ },
886
+ async resolveId(source, importer, { custom, ssr }) {
887
+ if (!sassVariables) {
888
+ return;
889
+ }
890
+ if (source.startsWith(PREFIX) || source.startsWith(SSR_PREFIX)) {
891
+ if (/\.s[ca]ss$/.test(source)) {
892
+ return source;
893
+ }
894
+ const idx = source.indexOf("?");
895
+ return idx === -1 ? source : source.slice(0, idx);
896
+ }
897
+ if (importer && source.endsWith(".css") && isSubdir(vuetifyBase, path.isAbsolute(source) ? source : importer)) {
898
+ const resolution = await this.resolve(source, importer, { skipSelf: true, custom });
899
+ if (!resolution) {
900
+ return;
901
+ }
902
+ const target = await resolveCss(resolution.id);
903
+ if (isNone) {
904
+ noneFiles.add(target);
905
+ return target;
906
+ }
907
+ return `${ssr ? SSR_PREFIX : PREFIX}${path.relative(vuetifyBase, target)}`;
908
+ }
909
+ return void 0;
910
+ },
911
+ load(id) {
912
+ if (sassVariables) {
913
+ const target = id.startsWith(PREFIX) ? path.resolve(vuetifyBase, id.slice(PREFIX.length)) : id.startsWith(SSR_PREFIX) ? path.resolve(vuetifyBase, id.slice(SSR_PREFIX.length)) : void 0;
914
+ if (target) {
915
+ if (useLoadCache) {
916
+ const cached = loadCache.get(id);
917
+ if (cached) {
918
+ return cached;
919
+ }
920
+ }
921
+ const suffix = /\.scss/.test(target) ? ";\n" : "\n";
922
+ const result = {
923
+ code: `@use "${configFile}"${suffix}@use "${fileImport ? pathToFileURL(target).href : normalizePath(target)}"${suffix}`,
924
+ map: {
925
+ mappings: ""
926
+ }
927
+ };
928
+ if (useLoadCache) {
929
+ loadCache.set(id, result);
930
+ }
931
+ return result;
932
+ }
933
+ }
934
+ return isNone && noneFiles.has(id) ? "" : void 0;
935
+ },
936
+ handleHotUpdate({ file }) {
937
+ if (!useLoadCache) {
938
+ return;
939
+ }
940
+ const normalizedFile = normalizePath(file);
941
+ if (normalizedFile === normalizePath(configFile || "") || normalizedFile.endsWith(".sass") || normalizedFile.endsWith(".scss")) {
942
+ loadCache.clear();
943
+ }
944
+ }
945
+ };
946
+ }
947
+ function resolveCssFactory() {
948
+ const mappings = /* @__PURE__ */ new Map();
949
+ return async (source) => {
950
+ let mapping = mappings.get(source);
951
+ if (!mapping) {
952
+ try {
953
+ mapping = source.replace(/\.css$/, ".sass");
954
+ await fsp.access(mapping, fs.constants.R_OK);
955
+ } catch (error) {
956
+ if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) {
957
+ throw error;
958
+ }
959
+ mapping = source.replace(/\.css$/, ".scss");
960
+ }
961
+ mappings.set(source, mapping);
962
+ }
963
+ return mapping;
964
+ };
965
+ }
966
+ function isSubdir(root, test) {
967
+ const relative$1 = relative(root, test);
968
+ return relative$1 && !relative$1.startsWith("..") && !isAbsolute(relative$1);
969
+ }
970
+
971
+ function detectDate() {
972
+ const result = [];
973
+ for (const adapter of [
974
+ "date-fns",
975
+ "moment",
976
+ "luxon",
977
+ "dayjs",
978
+ "js-joda",
979
+ "date-fns-jalali",
980
+ "jalaali",
981
+ "hijri"
982
+ ]) {
983
+ if (isPackageExists(`@date-io/${adapter}`)) {
984
+ result.push(adapter);
985
+ }
986
+ }
987
+ return result;
988
+ }
989
+ function cleanupBlueprint(vuetifyOptions) {
990
+ const blueprint = vuetifyOptions.blueprint;
991
+ if (blueprint) {
992
+ delete blueprint.ssr;
993
+ delete blueprint.components;
994
+ delete blueprint.directives;
995
+ delete blueprint.locale;
996
+ delete blueprint.date;
997
+ delete blueprint.icons;
998
+ vuetifyOptions.blueprint = blueprint;
999
+ }
1000
+ }
1001
+ function checkVuetifyPlugins(config) {
1002
+ let plugin = config.plugins?.find((p) => p && typeof p === "object" && "name" in p && p.name === "vuetify:import");
1003
+ if (plugin) {
1004
+ throw new Error("Remove vite-plugin-vuetify plugin from Vite Plugins entry in Nuxt config file!");
1005
+ }
1006
+ plugin = config.plugins?.find((p) => p && typeof p === "object" && "name" in p && p.name === "vuetify:styles");
1007
+ if (plugin) {
1008
+ throw new Error("Remove vite-plugin-vuetify plugin from Vite Plugins entry in Nuxt config file!");
1009
+ }
1010
+ }
1011
+ function resolveVuetifyComponents(resolver) {
1012
+ const vuetifyBase = resolveVuetifyBase();
1013
+ const componentsPromise = importMapResolver();
1014
+ const labComponentsPromise = importMapLabResolver();
1015
+ return {
1016
+ vuetifyBase,
1017
+ componentsPromise,
1018
+ labComponentsPromise
1019
+ };
1020
+ async function importMapResolver() {
1021
+ return JSON.parse(await readFile(resolver.resolve(vuetifyBase, "dist/json/importMap.json"), "utf8")).components;
1022
+ }
1023
+ async function importMapLabResolver() {
1024
+ return JSON.parse(await readFile(resolver.resolve(vuetifyBase, "dist/json/importMap-labs.json"), "utf8")).components;
1025
+ }
1026
+ }
1027
+
1028
+ function configureVite(configKey, nuxt, ctx) {
1029
+ nuxt.hook("vite:extend", ({ config }) => checkVuetifyPlugins(config));
1030
+ nuxt.hook("vite:extendConfig", (viteInlineConfig) => {
1031
+ viteInlineConfig.plugins = viteInlineConfig.plugins || [];
1032
+ checkVuetifyPlugins(viteInlineConfig);
1033
+ if (!ctx.moduleOptions.disableModernSassCompiler) {
1034
+ const enableModernSassCompiler = semver.gte(ctx.viteVersion, "5.4.0") && semver.lt(ctx.viteVersion, "7.0.0-0");
1035
+ if (enableModernSassCompiler) {
1036
+ const sassEmbedded = isPackageExists("sass-embedded");
1037
+ if (sassEmbedded) {
1038
+ viteInlineConfig.css ??= {};
1039
+ viteInlineConfig.css.preprocessorOptions ??= {};
1040
+ viteInlineConfig.css.preprocessorOptions.sass ??= {};
1041
+ viteInlineConfig.css.preprocessorOptions.sass.api = "modern-compiler";
1042
+ viteInlineConfig.css.preprocessorOptions.scss ??= {};
1043
+ viteInlineConfig.css.preprocessorOptions.scss.api = "modern-compiler";
1044
+ } else {
1045
+ viteInlineConfig.css ??= {};
1046
+ viteInlineConfig.css.preprocessorOptions ??= {};
1047
+ viteInlineConfig.css.preprocessorOptions.sass ??= {};
1048
+ viteInlineConfig.css.preprocessorOptions.sass.api = "modern";
1049
+ viteInlineConfig.css.preprocessorOptions.scss ??= {};
1050
+ viteInlineConfig.css.preprocessorOptions.scss.api = "modern";
1051
+ if (!("preprocessorMaxWorkers" in viteInlineConfig.css)) {
1052
+ viteInlineConfig.css.preprocessorMaxWorkers = true;
1053
+ }
1054
+ }
1055
+ }
1056
+ }
1057
+ viteInlineConfig.optimizeDeps = defu(viteInlineConfig.optimizeDeps, { exclude: ["vuetify"] });
1058
+ if (ctx.isSSR) {
1059
+ viteInlineConfig.ssr ||= {};
1060
+ viteInlineConfig.ssr.noExternal = [
1061
+ ...Array.isArray(viteInlineConfig.ssr.noExternal) ? viteInlineConfig.ssr.noExternal : viteInlineConfig.ssr.noExternal && typeof viteInlineConfig.ssr.noExternal !== "boolean" ? [viteInlineConfig.ssr.noExternal] : [],
1062
+ configKey
1063
+ ];
1064
+ }
1065
+ const transformAssetUrls = createTransformAssetUrls(
1066
+ ctx,
1067
+ viteInlineConfig
1068
+ );
1069
+ if (transformAssetUrls) {
1070
+ viteInlineConfig.vue ??= {};
1071
+ viteInlineConfig.vue.template ??= {};
1072
+ viteInlineConfig.vue.template.transformAssetUrls = transformAssetUrls;
1073
+ }
1074
+ const autoImport = { labs: true };
1075
+ const ignoreDirectives = ctx.moduleOptions.ignoreDirectives;
1076
+ if (ignoreDirectives) {
1077
+ autoImport.ignore = Array.isArray(ignoreDirectives) ? ignoreDirectives : [ignoreDirectives];
1078
+ }
1079
+ viteInlineConfig.plugins.push(vuetifyImportPlugin({ autoImport }));
1080
+ if (ctx.moduleOptions.styles !== false && ctx.moduleOptions.styles !== "none") {
1081
+ viteInlineConfig.plugins.push(vuetifyStylesPlugin({ styles: ctx.moduleOptions.styles }, ctx.viteVersion, ctx.logger));
1082
+ }
1083
+ viteInlineConfig.plugins.push(vuetifyConfigurationPlugin(ctx), vuetifyIconsPlugin(ctx), vuetifyDateConfigurationPlugin(ctx));
1084
+ if (ctx.ssrClientHints.enabled) {
1085
+ viteInlineConfig.plugins.push(vuetifySSRClientHintsPlugin(ctx));
1086
+ }
1087
+ });
1088
+ }
1089
+
1090
+ const cssFonts = ["unocss-mdi", "mdi", "md", "fa", "fa4"];
1091
+ const iconsPackageNames = {
1092
+ "unocss-mdi": { name: "@mdi/font", css: "" },
1093
+ "mdi": { name: "@mdi/font", css: "@mdi/font/css/materialdesignicons.css" },
1094
+ "md": { name: "material-design-icons-iconfont", css: "@mdi/font/css/materialdesignicons.css" },
1095
+ "fa": { name: "@fortawesome/fontawesome-free", css: "@fortawesome/fontawesome-free/css/all.css" },
1096
+ "fa4": { name: "font-awesome@4.7.0", css: "font-awesome/css/font-awesome.min.css" }
1097
+ };
1098
+ const iconsCDN = {
1099
+ "unocss-mdi": "",
1100
+ "mdi": "https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css",
1101
+ "md": "https://fonts.googleapis.com/css?family=Material+Icons",
1102
+ "fa": "https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@latest/css/all.min.css",
1103
+ "fa4": "https://cdn.jsdelivr.net/npm/font-awesome@4.x/css/font-awesome.min.css"
1104
+ };
1105
+ const disabledResolvedIcons = Object.freeze({
1106
+ enabled: false,
1107
+ unocss: false,
1108
+ unocssAliases: false,
1109
+ unocssIconPrefix: "i-",
1110
+ unocssIcons: {},
1111
+ unocssAdditionalIcons: {},
1112
+ imports: [],
1113
+ aliases: [],
1114
+ aliasesImportPresent: false,
1115
+ sets: [],
1116
+ cdn: [],
1117
+ local: [],
1118
+ svg: {}
1119
+ });
1120
+ function prepareIcons(unocssPresent, logger, vuetifyOptions) {
1121
+ if (vuetifyOptions.icons === false) {
1122
+ return disabledResolvedIcons;
1123
+ }
1124
+ const icons = vuetifyOptions.icons || {};
1125
+ let { defaultSet = "mdi", sets } = icons;
1126
+ if (!defaultSet) {
1127
+ defaultSet = icons.defaultSet = "mdi";
1128
+ }
1129
+ if (!sets && defaultSet !== "mdi-svg" && defaultSet !== "fa-svg" && defaultSet !== "custom") {
1130
+ sets = [{ name: defaultSet || "mdi" }];
1131
+ }
1132
+ sets = sets ? convertFontSetsToObjectNotation(sets) : [];
1133
+ const resolvedIcons = {
1134
+ enabled: true,
1135
+ unocss: unocssPresent && (defaultSet === "unocss-mdi" || sets.some((s) => s.name === "unocss-mdi")),
1136
+ unocssAliases: defaultSet === "unocss-mdi",
1137
+ unocssIconPrefix: icons.unocssIconPrefix ?? "i-",
1138
+ unocssIcons: icons.unocssIcons ?? {},
1139
+ unocssAdditionalIcons: icons.unocssAdditionalIcons ?? {},
1140
+ defaultSet,
1141
+ sets: [],
1142
+ aliases: [],
1143
+ aliasesImportPresent: false,
1144
+ imports: [],
1145
+ cdn: [],
1146
+ local: [],
1147
+ svg: {
1148
+ mdi: false
1149
+ }
1150
+ };
1151
+ if (sets) {
1152
+ if (!unocssPresent && defaultSet === "unocss-mdi") {
1153
+ logger.warn("Configured unocss-mdi as default icon set and @unocss/nuxt is not installed, reverting configuration to use mdi icon set: install @unocss/nuxt module or change the default icon set!");
1154
+ defaultSet = "mdi";
1155
+ sets = sets.filter((s) => s.name !== "unocss-mdi");
1156
+ }
1157
+ for (const { name, cdn } of sets.filter((s) => cssFonts.includes(s.name))) {
1158
+ resolvedIcons.aliasesImportPresent ||= name === defaultSet;
1159
+ if (name === "unocss-mdi") {
1160
+ continue;
1161
+ }
1162
+ resolvedIcons.imports.push(`import {${name === defaultSet ? "aliases," : ""}${name}} from 'vuetify/iconsets/${name}'`);
1163
+ resolvedIcons.sets.push(name);
1164
+ if (isPackageExists(iconsPackageNames[name].name)) {
1165
+ resolvedIcons.local.push(iconsPackageNames[name].css);
1166
+ } else {
1167
+ resolvedIcons.cdn.push([name, cdn ?? iconsCDN[name]]);
1168
+ }
1169
+ }
1170
+ if (resolvedIcons.unocss && defaultSet === "unocss-mdi") {
1171
+ if (!resolvedIcons.sets.includes("mdi")) {
1172
+ resolvedIcons.sets.push("mdi");
1173
+ resolvedIcons.imports.push("import {mdi} from 'vuetify/iconsets/mdi'");
1174
+ }
1175
+ resolvedIcons.defaultSet = "mdi";
1176
+ }
1177
+ }
1178
+ let faSvg = icons.svg?.fa;
1179
+ if (defaultSet === "fa-svg" || faSvg) {
1180
+ if (!faSvg) {
1181
+ faSvg = {};
1182
+ }
1183
+ let faSvgExists = isPackageExists("@fortawesome/fontawesome-svg-core");
1184
+ if (!faSvgExists) {
1185
+ logger.warn("Missing @fortawesome/fontawesome-svg-core dependency, install it!");
1186
+ }
1187
+ faSvgExists = isPackageExists("@fortawesome/vue-fontawesome");
1188
+ if (faSvgExists) {
1189
+ if (!faSvg.libraries?.length) {
1190
+ faSvg.libraries = [[false, "fas", "@fortawesome/free-solid-svg-icons"]];
1191
+ }
1192
+ for (const p in faSvg.libraries) {
1193
+ const [_defaultExport, _name, library] = faSvg.libraries[p];
1194
+ if (!isPackageExists(library)) {
1195
+ faSvgExists = false;
1196
+ logger.warn(`Missing library ${library} dependency, install it!`);
1197
+ }
1198
+ }
1199
+ } else {
1200
+ logger.warn("Missing @fortawesome/vue-fontawesome dependency, install it!");
1201
+ }
1202
+ if (faSvgExists) {
1203
+ resolvedIcons.aliasesImportPresent ||= defaultSet === "fa-svg";
1204
+ resolvedIcons.imports.push(`import {${defaultSet === "fa-svg" ? "aliases," : ""}fa} from 'vuetify/iconsets/fa-svg'`, "import { library } from '@fortawesome/fontawesome-svg-core'", "import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'", "import { useNuxtApp } from '#imports'");
1205
+ resolvedIcons.svg.fa = ["useNuxtApp().vueApp.component('font-awesome-icon', FontAwesomeIcon)"];
1206
+ for (const [defaultExport, name, library] of faSvg.libraries) {
1207
+ resolvedIcons.imports.push(`import ${defaultExport ? name : `{${name}}`} from '${library}'`);
1208
+ resolvedIcons.svg.fa.push(`library.add(${name})`);
1209
+ }
1210
+ resolvedIcons.sets.push("fa");
1211
+ if (defaultSet === "fa-svg") {
1212
+ resolvedIcons.defaultSet = "fa";
1213
+ }
1214
+ }
1215
+ }
1216
+ let mdiSvg = icons.svg?.mdi;
1217
+ if (defaultSet === "mdi-svg" || mdiSvg) {
1218
+ if (!mdiSvg) {
1219
+ mdiSvg = {};
1220
+ }
1221
+ const mdiSvgExists = isPackageExists("@mdi/js");
1222
+ if (mdiSvgExists) {
1223
+ resolvedIcons.svg.mdi = true;
1224
+ resolvedIcons.aliasesImportPresent ||= defaultSet === "mdi-svg";
1225
+ resolvedIcons.imports.push(`import {${defaultSet === "mdi-svg" ? "aliases," : ""}mdi} from 'vuetify/iconsets/mdi-svg'`);
1226
+ if (mdiSvg && mdiSvg.aliases) {
1227
+ resolvedIcons.imports.push(`import {${Object.values(mdiSvg.aliases).join(",")}} from '@mdi/js'`);
1228
+ for (const [alias, icon] of Object.entries(mdiSvg.aliases)) {
1229
+ resolvedIcons.aliases.push(`${alias}: ${icon}`);
1230
+ }
1231
+ }
1232
+ resolvedIcons.sets.push("mdi");
1233
+ if (defaultSet === "mdi-svg") {
1234
+ resolvedIcons.defaultSet = "mdi";
1235
+ }
1236
+ } else {
1237
+ resolvedIcons.svg.mdi = false;
1238
+ logger.warn("Missing @mdi/js dependency, install it!");
1239
+ }
1240
+ }
1241
+ if (defaultSet !== "custom" && !resolvedIcons.unocss && !resolvedIcons.local?.length && !resolvedIcons.cdn?.length && !resolvedIcons.svg?.mdi && !resolvedIcons.svg?.fa?.length) {
1242
+ logger.warn("No icons found, icons disabled!");
1243
+ return disabledResolvedIcons;
1244
+ }
1245
+ return resolvedIcons;
1246
+ }
1247
+ function convertFontSetsToObjectNotation(sets) {
1248
+ const result = [];
1249
+ if (typeof sets === "string") {
1250
+ result.push({ name: sets });
1251
+ } else {
1252
+ for (const set of sets) {
1253
+ if (typeof set === "string") {
1254
+ result.push({ name: set });
1255
+ } else {
1256
+ result.push(set);
1257
+ }
1258
+ }
1113
1259
  }
1260
+ return result;
1114
1261
  }
1115
1262
 
1116
- function vuetifyDateConfigurationPlugin(ctx) {
1117
- return {
1118
- name: "vuetify:date-configuration:nuxt",
1119
- enforce: "pre",
1120
- resolveId(id) {
1121
- if (id === VIRTUAL_VUETIFY_DATE_CONFIGURATION)
1122
- return RESOLVED_VIRTUAL_VUETIFY_DATE_CONFIGURATION;
1123
- },
1124
- async load(id) {
1125
- if (id === RESOLVED_VIRTUAL_VUETIFY_DATE_CONFIGURATION) {
1126
- if (!ctx.dateAdapter) {
1127
- return `
1128
- export const enabled = false
1129
- export const isDev = ${ctx.isDev}
1130
- export const i18n = ${ctx.i18n}
1131
- export const adapter = 'custom'
1132
- export function dateConfiguration() {
1133
- return {}
1263
+ async function loadVuetifyConfiguration(cwd = process.cwd(), configOrPath = cwd, defaults = {}, extraConfigSources = []) {
1264
+ let inlineConfig = {};
1265
+ if (typeof configOrPath !== "string") {
1266
+ inlineConfig = configOrPath;
1267
+ configOrPath = process.cwd();
1268
+ }
1269
+ const resolved = resolve(cwd, configOrPath);
1270
+ let isFile = false;
1271
+ if (existsSync(resolved) && statSync(resolved).isFile()) {
1272
+ isFile = true;
1273
+ cwd = dirname(resolved).replace(/\\/g, "/");
1274
+ }
1275
+ const rewrite = (config) => {
1276
+ if (typeof config === "function") {
1277
+ return config();
1278
+ }
1279
+ return config;
1280
+ };
1281
+ const loader = createConfigLoader({
1282
+ sources: isFile ? [
1283
+ {
1284
+ files: resolved,
1285
+ extensions: [],
1286
+ rewrite
1287
+ }
1288
+ ] : [
1289
+ {
1290
+ files: [
1291
+ "vuetify.config"
1292
+ ],
1293
+ // we don't want `package.json` to be loaded
1294
+ extensions: ["mts", "cts", "ts", "mjs", "cjs", "js"],
1295
+ rewrite
1296
+ },
1297
+ ...extraConfigSources
1298
+ ],
1299
+ cwd,
1300
+ defaults: inlineConfig,
1301
+ merge: false
1302
+ });
1303
+ const result = await loader.load();
1304
+ result.config = result.config?.config === false ? Object.assign(defaults, inlineConfig) : Object.assign(defaults, result.config || inlineConfig);
1305
+ delete result.config.config;
1306
+ return result;
1134
1307
  }
1135
- `;
1308
+
1309
+ async function mergeVuetifyModules(options, nuxt) {
1310
+ const moduleOptions = [];
1311
+ const vuetifyConfigurationFilesToWatch = /* @__PURE__ */ new Set();
1312
+ await nuxt.callHook("vuetify:registerModule", (layerModuleOptions) => moduleOptions.push(layerModuleOptions));
1313
+ if (nuxt.options._layers.length > 1) {
1314
+ for (let i = 1; i < nuxt.options._layers.length; i++) {
1315
+ const layer = nuxt.options._layers[i];
1316
+ const resolvedOptions2 = await loadVuetifyConfiguration(
1317
+ layer.config.rootDir,
1318
+ layer.config.vuetify?.vuetifyOptions
1319
+ );
1320
+ if (resolvedOptions2.sources.length > 0) {
1321
+ for (const s of resolvedOptions2.sources.map((s2) => s2.replace(/\\/g, "/")).filter((s2) => !s2.includes("/node_modules/"))) {
1322
+ vuetifyConfigurationFilesToWatch.add(s);
1136
1323
  }
1137
- const { adapter: _adapter, ...newDateOptions } = ctx.vuetifyOptions.date ?? {};
1138
- return `${buildImports()}
1139
- export const enabled = true
1140
- export const isDev = ${ctx.isDev}
1141
- export const i18n = ${ctx.i18n}
1142
- export const adapter = '${ctx.dateAdapter}'
1143
- export function dateConfiguration() {
1144
- const options = JSON.parse('${JSON.stringify(newDateOptions)}')
1145
- ${buildAdapter()}
1146
- return options
1147
- }
1148
- `;
1149
1324
  }
1325
+ moduleOptions.push({
1326
+ moduleOptions: layer.config.vuetify?.moduleOptions,
1327
+ vuetifyOptions: resolvedOptions2.config
1328
+ });
1150
1329
  }
1151
- };
1152
- function buildAdapter() {
1153
- if (ctx.dateAdapter === "custom" || ctx.dateAdapter === "vuetify" && ctx.vuetifyGte("3.4.0"))
1154
- return "";
1155
- if (ctx.dateAdapter === "vuetify")
1156
- return "options.adapter = VuetifyDateAdapter";
1157
- const locale = ctx.vuetifyOptions.locale?.locale ?? "en";
1158
- if (ctx.dateAdapter === "date-fns")
1159
- return `options.adapter = new Adapter({ locale: ${locale} })`;
1160
- return "options.adapter = Adapter";
1161
1330
  }
1162
- function buildImports() {
1163
- if (ctx.dateAdapter === "custom" || ctx.dateAdapter === "vuetify" && ctx.vuetifyGte("3.4.0"))
1164
- return "";
1165
- if (ctx.dateAdapter === "vuetify")
1166
- return "import { VuetifyDateAdapter } from 'vuetify/labs/date/adapters/vuetify'";
1167
- const imports = [`import Adapter from '@date-io/${ctx.dateAdapter}'`];
1168
- if (ctx.dateAdapter === "date-fns")
1169
- imports.push(`import { ${ctx.vuetifyOptions.locale?.locale ?? "en"} } from 'date-fns/locale'`);
1170
- return imports.join("\n");
1331
+ const resolvedOptions = await loadVuetifyConfiguration(
1332
+ nuxt.options.rootDir,
1333
+ options.vuetifyOptions
1334
+ );
1335
+ if (nuxt.options.dev && resolvedOptions.sources.length > 0) {
1336
+ if (nuxt.options.ssr) {
1337
+ for (const s of resolvedOptions.sources) {
1338
+ nuxt.options.watch.push(s.replace(/\\/g, "/"));
1339
+ }
1340
+ } else {
1341
+ for (const s of resolvedOptions.sources) {
1342
+ vuetifyConfigurationFilesToWatch.add(s.replace(/\\/g, "/"));
1343
+ }
1344
+ }
1345
+ }
1346
+ moduleOptions.unshift({
1347
+ moduleOptions: options.moduleOptions,
1348
+ vuetifyOptions: resolvedOptions.config
1349
+ });
1350
+ if (moduleOptions.length > 1) {
1351
+ const [app, ...rest] = moduleOptions;
1352
+ const configuration = defu(app, ...rest);
1353
+ dedupeIcons(configuration, moduleOptions.toReversed());
1354
+ return {
1355
+ configuration,
1356
+ vuetifyConfigurationFilesToWatch
1357
+ };
1358
+ } else {
1359
+ return {
1360
+ configuration: {
1361
+ moduleOptions: options.moduleOptions,
1362
+ vuetifyOptions: resolvedOptions.config
1363
+ },
1364
+ vuetifyConfigurationFilesToWatch
1365
+ };
1171
1366
  }
1172
1367
  }
1173
-
1174
- function vuetifySSRClientHintsPlugin(ctx) {
1175
- return {
1176
- name: "vuetify:ssr-client-hints:nuxt",
1177
- enforce: "pre",
1178
- resolveId(id) {
1179
- if (id === VIRTUAL_VUETIFY_SSR_CLIENT_HINTS_CONFIGURATION)
1180
- return RESOLVED_VIRTUAL_VUETIFY_SSR_CLIENT_HINTS_CONFIGURATION;
1181
- },
1182
- async load(id) {
1183
- if (id === RESOLVED_VIRTUAL_VUETIFY_SSR_CLIENT_HINTS_CONFIGURATION) {
1184
- const data = {
1185
- reloadOnFirstRequest: ctx.ssrClientHints.reloadOnFirstRequest,
1186
- viewportSize: ctx.ssrClientHints.viewportSize,
1187
- prefersColorScheme: ctx.ssrClientHints.prefersColorScheme,
1188
- prefersReducedMotion: ctx.ssrClientHints.prefersReducedMotion,
1189
- clientWidth: ctx.vuetifyOptions.ssr?.clientWidth,
1190
- clientHeight: ctx.vuetifyOptions.ssr?.clientHeight,
1191
- prefersColorSchemeOptions: ctx.ssrClientHints.prefersColorSchemeOptions
1192
- };
1193
- return `export const ssrClientHintsConfiguration = JSON.parse('${JSON.stringify(data)}');`;
1368
+ function dedupeIcons(configuration, moduleOptions) {
1369
+ const vuetifyOptions = configuration.vuetifyOptions;
1370
+ if (vuetifyOptions.icons && vuetifyOptions.icons.sets) {
1371
+ const sets = /* @__PURE__ */ new Map();
1372
+ for (const { vuetifyOptions: vuetifyOptions2 } of moduleOptions) {
1373
+ if (vuetifyOptions2.icons && vuetifyOptions2.icons.sets) {
1374
+ const mSets = vuetifyOptions2.icons.sets;
1375
+ if (typeof mSets === "string") {
1376
+ sets.set(mSets, { name: mSets });
1377
+ } else {
1378
+ for (const set of mSets) {
1379
+ if (typeof set === "string") {
1380
+ sets.set(set, { name: set });
1381
+ } else {
1382
+ sets.set(set.name, set);
1383
+ }
1384
+ }
1385
+ }
1194
1386
  }
1195
1387
  }
1196
- };
1388
+ vuetifyOptions.icons.sets = Array.from(sets.values());
1389
+ }
1197
1390
  }
1198
1391
 
1199
- function parseId2(id) {
1200
- id = id.replace(/^(virtual:nuxt:|virtual:)/, "");
1201
- return parseURL(decodeURIComponent(isAbsolute(id) ? pathToFileURL(id).href : id));
1202
- }
1203
- function parseId(id) {
1204
- const { search, pathname } = parseId2(id);
1205
- const query = parseQuery(search);
1206
- const urlProps = query.props ? destr(query.props) : void 0;
1207
- return {
1208
- query: urlProps,
1209
- path: pathname ?? id
1392
+ const disabledClientHints = Object.freeze({
1393
+ enabled: false,
1394
+ reloadOnFirstRequest: false,
1395
+ viewportSize: false,
1396
+ prefersColorScheme: false,
1397
+ prefersReducedMotion: false
1398
+ });
1399
+ function prepareSSRClientHints(baseUrl, ctx) {
1400
+ if (!ctx.isSSR || ctx.isNuxtGenerate) {
1401
+ return disabledClientHints;
1402
+ }
1403
+ const { ssrClientHints: ssrClientHintsConfiguration } = ctx.moduleOptions;
1404
+ const clientHints = {
1405
+ enabled: false,
1406
+ reloadOnFirstRequest: ssrClientHintsConfiguration?.reloadOnFirstRequest ?? false,
1407
+ viewportSize: ssrClientHintsConfiguration?.viewportSize ?? false,
1408
+ prefersColorScheme: ssrClientHintsConfiguration?.prefersColorScheme ?? false,
1409
+ prefersReducedMotion: ssrClientHintsConfiguration?.prefersReducedMotion ?? false
1210
1410
  };
1211
- }
1212
- function vuetifyImportPlugin(options) {
1213
- let filter;
1214
- return {
1215
- name: "vuetify:import:nuxt",
1216
- configResolved(config) {
1217
- if (config.plugins.findIndex((plugin) => plugin.name === "vuetify:import") > -1)
1218
- throw new Error("Remove vite-plugin-vuetify from your Nuxt config file, this module registers a modified version.");
1219
- const vueIdx = config.plugins.findIndex((plugin) => plugin.name === "vite:vue");
1220
- const vueOptions = vueIdx > -1 ? config.plugins[vueIdx].api?.options : {};
1221
- filter = createFilter(vueOptions.include, vueOptions.exclude);
1222
- },
1223
- async transform(code, id) {
1224
- const { query, path } = parseId(id);
1225
- const isVueVirtual = query && "vue" in query;
1226
- const isVueFile = !isVueVirtual && filter(path) && !/^import { render as _sfc_render } from ".*"$/m.test(code);
1227
- const isVueTemplate = isVueVirtual && (query.type === "template" || query.type === "script" && query.setup === "true");
1228
- if (isVueFile || isVueTemplate) {
1229
- const { code: imports, source } = generateImports(code, options);
1230
- return {
1231
- code: source + imports,
1232
- map: null
1233
- };
1234
- }
1235
- return null;
1411
+ clientHints.enabled = clientHints.viewportSize || clientHints.prefersColorScheme || clientHints.prefersReducedMotion;
1412
+ if (clientHints.enabled && clientHints.prefersColorScheme && ssrClientHintsConfiguration?.prefersColorSchemeOptions) {
1413
+ const theme = ctx.vuetifyOptions.theme;
1414
+ if (!theme) {
1415
+ throw new Error("Vuetify theme is disabled");
1236
1416
  }
1237
- };
1238
- }
1239
-
1240
- function configureVite(configKey, nuxt, ctx) {
1241
- nuxt.hook("vite:extend", ({ config }) => checkVuetifyPlugins(config));
1242
- nuxt.hook("vite:extendConfig", (viteInlineConfig) => {
1243
- viteInlineConfig.plugins = viteInlineConfig.plugins || [];
1244
- checkVuetifyPlugins(viteInlineConfig);
1245
- viteInlineConfig.optimizeDeps = defu(viteInlineConfig.optimizeDeps, { exclude: ["vuetify"] });
1246
- if (ctx.isSSR) {
1247
- viteInlineConfig.ssr ||= {};
1248
- viteInlineConfig.ssr.noExternal = [
1249
- ...Array.isArray(viteInlineConfig.ssr.noExternal) ? viteInlineConfig.ssr.noExternal : viteInlineConfig.ssr.noExternal && typeof viteInlineConfig.ssr.noExternal !== "boolean" ? [viteInlineConfig.ssr.noExternal] : [],
1250
- configKey
1251
- ];
1417
+ const themes = theme.themes;
1418
+ if (!themes) {
1419
+ throw new Error("Vuetify themes is missing in theme!");
1252
1420
  }
1253
- const transformAssetUrls = createTransformAssetUrls(
1254
- ctx,
1255
- viteInlineConfig
1256
- );
1257
- if (transformAssetUrls) {
1258
- viteInlineConfig.vue ??= {};
1259
- viteInlineConfig.vue.template ??= {};
1260
- viteInlineConfig.vue.template.transformAssetUrls = transformAssetUrls;
1421
+ const defaultTheme = theme.defaultTheme;
1422
+ if (!defaultTheme) {
1423
+ throw new Error("Vuetify default theme is missing in theme!");
1261
1424
  }
1262
- if (!ctx.moduleOptions.disableModernSassCompiler) {
1263
- const enableModernSassCompiler = semver.gte(ctx.viteVersion, "5.4.0");
1264
- if (enableModernSassCompiler) {
1265
- const sassEmbedded = isPackageExists("sass-embedded");
1266
- if (sassEmbedded) {
1267
- viteInlineConfig.css ??= {};
1268
- viteInlineConfig.css.preprocessorOptions ??= {};
1269
- viteInlineConfig.css.preprocessorOptions.sass ??= {};
1270
- viteInlineConfig.css.preprocessorOptions.sass.api = "modern-compiler";
1271
- viteInlineConfig.css.preprocessorOptions.scss ??= {};
1272
- viteInlineConfig.css.preprocessorOptions.scss.api = "modern-compiler";
1273
- } else {
1274
- viteInlineConfig.css ??= {};
1275
- viteInlineConfig.css.preprocessorOptions ??= {};
1276
- viteInlineConfig.css.preprocessorOptions.sass ??= {};
1277
- viteInlineConfig.css.preprocessorOptions.sass.api = "modern";
1278
- viteInlineConfig.css.preprocessorOptions.scss ??= {};
1279
- viteInlineConfig.css.preprocessorOptions.scss.api = "modern";
1280
- if (!("preprocessorMaxWorkers" in viteInlineConfig.css))
1281
- viteInlineConfig.css.preprocessorMaxWorkers = true;
1282
- }
1283
- }
1425
+ if (!themes[defaultTheme]) {
1426
+ throw new Error(`Missing default theme ${defaultTheme} in the Vuetify themes!`);
1284
1427
  }
1285
- const autoImport = { labs: true };
1286
- const ignoreDirectives = ctx.moduleOptions.ignoreDirectives;
1287
- if (ignoreDirectives) {
1288
- autoImport.ignore = Array.isArray(ignoreDirectives) ? ignoreDirectives : [ignoreDirectives];
1428
+ const darkThemeName = ssrClientHintsConfiguration.prefersColorSchemeOptions?.darkThemeName ?? "dark";
1429
+ if (!themes[darkThemeName]) {
1430
+ throw new Error(`Missing theme ${darkThemeName} in the Vuetify themes!`);
1289
1431
  }
1290
- viteInlineConfig.plugins.push(vuetifyImportPlugin({ autoImport }));
1291
- if (typeof ctx.moduleOptions.styles !== "boolean")
1292
- viteInlineConfig.plugins.push(vuetifyStylesPlugin({ styles: ctx.moduleOptions.styles }, ctx.viteVersion, ctx.logger));
1293
- viteInlineConfig.plugins.push(vuetifyConfigurationPlugin(ctx));
1294
- viteInlineConfig.plugins.push(vuetifyIconsPlugin(ctx));
1295
- viteInlineConfig.plugins.push(vuetifyDateConfigurationPlugin(ctx));
1296
- if (ctx.ssrClientHints.enabled)
1297
- viteInlineConfig.plugins.push(vuetifySSRClientHintsPlugin(ctx));
1298
- });
1432
+ const lightThemeName = ssrClientHintsConfiguration.prefersColorSchemeOptions?.lightThemeName ?? "light";
1433
+ if (!themes[lightThemeName]) {
1434
+ throw new Error(`Missing theme ${lightThemeName} in the Vuetify themes!`);
1435
+ }
1436
+ if (darkThemeName === lightThemeName) {
1437
+ throw new Error("Vuetify dark theme and light theme are the same, change darkThemeName or lightThemeName!");
1438
+ }
1439
+ clientHints.prefersColorSchemeOptions = {
1440
+ baseUrl,
1441
+ defaultTheme,
1442
+ themeNames: Array.from(Object.keys(themes)),
1443
+ cookieName: ssrClientHintsConfiguration.prefersColorSchemeOptions?.cookieName ?? "color-scheme",
1444
+ darkThemeName,
1445
+ lightThemeName,
1446
+ useBrowserThemeOnly: ssrClientHintsConfiguration.prefersColorSchemeOptions?.useBrowserThemeOnly ?? false
1447
+ };
1448
+ }
1449
+ return clientHints;
1299
1450
  }
1300
1451
 
1301
- function addVuetifyNuxtPlugins(nuxt, ctx) {
1302
- addVuetifyNuxtPlugin(nuxt, ctx, "client");
1303
- addVuetifyNuxtPlugin(nuxt, ctx, "server");
1304
- }
1305
- function addVuetifyNuxtPlugin(nuxt, ctx, mode) {
1306
- addPluginTemplate({
1307
- filename: `vuetify-nuxt-plugin.${mode}.mjs`,
1308
- name: `vuetify:nuxt:${mode}:plugin`,
1309
- write: false,
1310
- mode,
1311
- getContents() {
1312
- const dependsOn = ["vuetify:icons:plugin"];
1313
- if (ctx.ssrClientHints.enabled) {
1314
- if (mode === "client")
1315
- dependsOn.push("vuetify:client-hints:client:plugin");
1316
- else
1317
- dependsOn.push("vuetify:client-hints:server:plugin");
1318
- }
1319
- if (ctx.i18n) {
1320
- dependsOn.push("vuetify:i18n:plugin");
1321
- }
1322
- if (nuxt.options.dev || ctx.dateAdapter) {
1323
- if (ctx.i18n) {
1324
- dependsOn.push("vuetify:date-i18n:plugin");
1452
+ async function load(options, nuxt, ctx) {
1453
+ const {
1454
+ configuration,
1455
+ vuetifyConfigurationFilesToWatch
1456
+ } = await mergeVuetifyModules(options, nuxt);
1457
+ if (ctx.componentsPromise === void 0) {
1458
+ const {
1459
+ componentsPromise,
1460
+ labComponentsPromise
1461
+ } = resolveVuetifyComponents(ctx.resolver);
1462
+ ctx.componentsPromise = componentsPromise;
1463
+ ctx.labComponentsPromise = labComponentsPromise;
1464
+ }
1465
+ const { vuetifyOptions = {} } = configuration;
1466
+ const {
1467
+ directives: _directives,
1468
+ labComponents: _labComponents,
1469
+ ...vOptions
1470
+ } = vuetifyOptions;
1471
+ const vuetifyAppOptions = defu(vOptions, {});
1472
+ cleanupBlueprint(vuetifyAppOptions);
1473
+ ctx.dateAdapter = void 0;
1474
+ const dateOptions = vuetifyOptions.date;
1475
+ if (dateOptions) {
1476
+ const adapter = dateOptions.adapter;
1477
+ const date = detectDate();
1478
+ if (!adapter && date.length > 1) {
1479
+ 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.`);
1480
+ }
1481
+ if (adapter) {
1482
+ if (adapter === "vuetify" || adapter === "custom") {
1483
+ ctx.dateAdapter = adapter;
1484
+ } else {
1485
+ if (date.includes(adapter)) {
1486
+ ctx.dateAdapter = adapter;
1325
1487
  } else {
1326
- dependsOn.push("vuetify:date:plugin");
1488
+ ctx.logger.warn(`[vuetify-nuxt-module] Ignoring Vuetify Date configuration, date adapter "@date-io/${adapter}" not installed!`);
1327
1489
  }
1328
1490
  }
1329
- let rulesImports = "";
1330
- let rulesPlugin = "";
1331
- if (mode === "client" && ctx.enableRules) {
1332
- rulesImports = [
1333
- "",
1334
- `import { rulesOptions } from '#build/vuetify/${ctx.rulesConfiguration.fromLabs ? "labs-" : ""}rules-configuration.mjs'`,
1335
- `import { createRulesPlugin } from 'vuetify/${ctx.rulesConfiguration.fromLabs ? "labs/" : ""}rules'`
1336
- ].join("\n");
1337
- rulesPlugin = [
1338
- "",
1339
- " nuxtApp.vueApp.use(createRulesPlugin(rulesOptions, vuetify.locale))"
1340
- ].join("\n");
1341
- }
1342
- return `
1343
- import { defineNuxtPlugin } from '#imports'
1344
- import { isDev, vuetifyConfiguration } from 'virtual:vuetify-configuration'
1345
- import { createVuetify } from 'vuetify'${rulesImports}
1346
-
1347
- export default defineNuxtPlugin({
1348
- name: 'vuetify:nuxt:${mode}:plugin',
1349
- order: 25,
1350
- dependsOn: ${JSON.stringify(dependsOn)},
1351
- parallel: true,
1352
- async setup(nuxtApp) {
1353
- const vuetifyOptions = vuetifyConfiguration()
1354
- await nuxtApp.hooks.callHook('vuetify:configuration', { isDev, vuetifyOptions })
1355
- await nuxtApp.hooks.callHook('vuetify:before-create', { isDev, vuetifyOptions })
1356
- const vuetify = createVuetify(vuetifyOptions)
1357
- nuxtApp.vueApp.use(vuetify)${rulesPlugin}
1358
- nuxtApp.provide('vuetify', vuetify)
1359
- await nuxtApp.hooks.callHook('vuetify:ready', vuetify)
1360
- if (import.meta.client)
1361
- isDev && console.log('Vuetify 3 initialized', vuetify)
1362
- },
1363
- })
1364
- `;
1491
+ } else if (date.length === 0) {
1492
+ ctx.dateAdapter = "vuetify";
1493
+ } else {
1494
+ ctx.dateAdapter = date[0];
1365
1495
  }
1366
- });
1367
- }
1368
-
1369
- function configureNuxt(configKey, nuxt, ctx) {
1370
- const {
1371
- styles,
1372
- importComposables,
1373
- prefixComposables,
1374
- disableVuetifyStyles
1375
- } = ctx.moduleOptions;
1376
- const runtimeDir = ctx.resolver.resolve("./runtime");
1377
- if (typeof ctx.enableRules !== "undefined")
1378
- ctx.enableRules = ctx.vuetifyGte("3.8.0");
1379
- if (ctx.isSSR && !!styles && typeof styles === "object")
1380
- nuxt.options.features.inlineStyles = false;
1381
- if (!disableVuetifyStyles) {
1382
- nuxt.options.css ??= [];
1383
- nuxt.options.css.unshift("vuetify/styles");
1384
1496
  }
1385
- nuxt.options.build.transpile.push(configKey);
1386
- nuxt.options.build.transpile.push(runtimeDir);
1387
- if (ctx.enableRules)
1388
- nuxt.options.build.transpile.push(`#build/vuetify/${ctx.rulesConfiguration.fromLabs ? "labs-" : ""}rules-configuration.mjs`);
1389
- nuxt.options.build.transpile.push(/\/vuetify-nuxt-plugin\.(client|server)\.mjs$/);
1390
- nuxt.options.imports.transform ??= {};
1391
- nuxt.options.imports.transform.include ??= [];
1392
- for (const virtual of RESOLVED_VIRTUAL_MODULES)
1393
- nuxt.options.imports.transform.include.push(new RegExp(`${virtual}$`));
1394
- extendWebpackConfig(() => {
1395
- throw new Error("Webpack is not supported: vuetify-nuxt-module module can only be used with Vite!");
1396
- });
1397
- const v4Available = isNuxtMajorVersion(4, nuxt);
1398
- nuxt.hook("prepare:types", ({ references, nodeReferences }) => {
1399
- references.push({ types: "vuetify" });
1400
- references.push({ types: "vuetify-nuxt-module/custom-configuration" });
1401
- references.push({ types: "vuetify-nuxt-module/configuration" });
1402
- references.push({ path: ctx.resolver.resolve(runtimeDir, "plugins/types") });
1403
- if (ctx.enableRules)
1404
- references.push({ types: `vuetify-nuxt-module/custom-${ctx.rulesConfiguration.fromLabs ? "labs-" : ""}rules-configuration` });
1405
- if (v4Available) {
1406
- nodeReferences.push({ types: "vuetify-nuxt-module/custom-configuration" });
1407
- if (ctx.enableRules)
1408
- nodeReferences.push({ types: `vuetify-nuxt-module/custom-${ctx.rulesConfiguration.fromLabs ? "labs-" : ""}rules-configuration` });
1497
+ const oldIcons = ctx.icons;
1498
+ if (oldIcons && oldIcons.cdn?.length && nuxt.options.app.head.link) {
1499
+ nuxt.options.app.head.link = nuxt.options.app.head.link.filter((link) => !link.key || !oldIcons.cdn.some(([key]) => link.key === key));
1500
+ }
1501
+ ctx.moduleOptions = configuration.moduleOptions;
1502
+ ctx.vuetifyOptions = configuration.vuetifyOptions;
1503
+ ctx.enableRules = ctx.moduleOptions.enableRules;
1504
+ ctx.rulesConfiguration = ctx.moduleOptions.rulesConfiguration;
1505
+ ctx.vuetifyFilesToWatch = Array.from(vuetifyConfigurationFilesToWatch);
1506
+ ctx.icons = prepareIcons(ctx.unocss, ctx.logger, vuetifyAppOptions);
1507
+ ctx.ssrClientHints = prepareSSRClientHints(nuxt.options.app.baseURL ?? "/", ctx);
1508
+ if (ctx.icons.enabled) {
1509
+ if (ctx.icons.local) {
1510
+ for (const css of ctx.icons.local) {
1511
+ nuxt.options.css.push(css);
1512
+ }
1409
1513
  }
1410
- });
1411
- if (importComposables) {
1412
- const composables = ["useDate", "useLocale", "useDefaults", "useDisplay", "useLayout", "useRtl", "useTheme"];
1413
- if (ctx.vuetifyGte("3.5.0"))
1414
- composables.push("useGoTo");
1415
- if (ctx.vuetifyGte("3.8.0")) {
1416
- composables.push("useHotkey");
1417
- if (ctx.enableRules)
1418
- composables.push("useRules");
1514
+ if (ctx.icons.cdn?.length) {
1515
+ nuxt.options.app.head.link ??= [];
1516
+ for (const [key, href] of ctx.icons.cdn) {
1517
+ nuxt.options.app.head.link.push({
1518
+ key,
1519
+ rel: "stylesheet",
1520
+ href,
1521
+ type: "text/css",
1522
+ crossorigin: "anonymous"
1523
+ });
1524
+ }
1419
1525
  }
1420
- if (ctx.vuetifyGte("3.10.0"))
1421
- composables.push("useMask");
1422
- addImports(composables.map((name) => ({
1423
- name,
1424
- from: ctx.vuetifyGte("3.4.0") || name !== "useDate" ? "vuetify" : "vuetify/labs/date",
1425
- as: prefixComposables ? name.replace(/^use/, "useV") : void 0,
1426
- meta: { docsUrl: name === "useRules" ? "https://vuetifyjs.com/en/features/rules/" : `https://vuetifyjs.com/en/api/${toKebabCase(name)}/` }
1427
- })));
1428
1526
  }
1429
- if (ctx.ssrClientHints.enabled) {
1430
- addPlugin({
1431
- src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-client-hints.client"),
1432
- mode: "client"
1433
- });
1434
- addPlugin({
1435
- src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-client-hints.server"),
1436
- mode: "server"
1527
+ }
1528
+ function registerWatcher(options, nuxt, ctx) {
1529
+ if (nuxt.options.dev) {
1530
+ let pageReload;
1531
+ nuxt.hooks.hook("builder:watch", (_event, path) => {
1532
+ path = relative$1(nuxt.options.srcDir, resolve(nuxt.options.srcDir, path));
1533
+ if (!pageReload && ctx.vuetifyFilesToWatch.includes(path)) {
1534
+ return nuxt.callHook("restart");
1535
+ }
1437
1536
  });
1438
- } else {
1439
- addPlugin({
1440
- src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-no-client-hints")
1537
+ nuxt.hook("vite:serverCreated", (server, { isClient }) => {
1538
+ if (!server.ws || !isClient) {
1539
+ return;
1540
+ }
1541
+ pageReload = debounce(async () => {
1542
+ const modules = [];
1543
+ for (const v of RESOLVED_VIRTUAL_MODULES) {
1544
+ const module = server.moduleGraph.getModuleById(v);
1545
+ if (module) {
1546
+ modules.push(module);
1547
+ }
1548
+ }
1549
+ await load(options, nuxt, ctx);
1550
+ if (modules.length > 0) {
1551
+ await Promise.all(modules.map((m) => server.reloadModule(m)));
1552
+ }
1553
+ }, 50, { trailing: false });
1441
1554
  });
1442
- }
1443
- addPlugin({
1444
- src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-icons")
1445
- });
1446
- if (ctx.i18n) {
1447
- addPlugin({
1448
- src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-i18n")
1555
+ addVitePlugin({
1556
+ name: "vuetify:configuration:watch",
1557
+ enforce: "pre",
1558
+ handleHotUpdate({ file }) {
1559
+ if (pageReload && ctx.vuetifyFilesToWatch.includes(file)) {
1560
+ return pageReload();
1561
+ }
1562
+ }
1449
1563
  });
1450
1564
  }
1451
- if (nuxt.options.dev || ctx.dateAdapter) {
1452
- if (ctx.i18n) {
1453
- addPlugin({
1454
- src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-i18n-date")
1455
- });
1456
- } else {
1457
- addPlugin({
1458
- src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-date")
1459
- });
1460
- }
1461
- }
1462
- addVuetifyNuxtPlugins(nuxt, ctx);
1463
1565
  }
1464
1566
 
1465
1567
  const CONFIG_KEY = "vuetify";
@@ -1473,7 +1575,9 @@ const module$1 = defineNuxtModule({
1473
1575
  },
1474
1576
  version
1475
1577
  },
1476
- // Default configuration options of the Nuxt module
1578
+ /**
1579
+ * Default configuration options of the Nuxt module
1580
+ */
1477
1581
  defaults: () => ({
1478
1582
  vuetifyOptions: {
1479
1583
  labComponents: false,
@@ -1484,15 +1588,21 @@ const module$1 = defineNuxtModule({
1484
1588
  includeTransformAssetsUrls: true,
1485
1589
  styles: true,
1486
1590
  disableVuetifyStyles: false,
1487
- disableModernSassCompiler: false,
1488
1591
  rulesConfiguration: {
1489
1592
  fromLabs: true
1490
1593
  }
1491
1594
  }
1492
1595
  }),
1596
+ /**
1597
+ * Sets up the Vuetify Nuxt module.
1598
+ *
1599
+ * @param options - The module options.
1600
+ * @param nuxt - The Nuxt instance.
1601
+ */
1493
1602
  async setup(options, nuxt) {
1494
- if (isNuxtMajorVersion(2, nuxt))
1603
+ if (isNuxtMajorVersion(2, nuxt)) {
1495
1604
  logger.error(`Cannot support nuxt version: ${getNuxtVersion(nuxt)}`);
1605
+ }
1496
1606
  const vuetifyPkg = await getPackageInfo("vuetify");
1497
1607
  const currentVersion = vuetifyPkg?.version;
1498
1608
  const vuetifyGte = (version2) => !!currentVersion && semver.gte(currentVersion, version2);
@@ -1516,7 +1626,7 @@ const module$1 = defineNuxtModule({
1516
1626
  viteVersion
1517
1627
  };
1518
1628
  await load(options, nuxt, ctx);
1519
- configureNuxt(CONFIG_KEY, nuxt, ctx);
1629
+ await configureNuxt(CONFIG_KEY, nuxt, ctx);
1520
1630
  registerWatcher(options, nuxt, ctx);
1521
1631
  configureVite(CONFIG_KEY, nuxt, ctx);
1522
1632
  }