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

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.3";
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,298 @@ 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");
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
+ }
148
+ }
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");
157
+ }
158
+ }
159
+ let rulesImports = "";
160
+ let rulesPlugin = "";
161
+ if (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");
171
+ }
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
+ `;
279
193
  }
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'");
194
+ });
195
+ }
196
+
197
+ function getTemplate(source, settings) {
198
+ return [settings ? `@use '${settings}';` : "", `@use '${source}';`].filter(Boolean).join("\n");
199
+ }
200
+ async function configureNuxt(configKey, nuxt, ctx) {
201
+ const {
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");
209
+ }
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"));
295
222
  }
296
- resolvedIcons.defaultSet = "mdi";
223
+ if (typeof styles === "object" && styles?.colors !== false) {
224
+ nuxt.options.css.push(await resolvePath("vuetify/styles/colors"));
225
+ }
226
+ } else {
227
+ nuxt.options.css.push(await resolvePath("vuetify/styles"));
297
228
  }
298
229
  }
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!`);
230
+ nuxt.options.build.transpile.push(configKey, runtimeDir);
231
+ if (ctx.enableRules) {
232
+ const rulesConfigurationFile = `vuetify/${ctx.rulesConfiguration.fromLabs ? "labs-" : ""}rules-configuration.mjs`;
233
+ nuxt.options.build.transpile.push(`#build/${rulesConfigurationFile}`);
234
+ addTemplate({
235
+ filename: rulesConfigurationFile,
236
+ getContents: async () => {
237
+ if (ctx.rulesConfiguration?.configFile) {
238
+ const resolvedPath = await resolvePath(ctx.rulesConfiguration.configFile);
239
+ return `export { default as rulesOptions } from '${resolvedPath}'`;
315
240
  }
241
+ return "export const rulesOptions = {}";
242
+ },
243
+ write: true
244
+ });
245
+ }
246
+ nuxt.options.build.transpile.push(/\/vuetify-nuxt-plugin\.(client|server)\.mjs$/);
247
+ nuxt.options.imports.transform ??= {};
248
+ nuxt.options.imports.transform.include ??= [];
249
+ for (const virtual of RESOLVED_VIRTUAL_MODULES) {
250
+ nuxt.options.imports.transform.include.push(new RegExp(`${virtual}$`));
251
+ }
252
+ extendWebpackConfig(() => {
253
+ throw new Error("Webpack is not supported: vuetify-nuxt-module module can only be used with Vite!");
254
+ });
255
+ const v4Available = isNuxtMajorVersion(4, nuxt);
256
+ nuxt.hook("prepare:types", ({ references, nodeReferences }) => {
257
+ references.push({ types: "vuetify" }, { types: "vuetify-nuxt-module/custom-configuration" }, { types: "vuetify-nuxt-module/configuration" }, { path: ctx.resolver.resolve(runtimeDir, "plugins/types") });
258
+ if (ctx.enableRules) {
259
+ references.push({ types: `vuetify-nuxt-module/custom-${ctx.rulesConfiguration.fromLabs ? "labs-" : ""}rules-configuration` });
260
+ }
261
+ if (v4Available) {
262
+ nodeReferences.push({ types: "vuetify-nuxt-module/custom-configuration" });
263
+ if (ctx.enableRules) {
264
+ nodeReferences.push({ types: `vuetify-nuxt-module/custom-${ctx.rulesConfiguration.fromLabs ? "labs-" : ""}rules-configuration` });
316
265
  }
317
- } else {
318
- logger.warn("Missing @fortawesome/vue-fontawesome dependency, install it!");
319
266
  }
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";
267
+ });
268
+ if (importComposables) {
269
+ const composables = ["useDate", "useLocale", "useDefaults", "useDisplay", "useLayout", "useRtl", "useTheme"];
270
+ if (ctx.vuetifyGte("3.5.0")) {
271
+ composables.push("useGoTo");
334
272
  }
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
- });
273
+ if (ctx.vuetifyGte("3.8.0")) {
274
+ composables.push("useHotkey");
275
+ if (ctx.enableRules) {
276
+ composables.push("useRules");
350
277
  }
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
278
  }
279
+ if (ctx.vuetifyGte("3.10.0")) {
280
+ composables.push("useMask");
281
+ }
282
+ addImports(composables.map((name) => {
283
+ let from = ctx.vuetifyGte("3.4.0") || name !== "useDate" ? "vuetify" : "vuetify/labs/date";
284
+ if (name === "useRules" && ctx.rulesConfiguration?.fromLabs) {
285
+ from = "vuetify/labs/rules";
286
+ }
287
+ return {
288
+ name,
289
+ from,
290
+ as: prefixComposables ? name.replace(/^use/, "useV") : void 0,
291
+ meta: { docsUrl: name === "useRules" ? "https://vuetifyjs.com/en/features/rules/" : `https://vuetifyjs.com/en/api/${toKebabCase(name)}/` }
292
+ };
293
+ }));
358
294
  }
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 });
295
+ if (ctx.ssrClientHints.enabled) {
296
+ addPlugin({
297
+ src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-client-hints.client"),
298
+ mode: "client"
299
+ });
300
+ addPlugin({
301
+ src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-client-hints.server"),
302
+ mode: "server"
303
+ });
369
304
  } else {
370
- for (const set of sets) {
371
- if (typeof set === "string")
372
- result.push({ name: set });
373
- else
374
- result.push(set);
305
+ addPlugin({
306
+ src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-no-client-hints")
307
+ });
308
+ }
309
+ addPlugin({
310
+ src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-icons")
311
+ });
312
+ if (ctx.i18n) {
313
+ addPlugin({
314
+ src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-i18n")
315
+ });
316
+ }
317
+ if (nuxt.options.dev || ctx.dateAdapter) {
318
+ if (ctx.i18n) {
319
+ addPlugin({
320
+ src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-i18n-date")
321
+ });
322
+ } else {
323
+ addPlugin({
324
+ src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-date")
325
+ });
375
326
  }
376
327
  }
377
- return result;
378
- }
379
-
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;
430
- }
431
-
432
- async function load(options, nuxt, ctx) {
433
- 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;
444
- }
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;
468
- }
469
- } else if (date.length === 0) {
470
- ctx.dateAdapter = "vuetify";
471
- } else {
472
- ctx.dateAdapter = date[0];
473
- }
474
- }
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
- }
497
- }
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
- });
530
- }
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
- }
595
- }
596
- return isNone && noneFiles.has(id) ? "" : void 0;
597
- }
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");
612
- }
613
- mappings.set(source, mapping);
614
- }
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 ?? {};
662
- }
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]];
683
- }
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}`);
704
- }
705
- return [...result];
328
+ addVuetifyNuxtPlugins(nuxt, ctx);
706
329
  }
707
330
 
708
331
  function vuetifyConfigurationPlugin(ctx) {
@@ -710,8 +333,9 @@ function vuetifyConfigurationPlugin(ctx) {
710
333
  name: "vuetify:configuration:nuxt",
711
334
  enforce: "pre",
712
335
  resolveId(id) {
713
- if (id === VIRTUAL_VUETIFY_CONFIGURATION)
336
+ if (id === VIRTUAL_VUETIFY_CONFIGURATION) {
714
337
  return RESOLVED_VIRTUAL_VUETIFY_CONFIGURATION;
338
+ }
715
339
  },
716
340
  async load(id) {
717
341
  if (id === RESOLVED_VIRTUAL_VUETIFY_CONFIGURATION) {
@@ -726,8 +350,9 @@ function vuetifyConfigurationPlugin(ctx) {
726
350
  aliases: _aliases,
727
351
  ...newVuetifyOptions
728
352
  } = ctx.vuetifyOptions;
729
- if (ctx.isSSR)
353
+ if (ctx.isSSR) {
730
354
  newVuetifyOptions.ssr = ssr ?? true;
355
+ }
731
356
  if (ctx.i18n && newVuetifyOptions.locale) {
732
357
  delete newVuetifyOptions.locale.rtl;
733
358
  delete newVuetifyOptions.locale.locale;
@@ -798,78 +423,85 @@ async function buildConfiguration(ctx) {
798
423
  }
799
424
  const importMapComponents = await componentsPromise;
800
425
  const componentsToImport = /* @__PURE__ */ new Map();
801
- config.components.forEach((component) => {
426
+ for (const component of config.components) {
802
427
  const { from } = importMapComponents[component];
803
428
  if (!from) {
804
429
  logger.warn(`Component ${component} not found in Vuetify.`);
805
- return;
430
+ continue;
806
431
  }
807
432
  const parts = from.split("/");
808
433
  if (parts.length < 2) {
809
434
  logger.warn(`Component ${component} not found in Vuetify, please report a new issue.`);
810
- return;
435
+ continue;
811
436
  }
812
- if (!componentsToImport.has(parts[1]))
437
+ if (!componentsToImport.has(parts[1])) {
813
438
  componentsToImport.set(parts[1], []);
439
+ }
814
440
  const componentsArray = componentsToImport.get(parts[1]);
815
- if (!componentsArray.includes(component))
441
+ if (!componentsArray.includes(component)) {
816
442
  componentsArray.push(component);
817
- });
818
- Object.entries(config.aliases).forEach(([key, component]) => {
443
+ }
444
+ }
445
+ for (const [key, component] of Object.entries(config.aliases)) {
819
446
  const { from } = importMapComponents[component];
820
447
  if (!from) {
821
448
  logger.warn(`Component ${component} not found in Vuetify.`);
822
- return;
449
+ continue;
823
450
  }
824
451
  const parts = from.split("/");
825
452
  if (parts.length < 2) {
826
453
  logger.warn(`Component ${component} not found in Vuetify, please report a new issue.`);
827
- return;
454
+ continue;
828
455
  }
829
- if (!componentsToImport.has(parts[1]))
456
+ if (!componentsToImport.has(parts[1])) {
830
457
  componentsToImport.set(parts[1], []);
458
+ }
831
459
  const componentsArray = componentsToImport.get(parts[1]);
832
- if (!componentsArray.includes(component))
460
+ if (!componentsArray.includes(component)) {
833
461
  componentsArray.push(component);
462
+ }
834
463
  config.aliasEntries.push(`'${key}': ${component}`);
835
- });
836
- componentsToImport.forEach((componentsArray, from) => {
464
+ }
465
+ for (const [from, componentsArray] of componentsToImport.entries()) {
837
466
  config.imports.push(`import {${Array.from(new Set(componentsArray)).join(",")}} from 'vuetify/components/${from}'`);
838
- });
467
+ }
839
468
  let addDatePicker = ctx.vuetifyGte("3.4.0") ? !Array.from(componentsToImport.values()).some((components2) => components2.includes("VDatePicker")) : true;
840
469
  if (labComponents) {
841
470
  const useLabComponents = [];
842
471
  if (typeof labComponents === "boolean") {
843
472
  config.imports.push("import * as labsComponents from 'vuetify/labs/components'");
844
473
  config.labComponents.add("*");
845
- if (!ctx.vuetifyGte("3.4.0"))
474
+ if (!ctx.vuetifyGte("3.4.0")) {
846
475
  addDatePicker = false;
476
+ }
847
477
  } else if (typeof labComponents === "string") {
848
478
  useLabComponents.push(labComponents);
849
479
  } else if (Array.isArray(labComponents)) {
850
480
  useLabComponents.push(...labComponents);
851
481
  }
852
- if (useLabComponents.length) {
482
+ if (useLabComponents.length > 0) {
853
483
  componentsToImport.clear();
854
484
  const importMapLabComponents = await labComponentsPromise;
855
- useLabComponents.forEach((component) => {
485
+ for (const component of useLabComponents) {
856
486
  const { from } = importMapLabComponents[component];
857
487
  if (!from) {
858
488
  logger.warn(`Lab Component ${component} not found in Vuetify.`);
859
- return;
489
+ continue;
860
490
  }
861
491
  const parts = from.split("/");
862
492
  if (parts.length < 2) {
863
493
  logger.warn(`Lab Component ${component} not found in Vuetify, please report a new issue.`);
864
- return;
494
+ continue;
865
495
  }
866
- if (!componentsToImport.has(parts[1]))
496
+ if (!componentsToImport.has(parts[1])) {
867
497
  componentsToImport.set(parts[1], []);
498
+ }
868
499
  const componentsArray = componentsToImport.get(parts[1]);
869
- if (!componentsArray.includes(component))
500
+ if (!componentsArray.includes(component)) {
870
501
  componentsArray.push(component);
502
+ }
871
503
  config.labComponents.add(component);
872
- });
504
+ }
873
505
  if (!ctx.vuetifyGte("3.4.0") && dateOptions && !addDatePicker) {
874
506
  const entry = componentsToImport.get("VDatePicker");
875
507
  if (entry) {
@@ -878,9 +510,9 @@ async function buildConfiguration(ctx) {
878
510
  addDatePicker = false;
879
511
  }
880
512
  }
881
- componentsToImport.forEach((componentsArray, from) => {
513
+ for (const [from, componentsArray] of componentsToImport.entries()) {
882
514
  config.imports.push(`import {${Array.from(new Set(componentsArray)).join(",")}} from 'vuetify/labs/${from}'`);
883
- });
515
+ }
884
516
  }
885
517
  }
886
518
  if (dateOptions && addDatePicker) {
@@ -898,20 +530,14 @@ async function buildConfiguration(ctx) {
898
530
  warn && logger.warn("Unable to load Vuetify version from package.json, add VDatePicker to components or labComponents");
899
531
  }
900
532
  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(",")}}`;
533
+ if (config.components.size > 0) {
534
+ if (config.labComponents.size > 0) {
535
+ 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
536
  } else {
908
537
  componentsEntry = `options.components = {${Array.from(config.components).join(",")}}`;
909
538
  }
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(",")}}`;
539
+ } else if (config.labComponents.size > 0) {
540
+ componentsEntry = config.labComponents.has("*") ? "options.components = {...labsComponents}" : `options.components = {${Array.from(config.labComponents).join(",")}}`;
915
541
  }
916
542
  if (!ctx.i18n && localeMessages) {
917
543
  const useLocales = Array.isArray(localeMessages) ? [...new Set(localeMessages)] : [localeMessages];
@@ -930,21 +556,87 @@ ${useLocales.map((locale) => {
930
556
  `;
931
557
  }
932
558
  return {
933
- imports: config.imports.length ? config.imports.join("\n") : "",
559
+ imports: config.imports.length > 0 ? config.imports.join("\n") : "",
934
560
  components: componentsEntry,
935
- aliases: config.aliasEntries.length ? `options.aliases = {${config.aliasEntries.join(",")}}` : "",
561
+ aliases: config.aliasEntries.length > 0 ? `options.aliases = {${config.aliasEntries.join(",")}}` : "",
936
562
  directives: config.directives,
937
563
  messages: config.messages
938
564
  };
939
565
  }
940
566
 
567
+ function vuetifyDateConfigurationPlugin(ctx) {
568
+ return {
569
+ name: "vuetify:date-configuration:nuxt",
570
+ enforce: "pre",
571
+ resolveId(id) {
572
+ if (id === VIRTUAL_VUETIFY_DATE_CONFIGURATION) {
573
+ return RESOLVED_VIRTUAL_VUETIFY_DATE_CONFIGURATION;
574
+ }
575
+ },
576
+ async load(id) {
577
+ if (id === RESOLVED_VIRTUAL_VUETIFY_DATE_CONFIGURATION) {
578
+ if (!ctx.dateAdapter) {
579
+ return `
580
+ export const enabled = false
581
+ export const isDev = ${ctx.isDev}
582
+ export const i18n = ${ctx.i18n}
583
+ export const adapter = 'custom'
584
+ export function dateConfiguration() {
585
+ return {}
586
+ }
587
+ `;
588
+ }
589
+ const { adapter: _adapter, ...newDateOptions } = ctx.vuetifyOptions.date ?? {};
590
+ return `${buildImports()}
591
+ export const enabled = true
592
+ export const isDev = ${ctx.isDev}
593
+ export const i18n = ${ctx.i18n}
594
+ export const adapter = '${ctx.dateAdapter}'
595
+ export function dateConfiguration() {
596
+ const options = JSON.parse('${JSON.stringify(newDateOptions)}')
597
+ ${buildAdapter()}
598
+ return options
599
+ }
600
+ `;
601
+ }
602
+ }
603
+ };
604
+ function buildAdapter() {
605
+ if (ctx.dateAdapter === "custom" || ctx.dateAdapter === "vuetify" && ctx.vuetifyGte("3.4.0")) {
606
+ return "";
607
+ }
608
+ if (ctx.dateAdapter === "vuetify") {
609
+ return "options.adapter = VuetifyDateAdapter";
610
+ }
611
+ const locale = ctx.vuetifyOptions.locale?.locale ?? "en";
612
+ if (ctx.dateAdapter === "date-fns") {
613
+ return `options.adapter = new Adapter({ locale: ${locale} })`;
614
+ }
615
+ return "options.adapter = Adapter";
616
+ }
617
+ function buildImports() {
618
+ if (ctx.dateAdapter === "custom" || ctx.dateAdapter === "vuetify" && ctx.vuetifyGte("3.4.0")) {
619
+ return "";
620
+ }
621
+ if (ctx.dateAdapter === "vuetify") {
622
+ return "import { VuetifyDateAdapter } from 'vuetify/labs/date/adapters/vuetify'";
623
+ }
624
+ const imports = [`import Adapter from '@date-io/${ctx.dateAdapter}'`];
625
+ if (ctx.dateAdapter === "date-fns") {
626
+ imports.push(`import { ${ctx.vuetifyOptions.locale?.locale ?? "en"} } from 'date-fns/locale'`);
627
+ }
628
+ return imports.join("\n");
629
+ }
630
+ }
631
+
941
632
  function vuetifyIconsPlugin(ctx) {
942
633
  return {
943
634
  name: "vuetify:icons-configuration:nuxt",
944
635
  enforce: "pre",
945
636
  resolveId(id) {
946
- if (id === VIRTUAL_VUETIFY_ICONS_CONFIGURATION)
637
+ if (id === VIRTUAL_VUETIFY_ICONS_CONFIGURATION) {
947
638
  return RESOLVED_VIRTUAL_VUETIFY_ICONS_CONFIGURATION;
639
+ }
948
640
  },
949
641
  async load(id) {
950
642
  if (id === RESOLVED_VIRTUAL_VUETIFY_ICONS_CONFIGURATION) {
@@ -1006,7 +698,7 @@ ${unocss}
1006
698
  aliases = "";
1007
699
  } else {
1008
700
  const alias = ctx.icons.aliases;
1009
- if (alias.length) {
701
+ if (alias.length > 0) {
1010
702
  aliases = `aliases: {
1011
703
  ...aliases,
1012
704
  ${alias.join(",\n")}
@@ -1095,371 +787,799 @@ ${unocss}
1095
787
  minus,
1096
788
  calendar
1097
789
  };
1098
- Object.entries(ctx.icons.unocssAdditionalIcons).forEach(([key, value]) => {
790
+ for (const [key, value] of Object.entries(ctx.icons.unocssAdditionalIcons)) {
1099
791
  useIcons[key] = value;
1100
- });
792
+ }
1101
793
  unocss = `const aliases = JSON.parse('${JSON.stringify(useIcons)}');
1102
794
  `;
1103
795
  }
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
- };
796
+ return {
797
+ enabled: true,
798
+ unocss,
799
+ fa: ctx.icons.svg?.fa ?? [],
800
+ defaultSet: ctx.icons.defaultSet,
801
+ imports: Object.values(ctx.icons.imports).join("\n"),
802
+ sets: ctx.icons.sets.join(","),
803
+ aliases
804
+ };
805
+ }
806
+ }
807
+
808
+ function parseId2(id) {
809
+ id = id.replace(/^(virtual:nuxt:|virtual:)/, "");
810
+ return parseURL(decodeURIComponent(isAbsolute(id) ? pathToFileURL(id).href : id));
811
+ }
812
+ function parseId(id) {
813
+ const { search, pathname } = parseId2(id);
814
+ const query = parseQuery(search);
815
+ const urlProps = query.props ? destr(query.props) : void 0;
816
+ return {
817
+ query: urlProps,
818
+ path: pathname ?? id
819
+ };
820
+ }
821
+ function vuetifyImportPlugin(options) {
822
+ let filter;
823
+ return {
824
+ name: "vuetify:import:nuxt",
825
+ configResolved(config) {
826
+ if (config.plugins.some((plugin) => plugin.name === "vuetify:import")) {
827
+ throw new Error("Remove vite-plugin-vuetify from your Nuxt config file, this module registers a modified version.");
828
+ }
829
+ const vueIdx = config.plugins.findIndex((plugin) => plugin.name === "vite:vue");
830
+ const vueOptions = vueIdx === -1 ? {} : config.plugins[vueIdx].api?.options;
831
+ filter = createFilter(vueOptions.include, vueOptions.exclude);
832
+ },
833
+ async transform(code, id) {
834
+ const { query, path } = parseId(id);
835
+ const isVueVirtual = query && "vue" in query;
836
+ const isVueFile = !isVueVirtual && filter(path) && !/^import { render as _sfc_render } from ".*"$/m.test(code);
837
+ const isVueTemplate = isVueVirtual && (query.type === "template" || query.type === "script" && query.setup === "true");
838
+ if (isVueFile || isVueTemplate) {
839
+ const { code: imports, source } = generateImports(code, options);
840
+ return {
841
+ code: source + imports,
842
+ map: null
843
+ };
844
+ }
845
+ return null;
846
+ }
847
+ };
848
+ }
849
+
850
+ function vuetifySSRClientHintsPlugin(ctx) {
851
+ return {
852
+ name: "vuetify:ssr-client-hints:nuxt",
853
+ enforce: "pre",
854
+ resolveId(id) {
855
+ if (id === VIRTUAL_VUETIFY_SSR_CLIENT_HINTS_CONFIGURATION) {
856
+ return RESOLVED_VIRTUAL_VUETIFY_SSR_CLIENT_HINTS_CONFIGURATION;
857
+ }
858
+ },
859
+ async load(id) {
860
+ if (id === RESOLVED_VIRTUAL_VUETIFY_SSR_CLIENT_HINTS_CONFIGURATION) {
861
+ const data = {
862
+ reloadOnFirstRequest: ctx.ssrClientHints.reloadOnFirstRequest,
863
+ viewportSize: ctx.ssrClientHints.viewportSize,
864
+ prefersColorScheme: ctx.ssrClientHints.prefersColorScheme,
865
+ prefersReducedMotion: ctx.ssrClientHints.prefersReducedMotion,
866
+ clientWidth: ctx.vuetifyOptions.ssr?.clientWidth,
867
+ clientHeight: ctx.vuetifyOptions.ssr?.clientHeight,
868
+ prefersColorSchemeOptions: ctx.ssrClientHints.prefersColorSchemeOptions
869
+ };
870
+ return `export const ssrClientHintsConfiguration = JSON.parse('${JSON.stringify(data)}');`;
871
+ }
872
+ }
873
+ };
874
+ }
875
+
876
+ function vuetifyStylesPlugin(options, viteVersion, _logger) {
877
+ let configFile;
878
+ let useLoadCache = false;
879
+ const vuetifyBase = resolveVuetifyBase();
880
+ const noneFiles = /* @__PURE__ */ new Set();
881
+ const loadCache = /* @__PURE__ */ new Map();
882
+ let isNone = false;
883
+ let sassVariables = false;
884
+ let fileImport = false;
885
+ const PREFIX = "vuetify-styles/";
886
+ const SSR_PREFIX = `/@${PREFIX}`;
887
+ const resolveCss = resolveCssFactory();
888
+ return {
889
+ name: "vuetify:styles:nuxt",
890
+ enforce: "pre",
891
+ async configResolved(config) {
892
+ if (config.plugins.some((plugin) => plugin.name === "vuetify:styles")) {
893
+ throw new Error("Remove vite-plugin-vuetify from your Nuxt config file, this module registers a modified version.");
894
+ }
895
+ if (isObject(options.styles) && "configFile" in options.styles) {
896
+ sassVariables = true;
897
+ useLoadCache = !config.isProduction && !!options.styles.experimental?.cache;
898
+ fileImport = semver.gt(viteVersion, "5.4.2");
899
+ configFile = await resolvePath(options.styles.configFile);
900
+ } else {
901
+ isNone = options.styles === "none";
902
+ }
903
+ },
904
+ async resolveId(source, importer, { custom, ssr }) {
905
+ if (!sassVariables) {
906
+ return;
907
+ }
908
+ if (source.startsWith(PREFIX) || source.startsWith(SSR_PREFIX)) {
909
+ if (/\.s[ca]ss$/.test(source)) {
910
+ return source;
911
+ }
912
+ const idx = source.indexOf("?");
913
+ return idx === -1 ? source : source.slice(0, idx);
914
+ }
915
+ if (importer && source.endsWith(".css") && isSubdir(vuetifyBase, path.isAbsolute(source) ? source : importer)) {
916
+ const resolution = await this.resolve(source, importer, { skipSelf: true, custom });
917
+ if (!resolution) {
918
+ return;
919
+ }
920
+ const target = await resolveCss(resolution.id);
921
+ if (isNone) {
922
+ noneFiles.add(target);
923
+ return target;
924
+ }
925
+ return `${ssr ? SSR_PREFIX : PREFIX}${path.relative(vuetifyBase, target)}`;
926
+ }
927
+ return void 0;
928
+ },
929
+ load(id) {
930
+ if (sassVariables) {
931
+ 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;
932
+ if (target) {
933
+ if (useLoadCache) {
934
+ const cached = loadCache.get(id);
935
+ if (cached) {
936
+ return cached;
937
+ }
938
+ }
939
+ const suffix = /\.scss/.test(target) ? ";\n" : "\n";
940
+ const result = {
941
+ code: `@use "${configFile}"${suffix}@use "${fileImport ? pathToFileURL(target).href : normalizePath(target)}"${suffix}`,
942
+ map: {
943
+ mappings: ""
944
+ }
945
+ };
946
+ if (useLoadCache) {
947
+ loadCache.set(id, result);
948
+ }
949
+ return result;
950
+ }
951
+ }
952
+ return isNone && noneFiles.has(id) ? "" : void 0;
953
+ },
954
+ handleHotUpdate({ file }) {
955
+ if (!useLoadCache) {
956
+ return;
957
+ }
958
+ const normalizedFile = normalizePath(file);
959
+ if (normalizedFile === normalizePath(configFile || "") || normalizedFile.endsWith(".sass") || normalizedFile.endsWith(".scss")) {
960
+ loadCache.clear();
961
+ }
962
+ }
963
+ };
964
+ }
965
+ function resolveCssFactory() {
966
+ const mappings = /* @__PURE__ */ new Map();
967
+ return async (source) => {
968
+ let mapping = mappings.get(source);
969
+ if (!mapping) {
970
+ try {
971
+ mapping = source.replace(/\.css$/, ".sass");
972
+ await fsp.access(mapping, fs.constants.R_OK);
973
+ } catch (error) {
974
+ if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) {
975
+ throw error;
976
+ }
977
+ mapping = source.replace(/\.css$/, ".scss");
978
+ }
979
+ mappings.set(source, mapping);
980
+ }
981
+ return mapping;
982
+ };
983
+ }
984
+ function isSubdir(root, test) {
985
+ const relative$1 = relative(root, test);
986
+ return relative$1 && !relative$1.startsWith("..") && !isAbsolute(relative$1);
987
+ }
988
+
989
+ function detectDate() {
990
+ const result = [];
991
+ for (const adapter of [
992
+ "date-fns",
993
+ "moment",
994
+ "luxon",
995
+ "dayjs",
996
+ "js-joda",
997
+ "date-fns-jalali",
998
+ "jalaali",
999
+ "hijri"
1000
+ ]) {
1001
+ if (isPackageExists(`@date-io/${adapter}`)) {
1002
+ result.push(adapter);
1003
+ }
1004
+ }
1005
+ return result;
1006
+ }
1007
+ function cleanupBlueprint(vuetifyOptions) {
1008
+ const blueprint = vuetifyOptions.blueprint;
1009
+ if (blueprint) {
1010
+ delete blueprint.ssr;
1011
+ delete blueprint.components;
1012
+ delete blueprint.directives;
1013
+ delete blueprint.locale;
1014
+ delete blueprint.date;
1015
+ delete blueprint.icons;
1016
+ vuetifyOptions.blueprint = blueprint;
1017
+ }
1018
+ }
1019
+ function checkVuetifyPlugins(config) {
1020
+ let plugin = config.plugins?.find((p) => p && typeof p === "object" && "name" in p && p.name === "vuetify:import");
1021
+ if (plugin) {
1022
+ throw new Error("Remove vite-plugin-vuetify plugin from Vite Plugins entry in Nuxt config file!");
1023
+ }
1024
+ plugin = config.plugins?.find((p) => p && typeof p === "object" && "name" in p && p.name === "vuetify:styles");
1025
+ if (plugin) {
1026
+ throw new Error("Remove vite-plugin-vuetify plugin from Vite Plugins entry in Nuxt config file!");
1027
+ }
1028
+ }
1029
+ function resolveVuetifyComponents(resolver) {
1030
+ const vuetifyBase = resolveVuetifyBase();
1031
+ const componentsPromise = importMapResolver();
1032
+ const labComponentsPromise = importMapLabResolver();
1033
+ return {
1034
+ vuetifyBase,
1035
+ componentsPromise,
1036
+ labComponentsPromise
1037
+ };
1038
+ async function importMapResolver() {
1039
+ return JSON.parse(await readFile(resolver.resolve(vuetifyBase, "dist/json/importMap.json"), "utf8")).components;
1040
+ }
1041
+ async function importMapLabResolver() {
1042
+ return JSON.parse(await readFile(resolver.resolve(vuetifyBase, "dist/json/importMap-labs.json"), "utf8")).components;
1043
+ }
1044
+ }
1045
+
1046
+ function configureVite(configKey, nuxt, ctx) {
1047
+ nuxt.hook("vite:extend", ({ config }) => checkVuetifyPlugins(config));
1048
+ nuxt.hook("vite:extendConfig", (viteInlineConfig) => {
1049
+ viteInlineConfig.plugins = viteInlineConfig.plugins || [];
1050
+ checkVuetifyPlugins(viteInlineConfig);
1051
+ if (!ctx.moduleOptions.disableModernSassCompiler) {
1052
+ const enableModernSassCompiler = semver.gte(ctx.viteVersion, "5.4.0") && semver.lt(ctx.viteVersion, "7.0.0-0");
1053
+ if (enableModernSassCompiler) {
1054
+ const sassEmbedded = isPackageExists("sass-embedded");
1055
+ if (sassEmbedded) {
1056
+ viteInlineConfig.css ??= {};
1057
+ viteInlineConfig.css.preprocessorOptions ??= {};
1058
+ viteInlineConfig.css.preprocessorOptions.sass ??= {};
1059
+ viteInlineConfig.css.preprocessorOptions.sass.api = "modern-compiler";
1060
+ viteInlineConfig.css.preprocessorOptions.scss ??= {};
1061
+ viteInlineConfig.css.preprocessorOptions.scss.api = "modern-compiler";
1062
+ } else {
1063
+ viteInlineConfig.css ??= {};
1064
+ viteInlineConfig.css.preprocessorOptions ??= {};
1065
+ viteInlineConfig.css.preprocessorOptions.sass ??= {};
1066
+ viteInlineConfig.css.preprocessorOptions.sass.api = "modern";
1067
+ viteInlineConfig.css.preprocessorOptions.scss ??= {};
1068
+ viteInlineConfig.css.preprocessorOptions.scss.api = "modern";
1069
+ if (!("preprocessorMaxWorkers" in viteInlineConfig.css)) {
1070
+ viteInlineConfig.css.preprocessorMaxWorkers = true;
1071
+ }
1072
+ }
1073
+ }
1074
+ }
1075
+ viteInlineConfig.optimizeDeps = defu(viteInlineConfig.optimizeDeps, { exclude: ["vuetify"] });
1076
+ if (ctx.isSSR) {
1077
+ viteInlineConfig.ssr ||= {};
1078
+ viteInlineConfig.ssr.noExternal = [
1079
+ ...Array.isArray(viteInlineConfig.ssr.noExternal) ? viteInlineConfig.ssr.noExternal : viteInlineConfig.ssr.noExternal && typeof viteInlineConfig.ssr.noExternal !== "boolean" ? [viteInlineConfig.ssr.noExternal] : [],
1080
+ configKey
1081
+ ];
1082
+ }
1083
+ const transformAssetUrls = createTransformAssetUrls(
1084
+ ctx,
1085
+ viteInlineConfig
1086
+ );
1087
+ if (transformAssetUrls) {
1088
+ viteInlineConfig.vue ??= {};
1089
+ viteInlineConfig.vue.template ??= {};
1090
+ viteInlineConfig.vue.template.transformAssetUrls = transformAssetUrls;
1091
+ }
1092
+ const autoImport = { labs: true };
1093
+ const ignoreDirectives = ctx.moduleOptions.ignoreDirectives;
1094
+ if (ignoreDirectives) {
1095
+ autoImport.ignore = Array.isArray(ignoreDirectives) ? ignoreDirectives : [ignoreDirectives];
1096
+ }
1097
+ viteInlineConfig.plugins.push(vuetifyImportPlugin({ autoImport }));
1098
+ if (ctx.moduleOptions.styles !== false && ctx.moduleOptions.styles !== "none") {
1099
+ viteInlineConfig.plugins.push(vuetifyStylesPlugin({ styles: ctx.moduleOptions.styles }, ctx.viteVersion, ctx.logger));
1100
+ }
1101
+ viteInlineConfig.plugins.push(vuetifyConfigurationPlugin(ctx), vuetifyIconsPlugin(ctx), vuetifyDateConfigurationPlugin(ctx));
1102
+ if (ctx.ssrClientHints.enabled) {
1103
+ viteInlineConfig.plugins.push(vuetifySSRClientHintsPlugin(ctx));
1104
+ }
1105
+ });
1106
+ }
1107
+
1108
+ const cssFonts = ["unocss-mdi", "mdi", "md", "fa", "fa4"];
1109
+ const iconsPackageNames = {
1110
+ "unocss-mdi": { name: "@mdi/font", css: "" },
1111
+ "mdi": { name: "@mdi/font", css: "@mdi/font/css/materialdesignicons.css" },
1112
+ "md": { name: "material-design-icons-iconfont", css: "@mdi/font/css/materialdesignicons.css" },
1113
+ "fa": { name: "@fortawesome/fontawesome-free", css: "@fortawesome/fontawesome-free/css/all.css" },
1114
+ "fa4": { name: "font-awesome@4.7.0", css: "font-awesome/css/font-awesome.min.css" }
1115
+ };
1116
+ const iconsCDN = {
1117
+ "unocss-mdi": "",
1118
+ "mdi": "https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css",
1119
+ "md": "https://fonts.googleapis.com/css?family=Material+Icons",
1120
+ "fa": "https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@latest/css/all.min.css",
1121
+ "fa4": "https://cdn.jsdelivr.net/npm/font-awesome@4.x/css/font-awesome.min.css"
1122
+ };
1123
+ const disabledResolvedIcons = Object.freeze({
1124
+ enabled: false,
1125
+ unocss: false,
1126
+ unocssAliases: false,
1127
+ unocssIconPrefix: "i-",
1128
+ unocssIcons: {},
1129
+ unocssAdditionalIcons: {},
1130
+ imports: [],
1131
+ aliases: [],
1132
+ aliasesImportPresent: false,
1133
+ sets: [],
1134
+ cdn: [],
1135
+ local: [],
1136
+ svg: {}
1137
+ });
1138
+ function prepareIcons(unocssPresent, logger, vuetifyOptions) {
1139
+ if (vuetifyOptions.icons === false) {
1140
+ return disabledResolvedIcons;
1141
+ }
1142
+ const icons = vuetifyOptions.icons || {};
1143
+ let { defaultSet = "mdi", sets } = icons;
1144
+ if (!defaultSet) {
1145
+ defaultSet = icons.defaultSet = "mdi";
1146
+ }
1147
+ if (!sets && defaultSet !== "mdi-svg" && defaultSet !== "fa-svg" && defaultSet !== "custom") {
1148
+ sets = [{ name: defaultSet || "mdi" }];
1149
+ }
1150
+ sets = sets ? convertFontSetsToObjectNotation(sets) : [];
1151
+ const resolvedIcons = {
1152
+ enabled: true,
1153
+ unocss: unocssPresent && (defaultSet === "unocss-mdi" || sets.some((s) => s.name === "unocss-mdi")),
1154
+ unocssAliases: defaultSet === "unocss-mdi",
1155
+ unocssIconPrefix: icons.unocssIconPrefix ?? "i-",
1156
+ unocssIcons: icons.unocssIcons ?? {},
1157
+ unocssAdditionalIcons: icons.unocssAdditionalIcons ?? {},
1158
+ defaultSet,
1159
+ sets: [],
1160
+ aliases: [],
1161
+ aliasesImportPresent: false,
1162
+ imports: [],
1163
+ cdn: [],
1164
+ local: [],
1165
+ svg: {
1166
+ mdi: false
1167
+ }
1168
+ };
1169
+ if (sets) {
1170
+ if (!unocssPresent && defaultSet === "unocss-mdi") {
1171
+ 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!");
1172
+ defaultSet = "mdi";
1173
+ sets = sets.filter((s) => s.name !== "unocss-mdi");
1174
+ }
1175
+ for (const { name, cdn } of sets.filter((s) => cssFonts.includes(s.name))) {
1176
+ resolvedIcons.aliasesImportPresent ||= name === defaultSet;
1177
+ if (name === "unocss-mdi") {
1178
+ continue;
1179
+ }
1180
+ resolvedIcons.imports.push(`import {${name === defaultSet ? "aliases," : ""}${name}} from 'vuetify/iconsets/${name}'`);
1181
+ resolvedIcons.sets.push(name);
1182
+ if (isPackageExists(iconsPackageNames[name].name)) {
1183
+ resolvedIcons.local.push(iconsPackageNames[name].css);
1184
+ } else {
1185
+ resolvedIcons.cdn.push([name, cdn ?? iconsCDN[name]]);
1186
+ }
1187
+ }
1188
+ if (resolvedIcons.unocss && defaultSet === "unocss-mdi") {
1189
+ if (!resolvedIcons.sets.includes("mdi")) {
1190
+ resolvedIcons.sets.push("mdi");
1191
+ resolvedIcons.imports.push("import {mdi} from 'vuetify/iconsets/mdi'");
1192
+ }
1193
+ resolvedIcons.defaultSet = "mdi";
1194
+ }
1195
+ }
1196
+ let faSvg = icons.svg?.fa;
1197
+ if (defaultSet === "fa-svg" || faSvg) {
1198
+ if (!faSvg) {
1199
+ faSvg = {};
1200
+ }
1201
+ let faSvgExists = isPackageExists("@fortawesome/fontawesome-svg-core");
1202
+ if (!faSvgExists) {
1203
+ logger.warn("Missing @fortawesome/fontawesome-svg-core dependency, install it!");
1204
+ }
1205
+ faSvgExists = isPackageExists("@fortawesome/vue-fontawesome");
1206
+ if (faSvgExists) {
1207
+ if (!faSvg.libraries?.length) {
1208
+ faSvg.libraries = [[false, "fas", "@fortawesome/free-solid-svg-icons"]];
1209
+ }
1210
+ for (const p in faSvg.libraries) {
1211
+ const [_defaultExport, _name, library] = faSvg.libraries[p];
1212
+ if (!isPackageExists(library)) {
1213
+ faSvgExists = false;
1214
+ logger.warn(`Missing library ${library} dependency, install it!`);
1215
+ }
1216
+ }
1217
+ } else {
1218
+ logger.warn("Missing @fortawesome/vue-fontawesome dependency, install it!");
1219
+ }
1220
+ if (faSvgExists) {
1221
+ resolvedIcons.aliasesImportPresent ||= defaultSet === "fa-svg";
1222
+ 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'");
1223
+ resolvedIcons.svg.fa = ["useNuxtApp().vueApp.component('font-awesome-icon', FontAwesomeIcon)"];
1224
+ for (const [defaultExport, name, library] of faSvg.libraries) {
1225
+ resolvedIcons.imports.push(`import ${defaultExport ? name : `{${name}}`} from '${library}'`);
1226
+ resolvedIcons.svg.fa.push(`library.add(${name})`);
1227
+ }
1228
+ resolvedIcons.sets.push("fa");
1229
+ if (defaultSet === "fa-svg") {
1230
+ resolvedIcons.defaultSet = "fa";
1231
+ }
1232
+ }
1233
+ }
1234
+ let mdiSvg = icons.svg?.mdi;
1235
+ if (defaultSet === "mdi-svg" || mdiSvg) {
1236
+ if (!mdiSvg) {
1237
+ mdiSvg = {};
1238
+ }
1239
+ const mdiSvgExists = isPackageExists("@mdi/js");
1240
+ if (mdiSvgExists) {
1241
+ resolvedIcons.svg.mdi = true;
1242
+ resolvedIcons.aliasesImportPresent ||= defaultSet === "mdi-svg";
1243
+ resolvedIcons.imports.push(`import {${defaultSet === "mdi-svg" ? "aliases," : ""}mdi} from 'vuetify/iconsets/mdi-svg'`);
1244
+ if (mdiSvg && mdiSvg.aliases) {
1245
+ resolvedIcons.imports.push(`import {${Object.values(mdiSvg.aliases).join(",")}} from '@mdi/js'`);
1246
+ for (const [alias, icon] of Object.entries(mdiSvg.aliases)) {
1247
+ resolvedIcons.aliases.push(`${alias}: ${icon}`);
1248
+ }
1249
+ }
1250
+ resolvedIcons.sets.push("mdi");
1251
+ if (defaultSet === "mdi-svg") {
1252
+ resolvedIcons.defaultSet = "mdi";
1253
+ }
1254
+ } else {
1255
+ resolvedIcons.svg.mdi = false;
1256
+ logger.warn("Missing @mdi/js dependency, install it!");
1257
+ }
1258
+ }
1259
+ if (defaultSet !== "custom" && !resolvedIcons.unocss && !resolvedIcons.local?.length && !resolvedIcons.cdn?.length && !resolvedIcons.svg?.mdi && !resolvedIcons.svg?.fa?.length) {
1260
+ logger.warn("No icons found, icons disabled!");
1261
+ return disabledResolvedIcons;
1262
+ }
1263
+ return resolvedIcons;
1264
+ }
1265
+ function convertFontSetsToObjectNotation(sets) {
1266
+ const result = [];
1267
+ if (typeof sets === "string") {
1268
+ result.push({ name: sets });
1269
+ } else {
1270
+ for (const set of sets) {
1271
+ if (typeof set === "string") {
1272
+ result.push({ name: set });
1273
+ } else {
1274
+ result.push(set);
1275
+ }
1276
+ }
1113
1277
  }
1278
+ return result;
1114
1279
  }
1115
1280
 
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 {}
1281
+ async function loadVuetifyConfiguration(cwd = process.cwd(), configOrPath = cwd, defaults = {}, extraConfigSources = []) {
1282
+ let inlineConfig = {};
1283
+ if (typeof configOrPath !== "string") {
1284
+ inlineConfig = configOrPath;
1285
+ configOrPath = process.cwd();
1286
+ }
1287
+ const resolved = resolve(cwd, configOrPath);
1288
+ let isFile = false;
1289
+ if (existsSync(resolved) && statSync(resolved).isFile()) {
1290
+ isFile = true;
1291
+ cwd = dirname(resolved).replace(/\\/g, "/");
1292
+ }
1293
+ const rewrite = (config) => {
1294
+ if (typeof config === "function") {
1295
+ return config();
1296
+ }
1297
+ return config;
1298
+ };
1299
+ const loader = createConfigLoader({
1300
+ sources: isFile ? [
1301
+ {
1302
+ files: resolved,
1303
+ extensions: [],
1304
+ rewrite
1305
+ }
1306
+ ] : [
1307
+ {
1308
+ files: [
1309
+ "vuetify.config"
1310
+ ],
1311
+ // we don't want `package.json` to be loaded
1312
+ extensions: ["mts", "cts", "ts", "mjs", "cjs", "js"],
1313
+ rewrite
1314
+ },
1315
+ ...extraConfigSources
1316
+ ],
1317
+ cwd,
1318
+ defaults: inlineConfig,
1319
+ merge: false
1320
+ });
1321
+ const result = await loader.load();
1322
+ result.config = result.config?.config === false ? Object.assign(defaults, inlineConfig) : Object.assign(defaults, result.config || inlineConfig);
1323
+ delete result.config.config;
1324
+ return result;
1134
1325
  }
1135
- `;
1326
+
1327
+ async function mergeVuetifyModules(options, nuxt) {
1328
+ const moduleOptions = [];
1329
+ const vuetifyConfigurationFilesToWatch = /* @__PURE__ */ new Set();
1330
+ await nuxt.callHook("vuetify:registerModule", (layerModuleOptions) => moduleOptions.push(layerModuleOptions));
1331
+ if (nuxt.options._layers.length > 1) {
1332
+ for (let i = 1; i < nuxt.options._layers.length; i++) {
1333
+ const layer = nuxt.options._layers[i];
1334
+ const resolvedOptions2 = await loadVuetifyConfiguration(
1335
+ layer.config.rootDir,
1336
+ layer.config.vuetify?.vuetifyOptions
1337
+ );
1338
+ if (resolvedOptions2.sources.length > 0) {
1339
+ for (const s of resolvedOptions2.sources.map((s2) => s2.replace(/\\/g, "/")).filter((s2) => !s2.includes("/node_modules/"))) {
1340
+ vuetifyConfigurationFilesToWatch.add(s);
1136
1341
  }
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
1342
  }
1343
+ moduleOptions.push({
1344
+ moduleOptions: layer.config.vuetify?.moduleOptions,
1345
+ vuetifyOptions: resolvedOptions2.config
1346
+ });
1150
1347
  }
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
1348
  }
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");
1349
+ const resolvedOptions = await loadVuetifyConfiguration(
1350
+ nuxt.options.rootDir,
1351
+ options.vuetifyOptions
1352
+ );
1353
+ if (nuxt.options.dev && resolvedOptions.sources.length > 0) {
1354
+ if (nuxt.options.ssr) {
1355
+ for (const s of resolvedOptions.sources) {
1356
+ nuxt.options.watch.push(s.replace(/\\/g, "/"));
1357
+ }
1358
+ } else {
1359
+ for (const s of resolvedOptions.sources) {
1360
+ vuetifyConfigurationFilesToWatch.add(s.replace(/\\/g, "/"));
1361
+ }
1362
+ }
1363
+ }
1364
+ moduleOptions.unshift({
1365
+ moduleOptions: options.moduleOptions,
1366
+ vuetifyOptions: resolvedOptions.config
1367
+ });
1368
+ if (moduleOptions.length > 1) {
1369
+ const [app, ...rest] = moduleOptions;
1370
+ const configuration = defu(app, ...rest);
1371
+ dedupeIcons(configuration, moduleOptions.toReversed());
1372
+ return {
1373
+ configuration,
1374
+ vuetifyConfigurationFilesToWatch
1375
+ };
1376
+ } else {
1377
+ return {
1378
+ configuration: {
1379
+ moduleOptions: options.moduleOptions,
1380
+ vuetifyOptions: resolvedOptions.config
1381
+ },
1382
+ vuetifyConfigurationFilesToWatch
1383
+ };
1171
1384
  }
1172
1385
  }
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)}');`;
1386
+ function dedupeIcons(configuration, moduleOptions) {
1387
+ const vuetifyOptions = configuration.vuetifyOptions;
1388
+ if (vuetifyOptions.icons && vuetifyOptions.icons.sets) {
1389
+ const sets = /* @__PURE__ */ new Map();
1390
+ for (const { vuetifyOptions: vuetifyOptions2 } of moduleOptions) {
1391
+ if (vuetifyOptions2.icons && vuetifyOptions2.icons.sets) {
1392
+ const mSets = vuetifyOptions2.icons.sets;
1393
+ if (typeof mSets === "string") {
1394
+ sets.set(mSets, { name: mSets });
1395
+ } else {
1396
+ for (const set of mSets) {
1397
+ if (typeof set === "string") {
1398
+ sets.set(set, { name: set });
1399
+ } else {
1400
+ sets.set(set.name, set);
1401
+ }
1402
+ }
1403
+ }
1194
1404
  }
1195
1405
  }
1196
- };
1406
+ vuetifyOptions.icons.sets = Array.from(sets.values());
1407
+ }
1197
1408
  }
1198
1409
 
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
1410
+ const disabledClientHints = Object.freeze({
1411
+ enabled: false,
1412
+ reloadOnFirstRequest: false,
1413
+ viewportSize: false,
1414
+ prefersColorScheme: false,
1415
+ prefersReducedMotion: false
1416
+ });
1417
+ function prepareSSRClientHints(baseUrl, ctx) {
1418
+ if (!ctx.isSSR || ctx.isNuxtGenerate) {
1419
+ return disabledClientHints;
1420
+ }
1421
+ const { ssrClientHints: ssrClientHintsConfiguration } = ctx.moduleOptions;
1422
+ const clientHints = {
1423
+ enabled: false,
1424
+ reloadOnFirstRequest: ssrClientHintsConfiguration?.reloadOnFirstRequest ?? false,
1425
+ viewportSize: ssrClientHintsConfiguration?.viewportSize ?? false,
1426
+ prefersColorScheme: ssrClientHintsConfiguration?.prefersColorScheme ?? false,
1427
+ prefersReducedMotion: ssrClientHintsConfiguration?.prefersReducedMotion ?? false
1210
1428
  };
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;
1429
+ clientHints.enabled = clientHints.viewportSize || clientHints.prefersColorScheme || clientHints.prefersReducedMotion;
1430
+ if (clientHints.enabled && clientHints.prefersColorScheme && ssrClientHintsConfiguration?.prefersColorSchemeOptions) {
1431
+ const theme = ctx.vuetifyOptions.theme;
1432
+ if (!theme) {
1433
+ throw new Error("Vuetify theme is disabled");
1236
1434
  }
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
- ];
1435
+ const themes = theme.themes;
1436
+ if (!themes) {
1437
+ throw new Error("Vuetify themes is missing in theme!");
1252
1438
  }
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;
1439
+ const defaultTheme = theme.defaultTheme;
1440
+ if (!defaultTheme) {
1441
+ throw new Error("Vuetify default theme is missing in theme!");
1261
1442
  }
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
- }
1443
+ if (!themes[defaultTheme]) {
1444
+ throw new Error(`Missing default theme ${defaultTheme} in the Vuetify themes!`);
1284
1445
  }
1285
- const autoImport = { labs: true };
1286
- const ignoreDirectives = ctx.moduleOptions.ignoreDirectives;
1287
- if (ignoreDirectives) {
1288
- autoImport.ignore = Array.isArray(ignoreDirectives) ? ignoreDirectives : [ignoreDirectives];
1446
+ const darkThemeName = ssrClientHintsConfiguration.prefersColorSchemeOptions?.darkThemeName ?? "dark";
1447
+ if (!themes[darkThemeName]) {
1448
+ throw new Error(`Missing theme ${darkThemeName} in the Vuetify themes!`);
1289
1449
  }
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
- });
1450
+ const lightThemeName = ssrClientHintsConfiguration.prefersColorSchemeOptions?.lightThemeName ?? "light";
1451
+ if (!themes[lightThemeName]) {
1452
+ throw new Error(`Missing theme ${lightThemeName} in the Vuetify themes!`);
1453
+ }
1454
+ if (darkThemeName === lightThemeName) {
1455
+ throw new Error("Vuetify dark theme and light theme are the same, change darkThemeName or lightThemeName!");
1456
+ }
1457
+ clientHints.prefersColorSchemeOptions = {
1458
+ baseUrl,
1459
+ defaultTheme,
1460
+ themeNames: Array.from(Object.keys(themes)),
1461
+ cookieName: ssrClientHintsConfiguration.prefersColorSchemeOptions?.cookieName ?? "color-scheme",
1462
+ darkThemeName,
1463
+ lightThemeName,
1464
+ useBrowserThemeOnly: ssrClientHintsConfiguration.prefersColorSchemeOptions?.useBrowserThemeOnly ?? false
1465
+ };
1466
+ }
1467
+ return clientHints;
1299
1468
  }
1300
1469
 
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");
1470
+ async function load(options, nuxt, ctx) {
1471
+ const {
1472
+ configuration,
1473
+ vuetifyConfigurationFilesToWatch
1474
+ } = await mergeVuetifyModules(options, nuxt);
1475
+ if (ctx.componentsPromise === void 0) {
1476
+ const {
1477
+ componentsPromise,
1478
+ labComponentsPromise
1479
+ } = resolveVuetifyComponents(ctx.resolver);
1480
+ ctx.componentsPromise = componentsPromise;
1481
+ ctx.labComponentsPromise = labComponentsPromise;
1482
+ }
1483
+ const { vuetifyOptions = {} } = configuration;
1484
+ const {
1485
+ directives: _directives,
1486
+ labComponents: _labComponents,
1487
+ ...vOptions
1488
+ } = vuetifyOptions;
1489
+ const vuetifyAppOptions = defu(vOptions, {});
1490
+ cleanupBlueprint(vuetifyAppOptions);
1491
+ ctx.dateAdapter = void 0;
1492
+ const dateOptions = vuetifyOptions.date;
1493
+ if (dateOptions) {
1494
+ const adapter = dateOptions.adapter;
1495
+ const date = detectDate();
1496
+ if (!adapter && date.length > 1) {
1497
+ 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.`);
1498
+ }
1499
+ if (adapter) {
1500
+ if (adapter === "vuetify" || adapter === "custom") {
1501
+ ctx.dateAdapter = adapter;
1502
+ } else {
1503
+ if (date.includes(adapter)) {
1504
+ ctx.dateAdapter = adapter;
1325
1505
  } else {
1326
- dependsOn.push("vuetify:date:plugin");
1506
+ ctx.logger.warn(`[vuetify-nuxt-module] Ignoring Vuetify Date configuration, date adapter "@date-io/${adapter}" not installed!`);
1327
1507
  }
1328
1508
  }
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
- `;
1509
+ } else if (date.length === 0) {
1510
+ ctx.dateAdapter = "vuetify";
1511
+ } else {
1512
+ ctx.dateAdapter = date[0];
1365
1513
  }
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
1514
  }
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` });
1515
+ const oldIcons = ctx.icons;
1516
+ if (oldIcons && oldIcons.cdn?.length && nuxt.options.app.head.link) {
1517
+ nuxt.options.app.head.link = nuxt.options.app.head.link.filter((link) => !link.key || !oldIcons.cdn.some(([key]) => link.key === key));
1518
+ }
1519
+ ctx.moduleOptions = configuration.moduleOptions;
1520
+ ctx.vuetifyOptions = configuration.vuetifyOptions;
1521
+ ctx.enableRules = ctx.moduleOptions.enableRules;
1522
+ ctx.rulesConfiguration = ctx.moduleOptions.rulesConfiguration;
1523
+ ctx.vuetifyFilesToWatch = Array.from(vuetifyConfigurationFilesToWatch);
1524
+ ctx.icons = prepareIcons(ctx.unocss, ctx.logger, vuetifyAppOptions);
1525
+ ctx.ssrClientHints = prepareSSRClientHints(nuxt.options.app.baseURL ?? "/", ctx);
1526
+ if (ctx.icons.enabled) {
1527
+ if (ctx.icons.local) {
1528
+ for (const css of ctx.icons.local) {
1529
+ nuxt.options.css.push(css);
1530
+ }
1409
1531
  }
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");
1532
+ if (ctx.icons.cdn?.length) {
1533
+ nuxt.options.app.head.link ??= [];
1534
+ for (const [key, href] of ctx.icons.cdn) {
1535
+ nuxt.options.app.head.link.push({
1536
+ key,
1537
+ rel: "stylesheet",
1538
+ href,
1539
+ type: "text/css",
1540
+ crossorigin: "anonymous"
1541
+ });
1542
+ }
1419
1543
  }
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
1544
  }
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"
1545
+ }
1546
+ function registerWatcher(options, nuxt, ctx) {
1547
+ if (nuxt.options.dev) {
1548
+ let pageReload;
1549
+ nuxt.hooks.hook("builder:watch", (_event, path) => {
1550
+ path = relative$1(nuxt.options.srcDir, resolve(nuxt.options.srcDir, path));
1551
+ if (!pageReload && ctx.vuetifyFilesToWatch.includes(path)) {
1552
+ return nuxt.callHook("restart");
1553
+ }
1437
1554
  });
1438
- } else {
1439
- addPlugin({
1440
- src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-no-client-hints")
1555
+ nuxt.hook("vite:serverCreated", (server, { isClient }) => {
1556
+ if (!server.ws || !isClient) {
1557
+ return;
1558
+ }
1559
+ pageReload = debounce(async () => {
1560
+ const modules = [];
1561
+ for (const v of RESOLVED_VIRTUAL_MODULES) {
1562
+ const module = server.moduleGraph.getModuleById(v);
1563
+ if (module) {
1564
+ modules.push(module);
1565
+ }
1566
+ }
1567
+ await load(options, nuxt, ctx);
1568
+ if (modules.length > 0) {
1569
+ await Promise.all(modules.map((m) => server.reloadModule(m)));
1570
+ }
1571
+ }, 50, { trailing: false });
1441
1572
  });
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")
1573
+ addVitePlugin({
1574
+ name: "vuetify:configuration:watch",
1575
+ enforce: "pre",
1576
+ handleHotUpdate({ file }) {
1577
+ if (pageReload && ctx.vuetifyFilesToWatch.includes(file)) {
1578
+ return pageReload();
1579
+ }
1580
+ }
1449
1581
  });
1450
1582
  }
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
1583
  }
1464
1584
 
1465
1585
  const CONFIG_KEY = "vuetify";
@@ -1473,7 +1593,9 @@ const module$1 = defineNuxtModule({
1473
1593
  },
1474
1594
  version
1475
1595
  },
1476
- // Default configuration options of the Nuxt module
1596
+ /**
1597
+ * Default configuration options of the Nuxt module
1598
+ */
1477
1599
  defaults: () => ({
1478
1600
  vuetifyOptions: {
1479
1601
  labComponents: false,
@@ -1484,15 +1606,21 @@ const module$1 = defineNuxtModule({
1484
1606
  includeTransformAssetsUrls: true,
1485
1607
  styles: true,
1486
1608
  disableVuetifyStyles: false,
1487
- disableModernSassCompiler: false,
1488
1609
  rulesConfiguration: {
1489
1610
  fromLabs: true
1490
1611
  }
1491
1612
  }
1492
1613
  }),
1614
+ /**
1615
+ * Sets up the Vuetify Nuxt module.
1616
+ *
1617
+ * @param options - The module options.
1618
+ * @param nuxt - The Nuxt instance.
1619
+ */
1493
1620
  async setup(options, nuxt) {
1494
- if (isNuxtMajorVersion(2, nuxt))
1621
+ if (isNuxtMajorVersion(2, nuxt)) {
1495
1622
  logger.error(`Cannot support nuxt version: ${getNuxtVersion(nuxt)}`);
1623
+ }
1496
1624
  const vuetifyPkg = await getPackageInfo("vuetify");
1497
1625
  const currentVersion = vuetifyPkg?.version;
1498
1626
  const vuetifyGte = (version2) => !!currentVersion && semver.gte(currentVersion, version2);
@@ -1516,7 +1644,7 @@ const module$1 = defineNuxtModule({
1516
1644
  viteVersion
1517
1645
  };
1518
1646
  await load(options, nuxt, ctx);
1519
- configureNuxt(CONFIG_KEY, nuxt, ctx);
1647
+ await configureNuxt(CONFIG_KEY, nuxt, ctx);
1520
1648
  registerWatcher(options, nuxt, ctx);
1521
1649
  configureVite(CONFIG_KEY, nuxt, ctx);
1522
1650
  }