vuetify-nuxt-module
Version:
Zero-Config Nuxt Module for Vuetify
1,425 lines (1,405 loc) • 62 kB
JavaScript
import { existsSync, statSync, readFileSync } from 'node:fs';
import { pathToFileURL, fileURLToPath } from 'node:url';
import { addPluginTemplate, resolvePath, addTemplate, extendWebpackConfig, isNuxtMajorVersion, addImports, addPlugin, addVitePlugin, useLogger, defineNuxtModule, getNuxtVersion, findPath, hasNuxtModule, createResolver } from '@nuxt/kit';
import { isAbsolute, resolve, dirname } from 'pathe';
import semver from 'semver';
import { createFilter, version as version$1 } from 'vite';
import defu from 'defu';
import { transformAssetUrls, generateImports } from '@vuetify/loader-shared';
import Styles from '@vuetify/unplugin-styles/vite';
import { isPackageExists } from 'local-pkg';
import { parseQuery, parseURL } from 'ufo';
import { readFile } from 'node:fs/promises';
import process from 'node:process';
import { createConfigLoader } from 'unconfig';
const version = "1.0.0-rc.4";
const VIRTUAL_VUETIFY_CONFIGURATION = "virtual:vuetify-configuration";
const RESOLVED_VIRTUAL_VUETIFY_CONFIGURATION = `\0${VIRTUAL_VUETIFY_CONFIGURATION}`;
const VIRTUAL_VUETIFY_DATE_CONFIGURATION = "virtual:vuetify-date-configuration";
const RESOLVED_VIRTUAL_VUETIFY_DATE_CONFIGURATION = `\0${VIRTUAL_VUETIFY_DATE_CONFIGURATION}`;
const VIRTUAL_VUETIFY_ICONS_CONFIGURATION = "virtual:vuetify-icons-configuration";
const RESOLVED_VIRTUAL_VUETIFY_ICONS_CONFIGURATION = `\0${VIRTUAL_VUETIFY_ICONS_CONFIGURATION}`;
const VIRTUAL_VUETIFY_SSR_CLIENT_HINTS_CONFIGURATION = "virtual:vuetify-ssr-client-hints-configuration";
const RESOLVED_VIRTUAL_VUETIFY_SSR_CLIENT_HINTS_CONFIGURATION = `\0${VIRTUAL_VUETIFY_SSR_CLIENT_HINTS_CONFIGURATION}`;
const RESOLVED_VIRTUAL_MODULES = [
RESOLVED_VIRTUAL_VUETIFY_DATE_CONFIGURATION,
RESOLVED_VIRTUAL_VUETIFY_ICONS_CONFIGURATION,
RESOLVED_VIRTUAL_VUETIFY_CONFIGURATION,
RESOLVED_VIRTUAL_VUETIFY_SSR_CLIENT_HINTS_CONFIGURATION
];
function toKebabCase(str = "") {
if (toKebabCase.cache.has(str)) {
return toKebabCase.cache.get(str);
}
const kebab = str.replace(/[^a-z]/gi, "-").replace(/\B([A-Z])/g, "-$1").toLowerCase();
toKebabCase.cache.set(str, kebab);
return kebab;
}
toKebabCase.cache = /* @__PURE__ */ new Map();
function camelize(str) {
if (camelize.cache.has(str)) {
return camelize.cache.get(str);
}
const camel = str.replace(/-([a-z0-9])/g, (g) => g[1].toUpperCase());
camelize.cache.set(str, camel);
return camel;
}
camelize.cache = /* @__PURE__ */ new Map();
function pascalize(str) {
if (pascalize.cache.has(str)) {
return pascalize.cache.get(str);
}
let pascal = camelize(str);
pascal = pascal.slice(0, 1).toUpperCase() + pascal.slice(1);
pascalize.cache.set(str, pascal);
return pascal;
}
pascalize.cache = /* @__PURE__ */ new Map();
function createTransformAssetUrls(ctx, viteInlineConfig) {
const { includeTransformAssetsUrls } = ctx.moduleOptions;
if (!includeTransformAssetsUrls) {
return void 0;
}
let existingTransformAssetUrls = viteInlineConfig.vue?.template?.transformAssetUrls ?? {};
let useURLOptions;
if (typeof existingTransformAssetUrls === "boolean") {
existingTransformAssetUrls = {};
} else if ("base" in existingTransformAssetUrls || "includeAbsolute" in existingTransformAssetUrls || "tags" in existingTransformAssetUrls) {
useURLOptions = {
base: existingTransformAssetUrls.base,
includeAbsolute: existingTransformAssetUrls.includeAbsolute
};
existingTransformAssetUrls = existingTransformAssetUrls.tags ?? {};
}
const transformAssetUrls$1 = normalizeTransformAssetUrls(
typeof includeTransformAssetsUrls === "object" ? defu(existingTransformAssetUrls, transformAssetUrls, includeTransformAssetsUrls) : defu(existingTransformAssetUrls, transformAssetUrls)
);
if (!useURLOptions) {
return transformAssetUrls$1;
}
useURLOptions.tags = transformAssetUrls$1;
return useURLOptions;
}
function normalizeTransformAssetUrls(transformAssetUrls) {
const names = new Set(Object.keys(transformAssetUrls));
let kebab;
let pascal;
for (const name of names) {
transformAssetUrls[name] = normalizeTransformAssetUrlsAttrs(transformAssetUrls[name]);
kebab = toKebabCase(name);
pascal = pascalize(name);
if (!names.has(kebab)) {
transformAssetUrls[kebab] = [...transformAssetUrls[name]];
}
if (!names.has(pascal)) {
transformAssetUrls[pascal] = [...transformAssetUrls[name]];
}
}
return transformAssetUrls;
}
function normalizeTransformAssetUrlsAttrs(attrs) {
const result = /* @__PURE__ */ new Set();
let kebab;
let camel;
let bind;
let idx;
for (const attr of attrs) {
result.add(attr);
idx = attr.indexOf(":");
if (idx > 0) {
continue;
}
bind = idx === 0;
kebab = toKebabCase(bind ? attr.slice(1) : attr);
camel = camelize(bind ? attr.slice(1) : attr);
result.add(kebab);
result.add(camel);
result.add(`:${kebab}`);
result.add(`:${camel}`);
}
return [...result];
}
function resolveVuetifyConfigFile(configFile, nuxt) {
if (typeof configFile === "string" && !isAbsolute(configFile)) {
for (const layer of nuxt.options._layers) {
const resolved = resolve(layer.config.srcDir, configFile);
if (existsSync(resolved)) {
return resolved;
}
}
}
return configFile;
}
function addVuetifyNuxtPlugins(nuxt, ctx) {
addVuetifyNuxtPlugin(nuxt, ctx, "client");
addVuetifyNuxtPlugin(nuxt, ctx, "server");
}
function addVuetifyNuxtPlugin(nuxt, ctx, mode) {
addPluginTemplate({
filename: `vuetify-nuxt-plugin.${mode}.mjs`,
name: `vuetify:nuxt:${mode}:plugin`,
write: false,
mode,
getContents() {
const dependsOn = ["vuetify:icons:plugin"];
if (ctx.ssrClientHints.enabled) {
if (mode === "client") {
dependsOn.push("vuetify:client-hints:client:plugin");
} else {
dependsOn.push("vuetify:client-hints:server:plugin");
}
}
if (ctx.i18n) {
dependsOn.push("vuetify:i18n:plugin");
}
if (nuxt.options.dev || ctx.dateAdapter) {
if (ctx.i18n) {
dependsOn.push("vuetify:date-i18n:plugin");
} else {
dependsOn.push("vuetify:date:plugin");
}
}
let rulesImports = "";
let rulesPlugin = "";
if (ctx.enableRules) {
rulesImports = [
"",
`import { rulesOptions } from '#build/vuetify/${ctx.rulesConfiguration.fromLabs ? "labs-" : ""}rules-configuration.mjs'`,
`import { createRulesPlugin } from 'vuetify/${ctx.rulesConfiguration.fromLabs ? "labs/" : ""}rules'`
].join("\n");
rulesPlugin = [
"",
" nuxtApp.vueApp.use(createRulesPlugin(rulesOptions, vuetify.locale))"
].join("\n");
}
return `
import { defineNuxtPlugin } from '#imports'
import { isDev, vuetifyConfiguration } from 'virtual:vuetify-configuration'
import { createVuetify } from 'vuetify'${rulesImports}
export default defineNuxtPlugin({
name: 'vuetify:nuxt:${mode}:plugin',
order: 25,
dependsOn: ${JSON.stringify(dependsOn)},
parallel: true,
async setup(nuxtApp) {
const vuetifyOptions = vuetifyConfiguration()
await nuxtApp.hooks.callHook('vuetify:configuration', { isDev, vuetifyOptions })
await nuxtApp.hooks.callHook('vuetify:before-create', { isDev, vuetifyOptions })
const vuetify = createVuetify(vuetifyOptions)
nuxtApp.vueApp.use(vuetify)${rulesPlugin}
nuxtApp.provide('vuetify', vuetify)
await nuxtApp.hooks.callHook('vuetify:ready', vuetify)
},
})
`;
}
});
}
function getTemplate(source, settings) {
return [settings ? `@use '${settings}';` : "", `@use '${source}';`].filter(Boolean).join("\n");
}
async function configureNuxt(configKey, nuxt, ctx) {
const {
styles,
importComposables,
prefixComposables
} = ctx.moduleOptions;
const runtimeDir = ctx.resolver.resolve("./runtime");
if (ctx.enableRules === void 0) {
ctx.enableRules = ctx.vuetifyGte("3.8.0");
}
if (styles !== "none" && styles !== false) {
nuxt.options.css ??= [];
if (typeof styles === "object" && "configFile" in styles) {
const configFile = resolveVuetifyConfigFile(styles.configFile, nuxt);
ctx.stylesConfigFile = await resolvePath(configFile);
const a = addTemplate({
// Write to disk: without `write` Nuxt serves the template from its
// virtual FS, which 404s on Windows/SSR when the browser requests the
// real file (#363). Nest under `vuetify/` to match unplugin-styles.
write: true,
filename: "vuetify/vuetify.settings.scss",
getContents: async () => getTemplate("vuetify/styles", ctx.stylesConfigFile)
});
nuxt.options.css.push(a.dst);
} else if (ctx.vuetifyGte("4.0.0")) {
nuxt.options.css.push(await resolvePath("vuetify/styles/core"));
if (styles === true || typeof styles === "object" && styles?.utilities !== false) {
nuxt.options.css.push(await resolvePath("vuetify/styles/utilities"));
}
if (styles === true || typeof styles === "object" && styles?.colors !== false) {
nuxt.options.css.push(await resolvePath("vuetify/styles/colors"));
}
} else {
nuxt.options.css.push(await resolvePath("vuetify/styles"));
}
}
nuxt.options.build.transpile.push(configKey, runtimeDir);
if (ctx.enableRules) {
const rulesConfigurationFile = `vuetify/${ctx.rulesConfiguration.fromLabs ? "labs-" : ""}rules-configuration.mjs`;
nuxt.options.build.transpile.push(`#build/${rulesConfigurationFile}`);
addTemplate({
filename: rulesConfigurationFile,
getContents: async () => {
if (ctx.rulesConfiguration?.configFile) {
const resolvedPath = await resolvePath(ctx.rulesConfiguration.configFile);
return `export { default as rulesOptions } from '${resolvedPath}'`;
}
return "export const rulesOptions = {}";
},
write: true
});
}
nuxt.options.build.transpile.push(/\/vuetify-nuxt-plugin\.(client|server)\.mjs$/);
nuxt.options.imports.transform ??= {};
nuxt.options.imports.transform.include ??= [];
for (const virtual of RESOLVED_VIRTUAL_MODULES) {
nuxt.options.imports.transform.include.push(new RegExp(`${virtual}$`));
}
extendWebpackConfig(() => {
throw new Error("Webpack is not supported: vuetify-nuxt-module module can only be used with Vite!");
});
const v4Available = isNuxtMajorVersion(4, nuxt);
nuxt.hook("prepare:types", ({ references, nodeReferences }) => {
references.push({ types: "vuetify" }, { types: "vuetify-nuxt-module/custom-configuration" }, { types: "vuetify-nuxt-module/configuration" }, { path: ctx.resolver.resolve(runtimeDir, "plugins/types") });
if (ctx.enableRules) {
references.push({ types: `vuetify-nuxt-module/custom-${ctx.rulesConfiguration.fromLabs ? "labs-" : ""}rules-configuration` });
}
if (v4Available) {
nodeReferences.push({ types: "vuetify-nuxt-module/custom-configuration" });
if (ctx.enableRules) {
nodeReferences.push({ types: `vuetify-nuxt-module/custom-${ctx.rulesConfiguration.fromLabs ? "labs-" : ""}rules-configuration` });
}
}
});
if (importComposables) {
let composables = ["useDate", "useLocale", "useDefaults", "useDisplay", "useLayout", "useRtl", "useTheme"];
if (ctx.vuetifyGte("3.5.0")) {
composables.push("useGoTo");
}
if (ctx.vuetifyGte("3.8.0")) {
composables.push("useHotkey");
if (ctx.enableRules) {
composables.push("useRules");
}
}
if (ctx.vuetifyGte("3.10.0")) {
composables.push("useMask");
}
if (Array.isArray(importComposables)) {
composables = composables.filter((name) => importComposables.includes(name));
}
addImports(composables.map((name) => {
let from = ctx.vuetifyGte("3.4.0") || name !== "useDate" ? "vuetify" : "vuetify/labs/date";
if (name === "useRules" && ctx.rulesConfiguration?.fromLabs) {
from = "vuetify/labs/rules";
}
return {
name,
from,
as: (Array.isArray(prefixComposables) ? prefixComposables.includes(name) : prefixComposables) ? name.replace(/^use/, "useV") : void 0,
meta: { docsUrl: name === "useRules" ? "https://vuetifyjs.com/en/features/rules/" : `https://vuetifyjs.com/en/api/${toKebabCase(name)}/` }
};
}));
}
if (ctx.ssrClientHints.enabled) {
addPlugin({
src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-client-hints.client"),
mode: "client"
});
addPlugin({
src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-client-hints.server"),
mode: "server"
});
} else {
addPlugin({
src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-no-client-hints")
});
}
addPlugin({
src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-icons")
});
if (ctx.i18n) {
addPlugin({
src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-i18n")
});
}
if (nuxt.options.dev || ctx.dateAdapter) {
if (ctx.i18n) {
addPlugin({
src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-i18n-date")
});
} else {
addPlugin({
src: ctx.resolver.resolve(runtimeDir, "plugins/vuetify-date")
});
}
}
addVuetifyNuxtPlugins(nuxt, ctx);
}
function vuetifyConfigurationPlugin(ctx) {
return {
name: "vuetify:configuration:nuxt",
enforce: "pre",
resolveId(id) {
if (id === VIRTUAL_VUETIFY_CONFIGURATION) {
return RESOLVED_VIRTUAL_VUETIFY_CONFIGURATION;
}
},
async load(id) {
if (id === RESOLVED_VIRTUAL_VUETIFY_CONFIGURATION) {
if (ctx.isDev && ctx.canHmrConfig) {
for (const file of ctx.vuetifyFilesToWatch) {
this.addWatchFile(file);
}
}
const {
directives: _directives,
date: _date,
icons: _icons,
localeMessages: _localeMessages,
components: _components,
labComponents: _labComponents,
ssr,
aliases: _aliases,
...newVuetifyOptions
} = ctx.vuetifyOptions;
if (ctx.isSSR) {
newVuetifyOptions.ssr = ssr ?? true;
}
if (ctx.i18n && newVuetifyOptions.locale) {
delete newVuetifyOptions.locale.rtl;
delete newVuetifyOptions.locale.locale;
delete newVuetifyOptions.locale.fallback;
}
const result = await buildConfiguration(ctx);
const deepCopy = result.messages.length > 0;
let configDepImports = "";
if (ctx.isDev && ctx.canHmrConfig && this.environment?.name === "ssr") {
configDepImports = ctx.vuetifyFilesToWatch.map((file) => `import ${JSON.stringify(file)}`).join("\n");
}
return `${configDepImports}
${result.imports}
export const isDev = ${ctx.isDev}
export function vuetifyConfiguration() {
const options = ${JSON.stringify(newVuetifyOptions)}
${result.directives}
${result.aliases}
${result.components}
${result.messages}
return options
}
${deepCopy ? `function deepCopy(src,des) {
for (const key in src) {
if (typeof src[key] === 'object') {
if (typeof des[key] !== 'object') des[key] = {}
deepCopy(src[key], des[key])
} else {
des[key] = src[key]
}
}
}
` : ""}
`;
}
}
};
}
async function buildConfiguration(ctx) {
const {
componentsPromise,
labComponentsPromise,
logger,
vuetifyOptions
} = ctx;
const {
aliases,
components,
directives,
localeMessages,
labComponents,
date: dateOptions
} = vuetifyOptions;
const config = {
directives: "",
imports: [],
aliasEntries: [],
aliases: aliases || {},
components: new Set(components ? Array.isArray(components) ? components : [components] : []),
labComponents: /* @__PURE__ */ new Set(),
messages: ""
};
if (directives) {
if (typeof directives === "boolean") {
config.imports.push("import * as directives from 'vuetify/directives'");
config.directives = "options.directives = directives";
} else {
const useDirectives = Array.isArray(directives) ? [...new Set(directives)] : [directives];
config.imports.push(useDirectives.map((d) => `import {${d}} from 'vuetify/directives/${toKebabCase(d)}'`).join("\n"));
config.directives = `options.directives = {${useDirectives.join(",")}}`;
}
}
const importMapComponents = await componentsPromise;
const componentsToImport = /* @__PURE__ */ new Map();
for (const component of config.components) {
const componentEntry = importMapComponents[component];
const from = componentEntry?.from;
if (!from) {
logger.warn(`Component ${component} not found in Vuetify.`);
continue;
}
const parts = from.split("/");
if (parts.length < 2) {
logger.warn(`Component ${component} not found in Vuetify, please report a new issue.`);
continue;
}
const bucket = parts[1];
if (!bucket) {
continue;
}
if (!componentsToImport.has(bucket)) {
componentsToImport.set(bucket, []);
}
const componentsArray = componentsToImport.get(bucket);
if (!componentsArray.includes(component)) {
componentsArray.push(component);
}
}
for (const [key, component] of Object.entries(config.aliases)) {
const componentEntry = importMapComponents[component];
const from = componentEntry?.from;
if (!from) {
logger.warn(`Component ${component} not found in Vuetify.`);
continue;
}
const parts = from.split("/");
if (parts.length < 2) {
logger.warn(`Component ${component} not found in Vuetify, please report a new issue.`);
continue;
}
const bucket = parts[1];
if (!bucket) {
continue;
}
if (!componentsToImport.has(bucket)) {
componentsToImport.set(bucket, []);
}
const componentsArray = componentsToImport.get(bucket);
if (!componentsArray.includes(component)) {
componentsArray.push(component);
}
config.aliasEntries.push(`'${key}': ${component}`);
}
for (const [from, componentsArray] of componentsToImport.entries()) {
config.imports.push(`import {${Array.from(new Set(componentsArray)).join(",")}} from 'vuetify/components/${from}'`);
}
let addDatePicker = ctx.vuetifyGte("3.4.0") ? !Array.from(componentsToImport.values()).some((components2) => components2.includes("VDatePicker")) : true;
if (labComponents) {
const useLabComponents = [];
if (typeof labComponents === "boolean") {
config.imports.push("import * as labsComponents from 'vuetify/labs/components'");
config.labComponents.add("*");
if (!ctx.vuetifyGte("3.4.0")) {
addDatePicker = false;
}
} else if (typeof labComponents === "string") {
useLabComponents.push(labComponents);
} else if (Array.isArray(labComponents)) {
useLabComponents.push(...labComponents);
}
if (useLabComponents.length > 0) {
componentsToImport.clear();
const importMapLabComponents = await labComponentsPromise;
for (const component of useLabComponents) {
const componentEntry = importMapLabComponents[component];
const from = componentEntry?.from;
if (!from) {
logger.warn(`Lab Component ${component} not found in Vuetify.`);
continue;
}
const parts = from.split("/");
if (parts.length < 2) {
logger.warn(`Lab Component ${component} not found in Vuetify, please report a new issue.`);
continue;
}
const bucket = parts[1];
if (!bucket) {
continue;
}
if (!componentsToImport.has(bucket)) {
componentsToImport.set(bucket, []);
}
const componentsArray = componentsToImport.get(bucket);
if (!componentsArray.includes(component)) {
componentsArray.push(component);
}
config.labComponents.add(component);
}
if (!ctx.vuetifyGte("3.4.0") && dateOptions && !addDatePicker) {
const entry = componentsToImport.get("VDatePicker");
if (entry) {
entry.push("VDatePicker");
config.labComponents.add("VDatePicker");
addDatePicker = false;
}
}
for (const [from, componentsArray] of componentsToImport.entries()) {
config.imports.push(`import {${Array.from(new Set(componentsArray)).join(",")}} from 'vuetify/labs/${from}'`);
}
}
}
if (dateOptions && addDatePicker) {
let warn = true;
if (ctx.vuetifyGte("3.0.0")) {
warn = false;
if (ctx.vuetifyGte("3.4.0")) {
config.components.add("VDatePicker");
config.imports.push("import {VDatePicker} from 'vuetify/components/VDatePicker'");
} else {
config.labComponents.add("VDatePicker");
config.imports.push("import {VDatePicker} from 'vuetify/labs/VDatePicker'");
}
}
warn && logger.warn("Unable to load Vuetify version from package.json, add VDatePicker to components or labComponents");
}
let componentsEntry = "";
if (config.components.size > 0) {
if (config.labComponents.size > 0) {
componentsEntry = config.labComponents.has("*") ? `options.components = {${Array.from(config.components).join(",")},...labsComponents}` : `options.components = {${Array.from(config.components).join(",")},${Array.from(config.labComponents).join(",")}}`;
} else {
componentsEntry = `options.components = {${Array.from(config.components).join(",")}}`;
}
} else if (config.labComponents.size > 0) {
componentsEntry = config.labComponents.has("*") ? "options.components = {...labsComponents}" : `options.components = {${Array.from(config.labComponents).join(",")}}`;
}
if (!ctx.i18n && localeMessages) {
const useLocales = Array.isArray(localeMessages) ? [...new Set(localeMessages)] : [localeMessages];
config.imports.push(`import {${useLocales.join(",")}} from 'vuetify/locale'`);
config.messages = `
options.locale = options.locale || {}
options.locale.messages = options.locale.messages || {}
${useLocales.map((locale) => {
return `
if ('${locale}' in options.locale.messages)
deepCopy(options.locale.messages['${locale}'],${locale})
options.locale.messages['${locale}'] = ${locale}
`;
}).join("")}
`;
}
return {
imports: config.imports.length > 0 ? config.imports.join("\n") : "",
components: componentsEntry,
aliases: config.aliasEntries.length > 0 ? `options.aliases = {${config.aliasEntries.join(",")}}` : "",
directives: config.directives,
messages: config.messages
};
}
const VUETIFY_TO_DATE_FNS = {
en: "enUS",
fa: "faIR",
no: "nb",
srCyrl: "sr",
zhHans: "zhCN",
zhHant: "zhTW"
};
const DATE_FNS_SUPPORTED = /* @__PURE__ */ new Set([
"af",
"ar",
"az",
"bg",
"ca",
"ckb",
"cs",
"da",
"de",
"el",
"enUS",
"es",
"et",
"faIR",
"fi",
"fr",
"he",
"hr",
"hu",
"id",
"it",
"ja",
"km",
"ko",
"lt",
"lv",
"nb",
"nl",
"pl",
"pt",
"ro",
"ru",
"sk",
"sl",
"sr",
"srLatn",
"sv",
"th",
"tr",
"uk",
"vi",
"zhCN",
"zhTW"
]);
function resolveDateFnsLocaleName(code) {
if (!code) {
return { name: "enUS", fallback: true };
}
const candidate = VUETIFY_TO_DATE_FNS[code] ?? code;
if (DATE_FNS_SUPPORTED.has(candidate)) {
return { name: candidate, fallback: false };
}
return { name: "enUS", fallback: true };
}
function vuetifyDateConfigurationPlugin(ctx) {
return {
name: "vuetify:date-configuration:nuxt",
enforce: "pre",
resolveId(id) {
if (id === VIRTUAL_VUETIFY_DATE_CONFIGURATION) {
return RESOLVED_VIRTUAL_VUETIFY_DATE_CONFIGURATION;
}
},
async load(id) {
if (id === RESOLVED_VIRTUAL_VUETIFY_DATE_CONFIGURATION) {
if (ctx.isDev && ctx.canHmrConfig) {
for (const file of ctx.vuetifyFilesToWatch) {
this.addWatchFile(file);
}
}
if (!ctx.dateAdapter) {
return `
export const enabled = false
export const isDev = ${ctx.isDev}
export const i18n = ${ctx.i18n}
export const adapter = 'custom'
export function dateConfiguration() {
return {}
}
`;
}
const { adapter: _adapter, ...newDateOptions } = ctx.vuetifyOptions.date ?? {};
let dateFnsLocale;
if (ctx.dateAdapter === "date-fns") {
const resolved = resolveDateFnsLocaleName(ctx.vuetifyOptions.locale?.locale);
dateFnsLocale = resolved.name;
if (resolved.fallback) {
ctx.logger.warn(`[vuetify-nuxt-module] date-fns locale for "${ctx.vuetifyOptions.locale?.locale ?? "(unset)"}" not found, falling back to "enUS". Set "vuetifyOptions.locale.locale" to a supported locale.`);
}
}
return `${buildImports(dateFnsLocale)}
export const enabled = true
export const isDev = ${ctx.isDev}
export const i18n = ${ctx.i18n}
export const adapter = '${ctx.dateAdapter}'
export function dateConfiguration() {
const options = JSON.parse('${JSON.stringify(newDateOptions)}')
${buildAdapter(dateFnsLocale)}
return options
}
`;
}
}
};
function buildAdapter(dateFnsLocale) {
if (ctx.dateAdapter === "custom" || ctx.dateAdapter === "vuetify" && ctx.vuetifyGte("3.4.0")) {
return "";
}
if (ctx.dateAdapter === "vuetify") {
return "options.adapter = VuetifyDateAdapter";
}
if (ctx.dateAdapter === "date-fns") {
return `options.adapter = new Adapter({ locale: ${dateFnsLocale} })`;
}
return "options.adapter = Adapter";
}
function buildImports(dateFnsLocale) {
if (ctx.dateAdapter === "custom" || ctx.dateAdapter === "vuetify" && ctx.vuetifyGte("3.4.0")) {
return "";
}
if (ctx.dateAdapter === "vuetify") {
return "import { VuetifyDateAdapter } from 'vuetify/labs/date/adapters/vuetify'";
}
const imports = [`import Adapter from '@date-io/${ctx.dateAdapter}'`];
if (ctx.dateAdapter === "date-fns") {
imports.push(`import { ${dateFnsLocale} } from 'date-fns/locale'`);
}
return imports.join("\n");
}
}
function vuetifyIconsPlugin(ctx) {
return {
name: "vuetify:icons-configuration:nuxt",
enforce: "pre",
resolveId(id) {
if (id === VIRTUAL_VUETIFY_ICONS_CONFIGURATION) {
return RESOLVED_VIRTUAL_VUETIFY_ICONS_CONFIGURATION;
}
},
async load(id) {
if (id === RESOLVED_VIRTUAL_VUETIFY_ICONS_CONFIGURATION) {
if (ctx.isDev && ctx.canHmrConfig) {
for (const file of ctx.vuetifyFilesToWatch) {
this.addWatchFile(file);
}
}
const {
enabled,
unocss,
aliases,
fa,
defaultSet,
imports,
sets
} = await prepareIcons();
if (!enabled) {
return `export const enabled = false
export const isDev = ${ctx.isDev}
export function iconsConfiguration() {
return {}
}
`;
}
if (!defaultSet) {
return `export const enabled = true
export const isDev = ${ctx.isDev}
export function iconsConfiguration() {
return {}
}
`;
}
return `${imports}
export const enabled = true
export const isDev = ${ctx.isDev}
export function iconsConfiguration() {
${fa.map((f) => ` ${f}`).join("\n")}
return {
defaultSet: '${defaultSet}',
${aliases}
sets: { ${sets} }
}
}
${unocss}
`;
}
}
};
async function prepareIcons() {
if (!ctx.icons.enabled) {
return {
enabled: false,
unocss: "",
defaultSet: void 0,
imports: "",
sets: "",
aliases: "",
fa: []
};
}
let aliases = "aliases,";
if (!ctx.icons.aliasesImportPresent || ctx.vuetifyOptions.icons && ctx.vuetifyOptions.icons.defaultSet === "custom") {
aliases = "";
} else {
const alias = ctx.icons.aliases;
if (alias.length > 0) {
aliases = `aliases: {
...aliases,
${alias.join(",\n")}
},
`;
}
}
let unocss = "";
if (ctx.icons.unocss && ctx.icons.unocssAliases) {
ctx.icons.imports.unshift("// @unocss-include");
const prefix = `${ctx.icons.unocssIconPrefix}mdi:`;
const {
collapse = `${prefix}chevron-up`,
complete = `${prefix}check`,
cancel = `${prefix}close-circle`,
close = `${prefix}close`,
// delete (e.g. v-chip close)
clear = `${prefix}close-circle`,
success = `${prefix}check-circle`,
info = `${prefix}information`,
warning = `${prefix}alert-circle`,
error = `${prefix}close-circle`,
prev = `${prefix}chevron-left`,
next = `${prefix}chevron-right`,
checkboxOn = `${prefix}checkbox-marked`,
checkboxOff = `${prefix}checkbox-blank-outline`,
checkboxIndeterminate = `${prefix}minus-box`,
delimiter = `${prefix}circle`,
// for carousel
sortAsc = `${prefix}arrow-up`,
sortDesc = `${prefix}arrow-down`,
expand = `${prefix}chevron-down`,
menu = `${prefix}menu`,
subgroup = `${prefix}menu-down`,
dropdown = `${prefix}menu-down`,
radioOn = `${prefix}radiobox-marked`,
radioOff = `${prefix}radiobox-blank`,
edit = `${prefix}pencil`,
ratingEmpty = `${prefix}star-outline`,
ratingFull = `${prefix}star`,
ratingHalf = `${prefix}star-half-full`,
loading = `${prefix}cached`,
first = `${prefix}page-first`,
last = `${prefix}page-last`,
unfold = `${prefix}unfold-more-horizontal`,
file = `${prefix}paperclip`,
plus = `${prefix}plus`,
minus = `${prefix}minus`,
calendar = `${prefix}calendar`
} = ctx.icons.unocssIcons;
const useIcons = {
collapse,
complete,
cancel,
close,
delete: ctx.icons.unocssIcons.delete ?? `${prefix}close-circle`,
clear,
success,
info,
warning,
error,
prev,
next,
checkboxOn,
checkboxOff,
checkboxIndeterminate,
delimiter,
sortAsc,
sortDesc,
expand,
menu,
subgroup,
dropdown,
radioOn,
radioOff,
edit,
ratingEmpty,
ratingFull,
ratingHalf,
loading,
first,
last,
unfold,
file,
plus,
minus,
calendar
};
for (const [key, value] of Object.entries(ctx.icons.unocssAdditionalIcons)) {
useIcons[key] = value;
}
unocss = `const aliases = JSON.parse('${JSON.stringify(useIcons)}');
`;
}
return {
enabled: true,
unocss,
fa: ctx.icons.svg?.fa ?? [],
defaultSet: ctx.icons.defaultSet,
imports: Object.values(ctx.icons.imports).join("\n"),
sets: ctx.icons.sets.join(","),
aliases
};
}
}
function parseId2(id) {
id = id.replace(/^(virtual:nuxt:|virtual:)/, "");
return parseURL(decodeURIComponent(isAbsolute(id) ? pathToFileURL(id).href : id));
}
function reviver(key, value) {
if (key === "__proto__" || key === "constructor") {
return void 0;
}
return value;
}
function parseProps(value) {
try {
const parsed = JSON.parse(value, reviver);
return parsed && typeof parsed === "object" ? parsed : void 0;
} catch {
return void 0;
}
}
function parseId(id) {
const { search, pathname } = parseId2(id);
const query = parseQuery(search);
const urlProps = query.props ? parseProps(query.props) : void 0;
return {
query: urlProps,
path: pathname ?? id
};
}
function vuetifyImportPlugin(options) {
let filter;
return {
name: "vuetify:import:nuxt",
configResolved(config) {
if (config.plugins.some((plugin) => plugin.name === "vuetify:import")) {
throw new Error("Remove vite-plugin-vuetify from your Nuxt config file, this module registers a modified version.");
}
const vueIdx = config.plugins.findIndex((plugin) => plugin.name === "vite:vue");
const vueOptions = vueIdx === -1 ? {} : config.plugins[vueIdx].api?.options;
filter = createFilter(vueOptions.include, vueOptions.exclude);
},
async transform(code, id) {
const { query, path } = parseId(id);
const isVueVirtual = query && "vue" in query;
const isVueFile = !isVueVirtual && filter(path) && !/^import { render as _sfc_render } from ".*"$/m.test(code);
const isVueTemplate = isVueVirtual && (query.type === "template" || query.type === "script" && query.setup === "true");
if (isVueFile || isVueTemplate) {
const { code: imports, source } = generateImports(code, options);
return {
code: source + imports,
map: null
};
}
return null;
}
};
}
function vuetifySSRClientHintsPlugin(ctx) {
return {
name: "vuetify:ssr-client-hints:nuxt",
enforce: "pre",
resolveId(id) {
if (id === VIRTUAL_VUETIFY_SSR_CLIENT_HINTS_CONFIGURATION) {
return RESOLVED_VIRTUAL_VUETIFY_SSR_CLIENT_HINTS_CONFIGURATION;
}
},
async load(id) {
if (id === RESOLVED_VIRTUAL_VUETIFY_SSR_CLIENT_HINTS_CONFIGURATION) {
const data = {
reloadOnFirstRequest: ctx.ssrClientHints.reloadOnFirstRequest,
viewportSize: ctx.ssrClientHints.viewportSize,
prefersColorScheme: ctx.ssrClientHints.prefersColorScheme,
prefersReducedMotion: ctx.ssrClientHints.prefersReducedMotion,
clientWidth: ctx.vuetifyOptions.ssr?.clientWidth,
clientHeight: ctx.vuetifyOptions.ssr?.clientHeight,
prefersColorSchemeOptions: ctx.ssrClientHints.prefersColorSchemeOptions
};
return `export const ssrClientHintsConfiguration = JSON.parse('${JSON.stringify(data)}');`;
}
}
};
}
function detectDate(paths) {
const result = [];
for (const adapter of [
"date-fns",
"moment",
"luxon",
"dayjs",
"js-joda",
"date-fns-jalali",
"jalaali",
"hijri"
]) {
if (isPackageExists(`@date-io/${adapter}`, { paths })) {
result.push(adapter);
}
}
return result;
}
function multipleDateAdaptersError(adapters) {
return `Multiple date adapters found: ${adapters.map((adapter) => `@date-io/${adapter}`).join(", ")}, please specify the adapter to use in the "vuetifyOptions.date.adapter" option.`;
}
function cleanupBlueprint(vuetifyOptions) {
const blueprint = vuetifyOptions.blueprint;
if (blueprint) {
delete blueprint.ssr;
delete blueprint.components;
delete blueprint.directives;
delete blueprint.locale;
delete blueprint.date;
delete blueprint.icons;
vuetifyOptions.blueprint = blueprint;
}
}
function checkVuetifyPlugins(config) {
let plugin = config.plugins?.find((p) => p && typeof p === "object" && "name" in p && p.name === "vuetify:import");
if (plugin) {
throw new Error("Remove vite-plugin-vuetify plugin from Vite Plugins entry in Nuxt config file!");
}
plugin = config.plugins?.find((p) => p && typeof p === "object" && "name" in p && p.name === "vuetify:styles");
if (plugin) {
throw new Error("Remove vite-plugin-vuetify plugin from Vite Plugins entry in Nuxt config file!");
}
}
function resolveVuetifyComponents(resolver, vuetifyBase) {
const componentsPromise = importMapResolver();
const labComponentsPromise = importMapLabResolver();
return {
componentsPromise,
labComponentsPromise
};
async function importMapResolver() {
return JSON.parse(await readFile(resolver.resolve(vuetifyBase, "dist/json/importMap.json"), "utf8")).components;
}
async function importMapLabResolver() {
return JSON.parse(await readFile(resolver.resolve(vuetifyBase, "dist/json/importMap-labs.json"), "utf8")).components;
}
}
function resolveStylesCache(stylesOption) {
return stylesOption.cache ?? stylesOption.experimental?.cache;
}
function configureVite(configKey, nuxt, ctx) {
nuxt.hook("vite:extend", ({ config }) => checkVuetifyPlugins(config));
nuxt.hook("vite:extendConfig", (viteInlineConfig) => {
viteInlineConfig.plugins = viteInlineConfig.plugins || [];
checkVuetifyPlugins(viteInlineConfig);
if (!ctx.moduleOptions.disableModernSassCompiler) {
const enableModernSassCompiler = semver.gte(ctx.viteVersion, "5.4.0") && semver.lt(ctx.viteVersion, "7.0.0-0");
if (enableModernSassCompiler) {
const sassEmbedded = isPackageExists("sass-embedded", { paths: ctx.resolvePaths });
if (sassEmbedded) {
viteInlineConfig.css ??= {};
viteInlineConfig.css.preprocessorOptions ??= {};
viteInlineConfig.css.preprocessorOptions.sass ??= {};
viteInlineConfig.css.preprocessorOptions.sass.api = "modern-compiler";
viteInlineConfig.css.preprocessorOptions.scss ??= {};
viteInlineConfig.css.preprocessorOptions.scss.api = "modern-compiler";
} else {
viteInlineConfig.css ??= {};
viteInlineConfig.css.preprocessorOptions ??= {};
viteInlineConfig.css.preprocessorOptions.sass ??= {};
viteInlineConfig.css.preprocessorOptions.sass.api = "modern";
viteInlineConfig.css.preprocessorOptions.scss ??= {};
viteInlineConfig.css.preprocessorOptions.scss.api = "modern";
if (!("preprocessorMaxWorkers" in viteInlineConfig.css)) {
viteInlineConfig.css.preprocessorMaxWorkers = true;
}
}
}
}
viteInlineConfig.optimizeDeps = defu(viteInlineConfig.optimizeDeps, { exclude: ["vuetify"] });
if (ctx.isSSR) {
viteInlineConfig.ssr ||= {};
viteInlineConfig.ssr.noExternal = [
...Array.isArray(viteInlineConfig.ssr.noExternal) ? viteInlineConfig.ssr.noExternal : viteInlineConfig.ssr.noExternal && typeof viteInlineConfig.ssr.noExternal !== "boolean" ? [viteInlineConfig.ssr.noExternal] : [],
configKey
];
}
const transformAssetUrls = createTransformAssetUrls(
ctx,
viteInlineConfig
);
if (transformAssetUrls) {
viteInlineConfig.vue ??= {};
viteInlineConfig.vue.template ??= {};
viteInlineConfig.vue.template.transformAssetUrls = transformAssetUrls;
}
const autoImport = { labs: true };
const ignoreDirectives = ctx.moduleOptions.ignoreDirectives;
if (ignoreDirectives) {
autoImport.ignore = Array.isArray(ignoreDirectives) ? ignoreDirectives : [ignoreDirectives];
}
viteInlineConfig.plugins.push(vuetifyImportPlugin({ autoImport }));
const stylesOption = ctx.moduleOptions.styles;
if (stylesOption === "none") {
viteInlineConfig.plugins.push(Styles({ styles: "none" }));
} else if (typeof stylesOption === "object" && stylesOption !== null && "configFile" in stylesOption) {
if (!ctx.stylesConfigFile) {
throw new Error("vuetify-nuxt-module: styles.configFile could not be resolved");
}
const cache = resolveStylesCache(stylesOption);
viteInlineConfig.plugins.push(Styles({
settings: ctx.stylesConfigFile,
...cache === void 0 ? {} : { cache }
}));
}
viteInlineConfig.plugins.push(vuetifyConfigurationPlugin(ctx), vuetifyIconsPlugin(ctx), vuetifyDateConfigurationPlugin(ctx));
if (ctx.ssrClientHints.enabled) {
viteInlineConfig.plugins.push(vuetifySSRClientHintsPlugin(ctx));
}
});
}
const cssFonts = ["unocss-mdi", "mdi", "md", "fa", "fa4"];
const iconsPackageNames = {
"unocss-mdi": { name: "@mdi/font", css: "" },
"mdi": { name: "@mdi/font", css: "@mdi/font/css/materialdesignicons.css" },
"md": { name: "material-design-icons-iconfont", css: "@mdi/font/css/materialdesignicons.css" },
"fa": { name: "@fortawesome/fontawesome-free", css: "@fortawesome/fontawesome-free/css/all.css" },
"fa4": { name: "font-awesome@4.7.0", css: "font-awesome/css/font-awesome.min.css" }
};
const iconsCDN = {
"unocss-mdi": "",
"mdi": "https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css",
"md": "https://fonts.googleapis.com/css?family=Material+Icons",
"fa": "https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@latest/css/all.min.css",
"fa4": "https://cdn.jsdelivr.net/npm/font-awesome@4.x/css/font-awesome.min.css"
};
const disabledResolvedIcons = Object.freeze({
enabled: false,
unocss: false,
unocssAliases: false,
unocssIconPrefix: "i-",
unocssIcons: {},
unocssAdditionalIcons: {},
imports: [],
aliases: [],
aliasesImportPresent: false,
sets: [],
cdn: [],
local: [],
svg: {}
});
function prepareIcons(unocssPresent, logger, vuetifyOptions, paths) {
const iconPackageExists = (name) => isPackageExists(name, { paths });
if (vuetifyOptions.icons === false) {
return disabledResolvedIcons;
}
const icons = vuetifyOptions.icons || {};
let { defaultSet = "mdi", sets } = icons;
if (!defaultSet) {
defaultSet = icons.defaultSet = "mdi";
}
if (!sets && defaultSet !== "mdi-svg" && defaultSet !== "fa-svg" && defaultSet !== "custom") {
sets = [{ name: defaultSet || "mdi" }];
}
sets = sets ? convertFontSetsToObjectNotation(sets) : [];
const resolvedIcons = {
enabled: true,
unocss: unocssPresent && (defaultSet === "unocss-mdi" || sets.some((s) => s.name === "unocss-mdi")),
unocssAliases: defaultSet === "unocss-mdi",
unocssIconPrefix: icons.unocssIconPrefix ?? "i-",
unocssIcons: icons.unocssIcons ?? {},
unocssAdditionalIcons: icons.unocssAdditionalIcons ?? {},
defaultSet,
sets: [],
aliases: [],
aliasesImportPresent: false,
imports: [],
cdn: [],
local: [],
svg: {
mdi: false
}
};
if (sets) {
if (!unocssPresent && defaultSet === "unocss-mdi") {
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!");
defaultSet = "mdi";
sets = sets.filter((s) => s.name !== "unocss-mdi");
}
for (const { name, cdn } of sets.filter((s) => cssFonts.includes(s.name))) {
resolvedIcons.aliasesImportPresent ||= name === defaultSet;
if (name === "unocss-mdi") {
continue;
}
resolvedIcons.imports.push(`import {${name === defaultSet ? "aliases," : ""}${name}} from 'vuetify/iconsets/${name}'`);
resolvedIcons.sets.push(name);
if (iconPackageExists(iconsPackageNames[name].name)) {
resolvedIcons.local.push(iconsPackageNames[name].css);
} else {
resolvedIcons.cdn.push([name, cdn ?? iconsCDN[name]]);
}
}
if (resolvedIcons.unocss && defaultSet === "unocss-mdi") {
if (!resolvedIcons.sets.includes("mdi")) {
resolvedIcons.sets.push("mdi");
resolvedIcons.imports.push("import {mdi} from 'vuetify/iconsets/mdi'");
}
resolvedIcons.defaultSet = "mdi";
}
}
let faSvg = icons.svg?.fa;
if (defaultSet === "fa-svg" || faSvg) {
if (!faSvg) {
faSvg = {};
}
let faSvgExists = iconPackageExists("@fortawesome/fontawesome-svg-core");
if (!faSvgExists) {
logger.warn("Missing @fortawesome/fontawesome-svg-core dependency, install it!");
}
faSvgExists = iconPackageExists("@fortawesome/vue-fontawesome");
if (faSvgExists) {
if (!faSvg.libraries?.length) {
faSvg.libraries = [[false, "fas", "@fortawesome/free-solid-svg-icons"]];
}
for (const p in faSvg.libraries) {
const [_defaultExport, _name, library] = faSvg.libraries[p];
if (!iconPackageExists(library)) {
faSvgExists = false;
logger.warn(`Missing library ${library} dependency, install it!`);
}
}
} else {
logger.warn("Missing @fortawesome/vue-fontawesome dependency, install it!");
}
if (faSvgExists) {
resolvedIcons.aliasesImportPresent ||= defaultSet === "fa-svg";
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'");
resolvedIcons.svg.fa = ["useNuxtApp().vueApp.component('font-awesome-icon', FontAwesomeIcon)"];
for (const [defaultExport, name, library] of faSvg.libraries) {
resolvedIcons.imports.push(`import ${defaultExport ? name : `{${name}}`} from '${library}'`);
resolvedIcons.svg.fa.push(`library.add(${name})`);
}
resolvedIcons.sets.push("fa");
if (defaultSet === "fa-svg") {
resolvedIcons.defaultSet = "fa";
}
}
}
let mdiSvg = icons.svg?.mdi;
if (defaultSet === "mdi-svg" || mdiSvg) {
if (!mdiSvg) {
mdiSvg = {};
}
const mdiSvgExists = iconPackageExists("@mdi/js");
if (mdiSvgExists) {
resolvedIcons.svg.mdi = true;
resolvedIcons.aliasesImportPresent ||= defaultSet === "mdi-svg";
resolvedIcons.imports.push(`import {${defaultSet === "mdi-svg" ? "aliases," : ""}mdi} from 'vuetify/iconsets/mdi-svg'`);
if (mdiSvg && mdiSvg.aliases) {
resolvedIcons.imports.push(`import {${Object.values(mdiSvg.aliases).join(",")}} from '@mdi/js'`);
for (const [alias, icon] of Object.entries(mdiSvg.aliases)) {
resolvedIcons.aliases.push(`${alias}: ${icon}`);
}
}
resolvedIcons.sets.push("mdi");
if (defaultSet === "mdi-svg") {
resolvedIcons.defaultSet = "mdi";
}
} else {
resolvedIcons.svg.mdi = false;
logger.warn("Missing @mdi/js dependency, install it!");
}
}
if (defaultSet !== "custom" && !resolvedIcons.unocss && !resolvedIcons.local?.length && !resolvedIcons.cdn?.length && !resolvedIcons.svg?.mdi && !resolvedIcons.svg?.fa?.length) {
logger.warn("No icons found, icons disabled!");
return disabledResolvedIcons;
}
return resolvedIcons;
}
function convertFontSetsToObjectNotation(sets) {
const result = [];
if (typeof sets === "string") {
result.push({ name: sets });
} else {
for (const set of sets) {
if (typeof set === "string") {
result.push({ name: set });
} else {
result.push(set);
}
}
}
return result;
}
async function loadVuetifyConfiguration(cwd = process.cwd(), configOrPath = cwd, defaults = {}, extraConfigSources = []) {
let inlineConfig = {};
if (typeof configOrPath !== "string") {
inlineConfig = configOrPath;
configOrPath = process.cwd();
}
const resolved = resolve(cwd, configOrPath);
let isFile = false;
if (existsSync(resolved) && statSync(resolved).isFile()) {
isFile = true;
cwd = dirname(resolved).replace(/\\/g, "/");
}
const rewrite = (config) => {
if (typeof config === "function") {
return config();
}
return config;
};
const loader = createConfigLoader({
sources: isFile ? [
{
files: resolved,
extensions: [],
rewrite
}
] : [
{
files: [
"vuetify.config"
],
// we don't want `package.json` to be loaded
extensions: ["mts", "cts", "ts", "mjs", "cjs", "js"],
rewrite
},
...extraConfigSources
],
cwd,
defaults: inlineConfig,
merge: false
});
const result = await loader.load();
result.config = result.config?.config === false ? Object.assign(defaults, inlineConfig) : Object.assign(defaults, result.config || inlineConfig);
if (result.config && typeof result.config === "object" && "vuetifyOptions" in result.config) {
const nestedOptions = result.config.vuetifyOptions;
if (typeof nestedOptions === "object" && nestedOptions !== null) {
console.warn('[@vuetify/nuxt-module] Detected nested "vuetifyOptions" in your configuration file. This usually happens when using a named export or wrapping options incorrectly. Please export the options directly using "export default".');
Object.assign(result.config, nestedOptions);
delete result.config.vuetifyOptions;
}
}
delete result.config.config;
return result;
}
const MODULE_DEFAULTS = {
moduleOptions: {
importComposables: true,
includeTransformAssetsUrls: true,
styles: true,
rulesConfiguration: {
fromLabs: true
}
},
vuetifyOptions: {
labComponents: false,
directives: false
}
};
function finalizeConfiguration(moduleOptions) {
if (moduleOptions.length > 1) {
const [app, ...rest] = moduleOptions;
const configuration = defu(app, ...rest, MODULE_DEFAULTS);
dedupeIcons(configuration, moduleOptions.toReversed());
return configuration;
}
return defu(moduleOptions[0] ?? {}, MODULE_DEFAULTS);
}
async function mergeVuetifyModules(options, nuxt) {
const moduleOptions = [];
const vuetifyConfigurationFilesToWatch = /* @__PURE__ */ new Set();
await nuxt.callHook("vuetify:registerModule", (layerModuleOptions) => moduleOptions.push(layerModuleOptions));
if (nuxt.options._layers.length > 1) {
for (let i = 1; i < nuxt.options._layers.length; i++) {
const layer = nuxt.options._layers[i];
const resolvedOptions2 = await loadVuetifyConfiguration(
layer.config.rootDir,
layer.config.vuetify?.vuetifyOptions
);
if (resolvedOptions2.sources.length > 0) {
for (const s of resolvedOptions2.sources.map((s2) => s2.replace(/\\/g, "/")).filter((s2) => !s2.includes("/node_modules/"))) {
vuetifyConfigurationFilesToWatch.add(s);
}
}
moduleOptions.push({
moduleOptions: layer.config.vuetify?.moduleOptions,
vuetifyOptions: resolvedOptions2.config
});
}
}
const resolvedOptions = await loadVuetifyConfiguration(
nuxt.options.rootDir,
options.vuetifyOptions
);
if (nuxt.options.dev && resolvedOptions.sources.length > 0) {
for (const s of resolvedOptions.sources) {
vuetifyConfigurationFilesToWatch.a