vuetify-nuxt-module
Version:
Zero-Config Nuxt Module for Vuetify
1,357 lines (1,335 loc) • 55 kB
JavaScript
import { addVitePlugin, addPluginTemplate, getNuxtVersion, extendWebpackConfig, addImports, addPlugin, useLogger, defineNuxtModule, isNuxt2, createResolver, hasNuxtModule } from '@nuxt/kit';
import { isPackageExists, getPackageInfo } from 'local-pkg';
import { createFilter, version as version$1 } from 'vite';
import { resolve, dirname, relative } from 'node:path';
import defu from 'defu';
import { debounce } from 'perfect-debounce';
import fs, { existsSync, statSync } from 'node:fs';
import process from 'node:process';
import { createConfigLoader } from 'unconfig';
import fsp, { readFile } from 'node:fs/promises';
import { resolveVuetifyBase, isObject, normalizePath, generateImports } from '@vuetify/loader-shared';
import { pathToFileURL } from 'node:url';
import { relative as relative$1, isAbsolute } from 'pathe';
import path from 'upath';
import { transformAssetUrls } from 'vite-plugin-vuetify';
import { parseQuery, parseURL } from 'ufo';
import destr from 'destr';
const version = "0.18.6";
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
];
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();
if (result.config?.config === false)
result.config = Object.assign(defaults, inlineConfig);
else
result.config = Object.assign(defaults, result.config || inlineConfig);
delete result.config.config;
return result;
}
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) {
resolvedOptions2.sources.map((s) => s.replace(/\\/g, "/")).filter((s) => !s.includes("/node_modules/")).forEach((s) => 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) {
if (nuxt.options.ssr)
resolvedOptions.sources.forEach((s) => nuxt.options.watch.push(s.replace(/\\/g, "/")));
else
resolvedOptions.sources.forEach((s) => vuetifyConfigurationFilesToWatch.add(s.replace(/\\/g, "/")));
}
moduleOptions.unshift({
moduleOptions: options.moduleOptions,
vuetifyOptions: resolvedOptions.config
});
if (moduleOptions.length > 1) {
const [app, ...rest] = moduleOptions;
const configuration = defu(app, ...rest);
dedupeIcons(configuration, moduleOptions.reverse());
return {
configuration,
vuetifyConfigurationFilesToWatch
};
} else {
return {
configuration: {
moduleOptions: options.moduleOptions,
vuetifyOptions: resolvedOptions.config
},
vuetifyConfigurationFilesToWatch
};
}
}
function dedupeIcons(configuration, moduleOptions) {
const vuetifyOptions = configuration.vuetifyOptions;
if (vuetifyOptions.icons) {
if (vuetifyOptions.icons.sets) {
const sets = /* @__PURE__ */ new Map();
for (const { vuetifyOptions: vuetifyOptions2 } of moduleOptions) {
if (vuetifyOptions2.icons && vuetifyOptions2.icons.sets) {
const mSets = vuetifyOptions2.icons.sets;
if (typeof mSets === "string") {
sets.set(mSets, { name: mSets });
} else {
for (const set of mSets) {
if (typeof set === "string")
sets.set(set, { name: set });
else
sets.set(set.name, set);
}
}
}
}
vuetifyOptions.icons.sets = Array.from(sets.values());
}
}
}
function detectDate() {
const result = [];
[
"date-fns",
"moment",
"luxon",
"dayjs",
"js-joda",
"date-fns-jalali",
"jalaali",
"hijri"
].forEach((adapter) => {
if (isPackageExists(`@date-io/${adapter}`))
result.push(adapter);
});
return result;
}
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) {
const vuetifyBase = resolveVuetifyBase();
const componentsPromise = importMapResolver();
const labComponentsPromise = importMapLabResolver();
return {
vuetifyBase,
componentsPromise,
labComponentsPromise
};
async function importMapResolver() {
return JSON.parse(await readFile(resolver.resolve(vuetifyBase, "dist/json/importMap.json"), "utf-8")).components;
}
async function importMapLabResolver() {
return JSON.parse(await readFile(resolver.resolve(vuetifyBase, "dist/json/importMap-labs.json"), "utf-8")).components;
}
}
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) {
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");
}
sets.filter((s) => cssFonts.includes(s.name)).forEach(({ name, cdn }) => {
resolvedIcons.aliasesImportPresent ||= name === defaultSet;
if (name === "unocss-mdi")
return;
resolvedIcons.imports.push(`import {${name === defaultSet ? "aliases," : ""}${name}} from 'vuetify/iconsets/${name}'`);
resolvedIcons.sets.push(name);
if (isPackageExists(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 = isPackageExists("@fortawesome/fontawesome-svg-core");
if (!faSvgExists)
logger.warn("Missing @fortawesome/fontawesome-svg-core dependency, install it!");
faSvgExists = isPackageExists("@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 (!isPackageExists(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'`);
resolvedIcons.imports.push("import { library } from '@fortawesome/fontawesome-svg-core'");
resolvedIcons.imports.push("import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'");
resolvedIcons.imports.push("import { useNuxtApp } from '#imports'");
resolvedIcons.svg.fa = ["useNuxtApp().vueApp.component('font-awesome-icon', FontAwesomeIcon)"];
faSvg.libraries.forEach(([defaultExport, name, library]) => {
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 = isPackageExists("@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'`);
Object.entries(mdiSvg.aliases).forEach(([alias, icon]) => {
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;
}
const disabledClientHints = Object.freeze({
enabled: false,
reloadOnFirstRequest: false,
viewportSize: false,
prefersColorScheme: false,
prefersReducedMotion: false
});
function prepareSSRClientHints(baseUrl, ctx) {
if (!ctx.isSSR || ctx.isNuxtGenerate)
return disabledClientHints;
const { ssrClientHints: ssrClientHintsConfiguration } = ctx.moduleOptions;
const clientHints = {
enabled: false,
reloadOnFirstRequest: ssrClientHintsConfiguration?.reloadOnFirstRequest ?? false,
viewportSize: ssrClientHintsConfiguration?.viewportSize ?? false,
prefersColorScheme: ssrClientHintsConfiguration?.prefersColorScheme ?? false,
prefersReducedMotion: ssrClientHintsConfiguration?.prefersReducedMotion ?? false
};
clientHints.enabled = clientHints.viewportSize || clientHints.prefersColorScheme || clientHints.prefersReducedMotion;
if (clientHints.enabled && clientHints.prefersColorScheme && ssrClientHintsConfiguration?.prefersColorSchemeOptions) {
const theme = ctx.vuetifyOptions.theme;
if (!theme)
throw new Error("Vuetify theme is disabled");
const themes = theme.themes;
if (!themes)
throw new Error("Vuetify themes is missing in theme!");
const defaultTheme = theme.defaultTheme;
if (!defaultTheme)
throw new Error("Vuetify default theme is missing in theme!");
if (!themes[defaultTheme])
throw new Error(`Missing default theme ${defaultTheme} in the Vuetify themes!`);
const darkThemeName = ssrClientHintsConfiguration.prefersColorSchemeOptions?.darkThemeName ?? "dark";
if (!themes[darkThemeName])
throw new Error(`Missing theme ${darkThemeName} in the Vuetify themes!`);
const lightThemeName = ssrClientHintsConfiguration.prefersColorSchemeOptions?.lightThemeName ?? "light";
if (!themes[lightThemeName])
throw new Error(`Missing theme ${lightThemeName} in the Vuetify themes!`);
if (darkThemeName === lightThemeName)
throw new Error("Vuetify dark theme and light theme are the same, change darkThemeName or lightThemeName!");
clientHints.prefersColorSchemeOptions = {
baseUrl,
defaultTheme,
themeNames: Array.from(Object.keys(themes)),
cookieName: ssrClientHintsConfiguration.prefersColorSchemeOptions?.cookieName ?? "color-scheme",
darkThemeName,
lightThemeName,
useBrowserThemeOnly: ssrClientHintsConfiguration.prefersColorSchemeOptions?.useBrowserThemeOnly ?? false
};
}
return clientHints;
}
async function load(options, nuxt, ctx) {
const {
configuration,
vuetifyConfigurationFilesToWatch
} = await mergeVuetifyModules(options, nuxt);
if (typeof ctx.componentsPromise === "undefined") {
const {
componentsPromise,
labComponentsPromise
} = resolveVuetifyComponents(ctx.resolver);
ctx.componentsPromise = componentsPromise;
ctx.labComponentsPromise = labComponentsPromise;
}
const { vuetifyOptions = {} } = configuration;
const {
directives: _directives,
labComponents: _labComponents,
...vOptions
} = vuetifyOptions;
const vuetifyAppOptions = defu(vOptions, {});
cleanupBlueprint(vuetifyAppOptions);
ctx.dateAdapter = void 0;
const dateOptions = vuetifyOptions.date;
if (dateOptions) {
const adapter = dateOptions.adapter;
const date = detectDate();
if (!adapter && date.length > 1)
throw new Error(`Multiple date adapters found: ${date.map((d) => `@date-io/${d[0]}`).join(", ")}, please specify the adapter to use in the "vuetifyOptions.date.adapter" option.`);
if (adapter) {
if (adapter === "vuetify" || adapter === "custom") {
ctx.dateAdapter = adapter;
} else {
if (date.find((d) => d === adapter) === void 0)
ctx.logger.warn(`[vuetify-nuxt-module] Ignoring Vuetify Date configuration, date adapter "@date-io/${adapter}" not installed!`);
else
ctx.dateAdapter = adapter;
}
} else if (date.length === 0) {
ctx.dateAdapter = "vuetify";
} else {
ctx.dateAdapter = date[0];
}
}
const oldIcons = ctx.icons;
if (oldIcons && oldIcons.cdn?.length && nuxt.options.app.head.link)
nuxt.options.app.head.link = nuxt.options.app.head.link.filter((link) => !link.key || !oldIcons.cdn.some(([key]) => link.key === key));
ctx.moduleOptions = configuration.moduleOptions;
ctx.vuetifyOptions = configuration.vuetifyOptions;
ctx.vuetifyFilesToWatch = Array.from(vuetifyConfigurationFilesToWatch);
ctx.icons = prepareIcons(ctx.unocss, ctx.logger, vuetifyAppOptions);
ctx.ssrClientHints = prepareSSRClientHints(nuxt.options.app.baseURL ?? "/", ctx);
if (ctx.icons.enabled) {
ctx.icons.local?.forEach((css) => nuxt.options.css.push(css));
if (ctx.icons.cdn?.length) {
nuxt.options.app.head.link ??= [];
ctx.icons.cdn.forEach(([key, href]) => nuxt.options.app.head.link.push({
key,
rel: "stylesheet",
href,
type: "text/css",
crossorigin: "anonymous"
}));
}
}
}
function registerWatcher(options, nuxt, ctx) {
if (nuxt.options.dev) {
let pageReload;
nuxt.hooks.hook("builder:watch", (_event, path) => {
path = relative(nuxt.options.srcDir, resolve(nuxt.options.srcDir, path));
if (!pageReload && ctx.vuetifyFilesToWatch.includes(path))
return nuxt.callHook("restart");
});
nuxt.hook("vite:serverCreated", (server, { isClient }) => {
if (!server.ws || !isClient)
return;
pageReload = debounce(async () => {
const modules = [];
for (const v of RESOLVED_VIRTUAL_MODULES) {
const module = server.moduleGraph.getModuleById(v);
if (module)
modules.push(module);
}
await load(options, nuxt, ctx);
if (modules.length)
await Promise.all(modules.map((m) => server.reloadModule(m)));
}, 50, { trailing: false });
});
addVitePlugin({
name: "vuetify:configuration:watch",
enforce: "pre",
handleHotUpdate({ file }) {
if (pageReload && ctx.vuetifyFilesToWatch.includes(file))
return pageReload();
}
});
}
}
function vuetifyStylesPlugin(options, [major, minor, patch], _logger) {
let configFile;
const vuetifyBase = resolveVuetifyBase();
const noneFiles = /* @__PURE__ */ new Set();
let isNone = false;
let sassVariables = false;
let fileImport = false;
const PREFIX = "vuetify-styles/";
const SSR_PREFIX = `/@${PREFIX}`;
const resolveCss = resolveCssFactory();
return {
name: "vuetify:styles:nuxt",
enforce: "pre",
configResolved(config) {
if (config.plugins.findIndex((plugin) => plugin.name === "vuetify:styles") > -1)
throw new Error("Remove vite-plugin-vuetify from your Nuxt config file, this module registers a modified version.");
if (isObject(options.styles)) {
sassVariables = true;
fileImport = major > 5 || major === 5 && minor > 4 || major === 5 && minor === 4 && patch > 2;
if (path.isAbsolute(options.styles.configFile))
configFile = path.resolve(options.styles.configFile);
else
configFile = path.resolve(path.join(config.root || process.cwd(), options.styles.configFile));
configFile = fileImport ? pathToFileURL(configFile).href : normalizePath(configFile);
} else {
isNone = options.styles === "none";
}
},
async resolveId(source, importer, { custom, ssr }) {
if (source.startsWith(PREFIX) || source.startsWith(SSR_PREFIX)) {
if (source.match(/\.s[ca]ss$/))
return source;
const idx = source.indexOf("?");
return idx > -1 ? source.slice(0, idx) : source;
}
if (source === "vuetify/styles" || importer && source.endsWith(".css") && isSubdir(vuetifyBase, path.isAbsolute(source) ? source : importer)) {
if (options.styles === "sass")
return this.resolve(await resolveCss(source), importer, { skipSelf: true, custom });
const resolution = await this.resolve(source, importer, { skipSelf: true, custom });
if (!resolution)
return void 0;
const target = await resolveCss(resolution.id);
if (isNone) {
noneFiles.add(target);
return target;
}
return `${ssr ? SSR_PREFIX : PREFIX}${path.relative(vuetifyBase, target)}`;
}
return void 0;
},
load(id) {
if (sassVariables) {
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;
if (target) {
const suffix = target.match(/\.scss/) ? ";\n" : "\n";
return {
code: `@use "${configFile}"${suffix}@use "${fileImport ? pathToFileURL(target).href : normalizePath(target)}"${suffix}`,
map: {
mappings: ""
}
};
}
}
return isNone && noneFiles.has(id) ? "" : void 0;
}
};
}
function resolveCssFactory() {
const mappings = /* @__PURE__ */ new Map();
return async (source) => {
let mapping = mappings.get(source);
if (!mapping) {
try {
mapping = source.replace(/\.css$/, ".sass");
await fsp.access(mapping, fs.constants.R_OK);
} catch (err) {
if (!(err instanceof Error && "code" in err && err.code === "ENOENT"))
throw err;
mapping = source.replace(/\.css$/, ".scss");
}
mappings.set(source, mapping);
}
return mapping;
};
}
function isSubdir(root, test) {
const relative = relative$1(root, test);
return relative && !relative.startsWith("..") && !isAbsolute(relative);
}
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 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) {
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;
return `${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();
config.components.forEach((component) => {
const { from } = importMapComponents[component];
if (!from) {
logger.warn(`Component ${component} not found in Vuetify.`);
return;
}
const parts = from.split("/");
if (parts.length < 2) {
logger.warn(`Component ${component} not found in Vuetify, please report a new issue.`);
return;
}
if (!componentsToImport.has(parts[1]))
componentsToImport.set(parts[1], []);
const componentsArray = componentsToImport.get(parts[1]);
if (!componentsArray.includes(component))
componentsArray.push(component);
});
Object.entries(config.aliases).forEach(([key, component]) => {
const { from } = importMapComponents[component];
if (!from) {
logger.warn(`Component ${component} not found in Vuetify.`);
return;
}
const parts = from.split("/");
if (parts.length < 2) {
logger.warn(`Component ${component} not found in Vuetify, please report a new issue.`);
return;
}
if (!componentsToImport.has(parts[1]))
componentsToImport.set(parts[1], []);
const componentsArray = componentsToImport.get(parts[1]);
if (!componentsArray.includes(component))
componentsArray.push(component);
config.aliasEntries.push(`'${key}': ${component}`);
});
componentsToImport.forEach((componentsArray, from) => {
config.imports.push(`import {${Array.from(new Set(componentsArray)).join(",")}} from 'vuetify/components/${from}'`);
});
let addDatePicker = ctx.vuetify3_4 === true ? !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.vuetify3_4 === false)
addDatePicker = false;
} else if (typeof labComponents === "string") {
useLabComponents.push(labComponents);
} else if (Array.isArray(labComponents)) {
useLabComponents.push(...labComponents);
}
if (useLabComponents.length) {
componentsToImport.clear();
const importMapLabComponents = await labComponentsPromise;
useLabComponents.forEach((component) => {
const { from } = importMapLabComponents[component];
if (!from) {
logger.warn(`Lab Component ${component} not found in Vuetify.`);
return;
}
const parts = from.split("/");
if (parts.length < 2) {
logger.warn(`Lab Component ${component} not found in Vuetify, please report a new issue.`);
return;
}
if (!componentsToImport.has(parts[1]))
componentsToImport.set(parts[1], []);
const componentsArray = componentsToImport.get(parts[1]);
if (!componentsArray.includes(component))
componentsArray.push(component);
config.labComponents.add(component);
});
if (ctx.vuetify3_4 === false && dateOptions && !addDatePicker) {
const entry = componentsToImport.get("VDatePicker");
if (entry) {
entry.push("VDatePicker");
config.labComponents.add("VDatePicker");
addDatePicker = false;
}
}
componentsToImport.forEach((componentsArray, from) => {
config.imports.push(`import {${Array.from(new Set(componentsArray)).join(",")}} from 'vuetify/labs/${from}'`);
});
}
}
if (dateOptions && addDatePicker) {
let warn = true;
if (typeof ctx.vuetify3_4 === "boolean") {
warn = false;
if (ctx.vuetify3_4) {
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) {
if (config.labComponents.size) {
if (config.labComponents.has("*"))
componentsEntry = `options.components = {${Array.from(config.components).join(",")},...labsComponents}`;
else
componentsEntry = `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) {
if (config.labComponents.has("*"))
componentsEntry = "options.components = {...labsComponents}";
else
componentsEntry = `options.components = {${Array.from(config.labComponents).join(",")}}`;
}
if (!ctx.i18n && localeMessages) {
const useLocales = Array.isArray(localeMessages) ? [.../* @__PURE__ */ 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 ? config.imports.join("\n") : "",
components: componentsEntry,
aliases: config.aliasEntries.length ? `options.aliases = {${config.aliasEntries.join(",")}}` : "",
directives: config.directives,
messages: config.messages
};
}
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) {
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) {
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
};
Object.entries(ctx.icons.unocssAdditionalIcons).forEach(([key, value]) => {
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 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.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 ?? {};
return `${buildImports()}
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()}
return options
}
`;
}
}
};
function buildAdapter() {
if (ctx.dateAdapter === "custom" || ctx.dateAdapter === "vuetify" && ctx.vuetify3_4 === true)
return "";
if (ctx.dateAdapter === "vuetify")
return "options.adapter = VuetifyDateAdapter";
const locale = ctx.vuetifyOptions.locale?.locale ?? "en";
if (ctx.dateAdapter === "date-fns")
return `options.adapter = new Adapter({ locale: ${locale} })`;
return "options.adapter = Adapter";
}
function buildImports() {
if (ctx.dateAdapter === "custom" || ctx.dateAdapter === "vuetify" && ctx.vuetify3_4 === true)
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 { ${ctx.vuetifyOptions.locale?.locale ?? "en"} } from 'date-fns/locale'`);
return imports.join("\n");
}
}
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 parseId2(id) {
id = id.replace(/^(virtual:nuxt:|virtual:)/, "");
return parseURL(decodeURIComponent(isAbsolute(id) ? pathToFileURL(id).href : id));
}
function parseId(id) {
const { search, pathname } = parseId2(id);
const query = parseQuery(search);
const urlProps = query.props ? destr(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.findIndex((plugin) => plugin.name === "vuetify:import") > -1)
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 configureVite(configKey, nuxt, ctx) {
nuxt.hook("vite:extend", ({ config }) => checkVuetifyPlugins(config));
nuxt.hook("vite:extendConfig", (viteInlineConfig) => {
viteInlineConfig.plugins = viteInlineConfig.plugins || [];
checkVuetifyPlugins(viteInlineConfig);
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;
}
if (!ctx.moduleOptions.disableModernSassCompiler) {
const [major, minor, patch] = ctx.viteVersion;
const enableModernSassCompiler = major > 5 || major === 5 && minor >= 4;
if (enableModernSassCompiler) {
const sassEmbedded = isPackageExists("sass-embedded");
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;
}
}
}
const autoImport = { labs: true };
const ignoreDirectives = ctx.moduleOptions.ignoreDirectives;
if (ignoreDirectives) {
autoImport.ignore = Array.isArray(ignoreDirectives) ? ignoreDirectives : [ignoreDirectives];
}
viteInlineConfig.plugins.push(vuetifyImportPlugin({ autoImport }));
if (typeof ctx.moduleOptions.styles !== "boolean")
viteInlineConfig.plugins.push(vuetifyStylesPlugin({ styles: ctx.moduleOptions.styles }, ctx.viteVersion, ctx.logger));
viteInlineConfig.plugins.push(vuetifyConfigurationPlugin(ctx));
viteInlineConfig.plugins.push(vuetifyIconsPlugin(ctx));
viteInlineConfig.plugins.push(vuetifyDateConfigurationPlugin(ctx));
if (ctx.ssrClientHints.enabled)
viteInlineConfig.plugins.push(vuetifySSRClientHintsPlugin(ctx));
});
}
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");
}
}
return `
import { defineNuxtPlugin } from '#imports'
import { isDev, vuetifyConfiguration } from 'virtual:vuetify-configuration'
import { createVuetify } from 'vuetify'
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)
nuxtApp.provide('vuetify', vuetify)
await nuxtApp.hooks.callHook('vuetify:ready', vuetify)
if (import.meta.client)
isDev && console.log('Vuetify 3 initialized', vuetify)
},
})
`;
}
});
}
function configureNuxt(configKey, nuxt, ctx) {
const {
styles,