vuetify-nuxt-module 1.0.0-beta.6 → 1.0.0-beta.7

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.
@@ -36,6 +36,9 @@ declare module 'virtual:vuetify-ssr-client-hints-configuration' {
36
36
  defaultTheme: string
37
37
  themeNames: string[]
38
38
  cookieName: string
39
+ cookieDomain?: string
40
+ cookieSecure?: boolean
41
+ cookieSameSite: 'lax' | 'strict' | 'none'
39
42
  darkThemeName: string
40
43
  lightThemeName: string
41
44
  useBrowserThemeOnly: boolean
package/dist/module.d.mts CHANGED
@@ -362,9 +362,43 @@ interface MOptions {
362
362
  /**
363
363
  * The name for the cookie.
364
364
  *
365
+ * @deprecated Use `cookie.name` instead.
365
366
  * @default 'color-scheme'
366
367
  */
367
368
  cookieName?: string;
369
+ /**
370
+ * Cookie attributes for the color scheme cookie.
371
+ */
372
+ cookie?: {
373
+ /**
374
+ * The name for the cookie.
375
+ *
376
+ * @default 'color-scheme'
377
+ */
378
+ name?: string;
379
+ /**
380
+ * The domain for the color scheme cookie.
381
+ *
382
+ * Useful to share the cookie across subdomains, e.g. `.example.com`.
383
+ *
384
+ * @default undefined
385
+ */
386
+ domain?: string;
387
+ /**
388
+ * Mark the cookie as `Secure`.
389
+ *
390
+ * Forced to `true` when `sameSite` is `'none'`.
391
+ *
392
+ * @default undefined
393
+ */
394
+ secure?: boolean;
395
+ /**
396
+ * The `SameSite` attribute for the cookie.
397
+ *
398
+ * @default 'lax'
399
+ */
400
+ sameSite?: 'lax' | 'strict' | 'none';
401
+ };
368
402
  /**
369
403
  * The name for the dark theme.
370
404
  *
@@ -459,6 +493,9 @@ interface SSRClientHintsConfiguration {
459
493
  defaultTheme: string;
460
494
  themeNames: string[];
461
495
  cookieName: string;
496
+ cookieDomain?: string;
497
+ cookieSecure?: boolean;
498
+ cookieSameSite: 'lax' | 'strict' | 'none';
462
499
  darkThemeName: string;
463
500
  lightThemeName: string;
464
501
  };
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3.15.0"
6
6
  },
7
- "version": "1.0.0-beta.6",
7
+ "version": "1.0.0-beta.7",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -1,14 +1,14 @@
1
- import { addPluginTemplate, resolvePath, addTemplate, extendWebpackConfig, isNuxtMajorVersion, addImports, addPlugin, addVitePlugin, useLogger, defineNuxtModule, getNuxtVersion, hasNuxtModule, createResolver } from '@nuxt/kit';
2
- import { isPackageExists, getPackageInfo } from 'local-pkg';
1
+ import { existsSync, statSync, readFileSync } from 'node:fs';
2
+ import { pathToFileURL, fileURLToPath } from 'node:url';
3
+ import { addPluginTemplate, resolvePath, addTemplate, extendWebpackConfig, isNuxtMajorVersion, addImports, addPlugin, addVitePlugin, useLogger, defineNuxtModule, getNuxtVersion, findPath, hasNuxtModule, createResolver } from '@nuxt/kit';
4
+ import { isAbsolute, resolve, dirname, relative } from 'pathe';
3
5
  import semver from 'semver';
4
6
  import { createFilter, version as version$1 } from 'vite';
5
7
  import defu from 'defu';
6
8
  import { transformAssetUrls } from 'vite-plugin-vuetify';
7
- import { existsSync, statSync } from 'node:fs';
8
- import { isAbsolute, resolve, dirname, relative } from 'pathe';
9
- import { generateImports, resolveVuetifyBase, isObject } from '@vuetify/loader-shared';
10
9
  import Styles from '@vuetify/unplugin-styles/vite';
11
- import { pathToFileURL } from 'node:url';
10
+ import { isPackageExists } from 'local-pkg';
11
+ import { generateImports } from '@vuetify/loader-shared';
12
12
  import destr from 'destr';
13
13
  import { parseQuery, parseURL } from 'ufo';
14
14
  import { readFile } from 'node:fs/promises';
@@ -16,7 +16,7 @@ import { debounce } from 'perfect-debounce';
16
16
  import process from 'node:process';
17
17
  import { createConfigLoader } from 'unconfig';
18
18
 
19
- const version = "1.0.0-beta.6";
19
+ const version = "1.0.0-beta.7";
20
20
 
21
21
  const VIRTUAL_VUETIFY_CONFIGURATION = "virtual:vuetify-configuration";
22
22
  const RESOLVED_VIRTUAL_VUETIFY_CONFIGURATION = `\0${VIRTUAL_VUETIFY_CONFIGURATION}`;
@@ -905,7 +905,7 @@ function vuetifySSRClientHintsPlugin(ctx) {
905
905
  };
906
906
  }
907
907
 
908
- function detectDate() {
908
+ function detectDate(paths) {
909
909
  const result = [];
910
910
  for (const adapter of [
911
911
  "date-fns",
@@ -917,12 +917,15 @@ function detectDate() {
917
917
  "jalaali",
918
918
  "hijri"
919
919
  ]) {
920
- if (isPackageExists(`@date-io/${adapter}`)) {
920
+ if (isPackageExists(`@date-io/${adapter}`, { paths })) {
921
921
  result.push(adapter);
922
922
  }
923
923
  }
924
924
  return result;
925
925
  }
926
+ function multipleDateAdaptersError(adapters) {
927
+ return `Multiple date adapters found: ${adapters.map((adapter) => `@date-io/${adapter}`).join(", ")}, please specify the adapter to use in the "vuetifyOptions.date.adapter" option.`;
928
+ }
926
929
  function cleanupBlueprint(vuetifyOptions) {
927
930
  const blueprint = vuetifyOptions.blueprint;
928
931
  if (blueprint) {
@@ -945,12 +948,10 @@ function checkVuetifyPlugins(config) {
945
948
  throw new Error("Remove vite-plugin-vuetify plugin from Vite Plugins entry in Nuxt config file!");
946
949
  }
947
950
  }
948
- function resolveVuetifyComponents(resolver) {
949
- const vuetifyBase = resolveVuetifyBase();
951
+ function resolveVuetifyComponents(resolver, vuetifyBase) {
950
952
  const componentsPromise = importMapResolver();
951
953
  const labComponentsPromise = importMapLabResolver();
952
954
  return {
953
- vuetifyBase,
954
955
  componentsPromise,
955
956
  labComponentsPromise
956
957
  };
@@ -973,7 +974,7 @@ function configureVite(configKey, nuxt, ctx) {
973
974
  if (!ctx.moduleOptions.disableModernSassCompiler) {
974
975
  const enableModernSassCompiler = semver.gte(ctx.viteVersion, "5.4.0") && semver.lt(ctx.viteVersion, "7.0.0-0");
975
976
  if (enableModernSassCompiler) {
976
- const sassEmbedded = isPackageExists("sass-embedded");
977
+ const sassEmbedded = isPackageExists("sass-embedded", { paths: ctx.resolvePaths });
977
978
  if (sassEmbedded) {
978
979
  viteInlineConfig.css ??= {};
979
980
  viteInlineConfig.css.preprocessorOptions ??= {};
@@ -1020,7 +1021,7 @@ function configureVite(configKey, nuxt, ctx) {
1020
1021
  const stylesOption = ctx.moduleOptions.styles;
1021
1022
  if (stylesOption === "none") {
1022
1023
  viteInlineConfig.plugins.push(Styles({ styles: "none" }));
1023
- } else if (isObject(stylesOption) && "configFile" in stylesOption) {
1024
+ } else if (typeof stylesOption === "object" && stylesOption !== null && "configFile" in stylesOption) {
1024
1025
  if (!ctx.stylesConfigFile) {
1025
1026
  throw new Error("vuetify-nuxt-module: styles.configFile could not be resolved");
1026
1027
  }
@@ -1067,7 +1068,8 @@ const disabledResolvedIcons = Object.freeze({
1067
1068
  local: [],
1068
1069
  svg: {}
1069
1070
  });
1070
- function prepareIcons(unocssPresent, logger, vuetifyOptions) {
1071
+ function prepareIcons(unocssPresent, logger, vuetifyOptions, paths) {
1072
+ const iconPackageExists = (name) => isPackageExists(name, { paths });
1071
1073
  if (vuetifyOptions.icons === false) {
1072
1074
  return disabledResolvedIcons;
1073
1075
  }
@@ -1111,7 +1113,7 @@ function prepareIcons(unocssPresent, logger, vuetifyOptions) {
1111
1113
  }
1112
1114
  resolvedIcons.imports.push(`import {${name === defaultSet ? "aliases," : ""}${name}} from 'vuetify/iconsets/${name}'`);
1113
1115
  resolvedIcons.sets.push(name);
1114
- if (isPackageExists(iconsPackageNames[name].name)) {
1116
+ if (iconPackageExists(iconsPackageNames[name].name)) {
1115
1117
  resolvedIcons.local.push(iconsPackageNames[name].css);
1116
1118
  } else {
1117
1119
  resolvedIcons.cdn.push([name, cdn ?? iconsCDN[name]]);
@@ -1130,18 +1132,18 @@ function prepareIcons(unocssPresent, logger, vuetifyOptions) {
1130
1132
  if (!faSvg) {
1131
1133
  faSvg = {};
1132
1134
  }
1133
- let faSvgExists = isPackageExists("@fortawesome/fontawesome-svg-core");
1135
+ let faSvgExists = iconPackageExists("@fortawesome/fontawesome-svg-core");
1134
1136
  if (!faSvgExists) {
1135
1137
  logger.warn("Missing @fortawesome/fontawesome-svg-core dependency, install it!");
1136
1138
  }
1137
- faSvgExists = isPackageExists("@fortawesome/vue-fontawesome");
1139
+ faSvgExists = iconPackageExists("@fortawesome/vue-fontawesome");
1138
1140
  if (faSvgExists) {
1139
1141
  if (!faSvg.libraries?.length) {
1140
1142
  faSvg.libraries = [[false, "fas", "@fortawesome/free-solid-svg-icons"]];
1141
1143
  }
1142
1144
  for (const p in faSvg.libraries) {
1143
1145
  const [_defaultExport, _name, library] = faSvg.libraries[p];
1144
- if (!isPackageExists(library)) {
1146
+ if (!iconPackageExists(library)) {
1145
1147
  faSvgExists = false;
1146
1148
  logger.warn(`Missing library ${library} dependency, install it!`);
1147
1149
  }
@@ -1168,7 +1170,7 @@ function prepareIcons(unocssPresent, logger, vuetifyOptions) {
1168
1170
  if (!mdiSvg) {
1169
1171
  mdiSvg = {};
1170
1172
  }
1171
- const mdiSvgExists = isPackageExists("@mdi/js");
1173
+ const mdiSvgExists = iconPackageExists("@mdi/js");
1172
1174
  if (mdiSvgExists) {
1173
1175
  resolvedIcons.svg.mdi = true;
1174
1176
  resolvedIcons.aliasesImportPresent ||= defaultSet === "mdi-svg";
@@ -1354,6 +1356,18 @@ const disabledClientHints = Object.freeze({
1354
1356
  prefersColorScheme: false,
1355
1357
  prefersReducedMotion: false
1356
1358
  });
1359
+ function resolveColorSchemeCookie(options, logger) {
1360
+ if (options.cookieName !== void 0) {
1361
+ logger.warn("[vuetify-nuxt-module] `prefersColorSchemeOptions.cookieName` is deprecated, use `prefersColorSchemeOptions.cookie.name` instead.");
1362
+ }
1363
+ const cookieSameSite = options.cookie?.sameSite ?? "lax";
1364
+ return {
1365
+ cookieName: options.cookie?.name ?? options.cookieName ?? "color-scheme",
1366
+ cookieDomain: options.cookie?.domain,
1367
+ cookieSecure: cookieSameSite === "none" ? true : options.cookie?.secure,
1368
+ cookieSameSite
1369
+ };
1370
+ }
1357
1371
  function prepareSSRClientHints(baseUrl, ctx) {
1358
1372
  if (!ctx.isSSR || ctx.isNuxtGenerate) {
1359
1373
  return disabledClientHints;
@@ -1394,14 +1408,15 @@ function prepareSSRClientHints(baseUrl, ctx) {
1394
1408
  if (darkThemeName === lightThemeName) {
1395
1409
  throw new Error("Vuetify dark theme and light theme are the same, change darkThemeName or lightThemeName!");
1396
1410
  }
1411
+ const pcsOptions = ssrClientHintsConfiguration.prefersColorSchemeOptions;
1397
1412
  clientHints.prefersColorSchemeOptions = {
1398
1413
  baseUrl,
1399
1414
  defaultTheme,
1400
1415
  themeNames: Array.from(Object.keys(themes)),
1401
- cookieName: ssrClientHintsConfiguration.prefersColorSchemeOptions?.cookieName ?? "color-scheme",
1416
+ ...resolveColorSchemeCookie(pcsOptions, ctx.logger),
1402
1417
  darkThemeName,
1403
1418
  lightThemeName,
1404
- useBrowserThemeOnly: ssrClientHintsConfiguration.prefersColorSchemeOptions?.useBrowserThemeOnly ?? false
1419
+ useBrowserThemeOnly: pcsOptions?.useBrowserThemeOnly ?? false
1405
1420
  };
1406
1421
  }
1407
1422
  return clientHints;
@@ -1416,7 +1431,7 @@ async function load(options, nuxt, ctx) {
1416
1431
  const {
1417
1432
  componentsPromise,
1418
1433
  labComponentsPromise
1419
- } = resolveVuetifyComponents(ctx.resolver);
1434
+ } = resolveVuetifyComponents(ctx.resolver, ctx.vuetifyBase);
1420
1435
  ctx.componentsPromise = componentsPromise;
1421
1436
  ctx.labComponentsPromise = labComponentsPromise;
1422
1437
  }
@@ -1432,9 +1447,9 @@ async function load(options, nuxt, ctx) {
1432
1447
  const dateOptions = vuetifyOptions.date;
1433
1448
  if (dateOptions) {
1434
1449
  const adapter = dateOptions.adapter;
1435
- const date = detectDate();
1450
+ const date = detectDate(ctx.resolvePaths);
1436
1451
  if (!adapter && date.length > 1) {
1437
- 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.`);
1452
+ throw new Error(multipleDateAdaptersError(date));
1438
1453
  }
1439
1454
  if (adapter) {
1440
1455
  if (adapter === "vuetify" || adapter === "custom") {
@@ -1461,7 +1476,7 @@ async function load(options, nuxt, ctx) {
1461
1476
  ctx.enableRules = ctx.moduleOptions.enableRules;
1462
1477
  ctx.rulesConfiguration = ctx.moduleOptions.rulesConfiguration;
1463
1478
  ctx.vuetifyFilesToWatch = Array.from(vuetifyConfigurationFilesToWatch);
1464
- ctx.icons = prepareIcons(ctx.unocss, ctx.logger, vuetifyAppOptions);
1479
+ ctx.icons = prepareIcons(ctx.unocss, ctx.logger, vuetifyAppOptions, ctx.resolvePaths);
1465
1480
  ctx.ssrClientHints = prepareSSRClientHints(nuxt.options.app.baseURL ?? "/", ctx);
1466
1481
  if (ctx.icons.enabled) {
1467
1482
  if (ctx.icons.local) {
@@ -1561,8 +1576,23 @@ const module$1 = defineNuxtModule({
1561
1576
  if (isNuxtMajorVersion(2, nuxt)) {
1562
1577
  logger.error(`Cannot support nuxt version: ${getNuxtVersion(nuxt)}`);
1563
1578
  }
1564
- const vuetifyPkg = await getPackageInfo("vuetify");
1565
- const currentVersion = vuetifyPkg?.version;
1579
+ let vuetifyPkgPath = await findPath("vuetify/package.json");
1580
+ if (!vuetifyPkgPath) {
1581
+ const metaResolve = import.meta.resolve;
1582
+ if (metaResolve) {
1583
+ try {
1584
+ vuetifyPkgPath = fileURLToPath(metaResolve("vuetify/package.json"));
1585
+ } catch {
1586
+ }
1587
+ }
1588
+ }
1589
+ if (!vuetifyPkgPath) {
1590
+ throw new Error(
1591
+ '[vuetify-nuxt-module] Could not resolve "vuetify". Please add it as a dependency of your project (e.g. `npm add vuetify`).'
1592
+ );
1593
+ }
1594
+ const vuetifyBase = dirname(vuetifyPkgPath);
1595
+ const currentVersion = JSON.parse(readFileSync(vuetifyPkgPath, "utf8")).version;
1566
1596
  const vuetifyGte = (version2) => !!currentVersion && semver.gte(currentVersion, version2);
1567
1597
  const viteVersion = version$1;
1568
1598
  const ctx = {
@@ -1582,6 +1612,8 @@ const module$1 = defineNuxtModule({
1582
1612
  labComponentsPromise: void 0,
1583
1613
  vuetifyGte,
1584
1614
  vuetifyVersion: currentVersion || "0.0.0",
1615
+ vuetifyBase,
1616
+ resolvePaths: [nuxt.options.rootDir, ...nuxt.options.modulesDir],
1585
1617
  viteVersion
1586
1618
  };
1587
1619
  await load(options, nuxt, ctx);
@@ -119,12 +119,21 @@ function useSSRClientHints() {
119
119
  const {
120
120
  baseUrl,
121
121
  cookieName,
122
+ cookieDomain,
123
+ cookieSecure,
124
+ cookieSameSite,
122
125
  defaultTheme
123
126
  } = ssrClientHintsConfiguration.prefersColorSchemeOptions;
124
127
  const cookieNamePrefix = `${cookieName}=`;
125
128
  initial.value.colorSchemeFromCookie = document.cookie?.split(";")?.find((c) => c.trim().startsWith(cookieNamePrefix))?.split("=")[1] ?? defaultTheme;
126
129
  const date = /* @__PURE__ */ new Date();
127
130
  const expires = new Date(date.setDate(date.getDate() + 365));
128
- initial.value.colorSchemeCookie = `${cookieName}=${initial.value.colorSchemeFromCookie}; Path=${baseUrl}; Expires=${expires.toUTCString()}; SameSite=Lax`;
131
+ initial.value.colorSchemeCookie = `${cookieName}=${initial.value.colorSchemeFromCookie}; Path=${baseUrl}; Expires=${expires.toUTCString()}; SameSite=${cookieSameSite[0].toUpperCase()}${cookieSameSite.slice(1)}`;
132
+ if (cookieDomain) {
133
+ initial.value.colorSchemeCookie += `; Domain=${cookieDomain}`;
134
+ }
135
+ if (cookieSecure) {
136
+ initial.value.colorSchemeCookie += "; Secure";
137
+ }
129
138
  return initial;
130
139
  }
@@ -273,15 +273,27 @@ function writeThemeCookie(clientHintsRequest, ssrClientHintsConfiguration2) {
273
273
  const cookieName = ssrClientHintsConfiguration2.prefersColorSchemeOptions.cookieName;
274
274
  const themeName = clientHintsRequest.colorSchemeFromCookie ?? ssrClientHintsConfiguration2.prefersColorSchemeOptions.defaultTheme;
275
275
  const path = ssrClientHintsConfiguration2.prefersColorSchemeOptions.baseUrl;
276
+ const domain = ssrClientHintsConfiguration2.prefersColorSchemeOptions.cookieDomain;
277
+ const secure = ssrClientHintsConfiguration2.prefersColorSchemeOptions.cookieSecure;
278
+ const sameSite = ssrClientHintsConfiguration2.prefersColorSchemeOptions.cookieSameSite;
276
279
  const date = /* @__PURE__ */ new Date();
277
280
  const expires = new Date(date.setDate(date.getDate() + 365));
278
281
  if (!clientHintsRequest.firstRequest || !ssrClientHintsConfiguration2.reloadOnFirstRequest) {
279
282
  useCookie(cookieName, {
280
283
  path,
284
+ domain,
281
285
  expires,
282
- sameSite: "lax"
286
+ sameSite,
287
+ secure
283
288
  }).value = themeName;
284
289
  }
285
- return `${cookieName}=${themeName}; Path=${path}; Expires=${expires.toUTCString()}; SameSite=Lax`;
290
+ let cookie = `${cookieName}=${themeName}; Path=${path}; Expires=${expires.toUTCString()}; SameSite=${sameSite[0].toUpperCase()}${sameSite.slice(1)}`;
291
+ if (domain) {
292
+ cookie += `; Domain=${domain}`;
293
+ }
294
+ if (secure) {
295
+ cookie += "; Secure";
296
+ }
297
+ return cookie;
286
298
  }
287
299
  export default plugin;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vuetify-nuxt-module",
3
3
  "type": "module",
4
- "version": "1.0.0-beta.6",
4
+ "version": "1.0.0-beta.7",
5
5
  "description": "Zero-Config Nuxt Module for Vuetify",
6
6
  "author": "userquin <userquin@gmail.com>",
7
7
  "license": "MIT",