vuetify-nuxt-module 1.0.0-beta.10 → 1.0.0-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,25 +26,19 @@
26
26
 
27
27
  ## 🚀 Features
28
28
 
29
- - 📖 [**Documentation & guides**](https://nuxt.vuetifyjs.com/)
29
+ > 📖 Full [**documentation & guides**](https://nuxt.vuetifyjs.com/)
30
+
30
31
  - 👌 **Zero-Config**: sensible built-in default [Vuetify](https://vuetifyjs.com/) configuration for common use cases
31
- - 🔌 **Extensible**: expose the ability to customize the Vuetify configuration via [Nuxt Runtime Hooks](https://nuxt.com/docs/guide/going-further/hooks#usage-with-plugins)
32
- - **Fully Tree Shakable**: by default, only the needed Vuetify components are imported
33
- - 🛠️ **Versatile**: custom Vuetify [directives](https://vuetifyjs.com/en/getting-started/installation/#manual-steps) and [labs components](https://vuetifyjs.com/en/labs/introduction/) registration
34
- - **Configurable Styles**: configure your variables using [Vuetify SASS Variables](https://vuetifyjs.com/en/features/sass-variables/)
35
- - 💥 **SSR**: automatic SSR detection and configuration including [HTTP Client hints](https://developer.mozilla.org/en-US/docs/Web/HTTP/Client_hints)
36
- - 🔩 **Nuxt Layers and Module Hooks**: load your Vuetify configuration using [Nuxt Layers](https://nuxt.com/docs/getting-started/layers#layers) or using a custom module via `vuetify:registerModule` [Nuxt Module Hook](https://nuxt.com/docs/guide/going-further/hooks#nuxt-hooks-build-time)
37
- - 📥 **Vuetify Configuration File**: configure your Vuetify options using a custom `vuetify.config` file, no dev server restart needed
38
- - 🔥 **Pure CSS Icons**: no more font/js icons, use the new `unocss-mdi` icon set or build your own with UnoCSS Preset Icons
39
- - 😃 **Icon Fonts**: configure the [icon font](https://vuetifyjs.com/en/features/icon-fonts/) you want to use, the module will automatically import it for you using CDN or local dependencies
40
- - 🎭 **SVG Icons**: ready to use [@mdi/js](https://www.npmjs.com/package/@mdi/js) and [@fortawesome/vue-fontawesome](https://www.npmjs.com/package/@fortawesome/vue-fontawesome) SVG icons packs
41
- - 📦 **Multiple Icon Sets**: register [multiple icon sets](https://vuetifyjs.com/en/features/icon-fonts/#multiple-icon-sets)
42
- - 🌍 **I18n Ready**: install [@nuxtjs/i18n](https://i18n.nuxtjs.org/) Nuxt module, and you're ready to use Vuetify [internationalization](https://vuetifyjs.com/en/features/internationalization/) features
43
- - 📆 **Date Components**: use Vuetify components [that require date functionality](https://vuetifyjs.com/en/features/dates/) installing and configuring one of the [@date-io](https://github.com/dmtrKovalenko/date-io#projects) adapters
44
- - 💬 **Auto-Import Vuetify Locale Messages**: add [Vuetify Locale Messages](https://vuetifyjs.com/en/features/internationalization/#getting-started) adding just the locales you want to use, no more imports needed
45
- - ⚙️ **Auto-Import Vuetify Composables**: you don't need to import Vuetify composables manually, they are automatically imported for you
46
- - 🎨 **Vuetify Blueprints**: use [Vuetify Blueprints](https://vuetifyjs.com/en/features/blueprints/) to quickly scaffold components
47
- - 👀 **Nuxt DevTools**: ready to inspect your Vuetify styles with the [Nuxt DevTools](https://github.com/nuxt/devtools) inspector
32
+ - **Fully Tree Shakable**: by default, only the Vuetify components you use are imported
33
+ - 🪄 **Auto-Import**: Vuetify components and composables are auto-imported no manual imports needed
34
+ - 🔌 **Extensible**: customize the Vuetify configuration via [Nuxt Runtime Hooks](https://nuxt.com/docs/guide/going-further/hooks#usage-with-plugins), [Nuxt Layers](https://nuxt.com/docs/getting-started/layers#layers), the `vuetify:registerModule` [module hook](https://nuxt.com/docs/guide/going-further/hooks#nuxt-hooks-build-time), or a dedicated `vuetify.config` file
35
+ - 💥 **SSR**: automatic SSR detection and configuration, including [HTTP Client Hints](https://developer.mozilla.org/en-US/docs/Web/HTTP/Client_hints)
36
+ - **Configurable Styles**: configure your variables using [Vuetify SASS Variables](https://vuetifyjs.com/en/features/sass-variables/)
37
+ - 🛠️ **Directives & Labs**: optional [directives](https://vuetifyjs.com/en/getting-started/installation/#manual-steps) and [labs components](https://vuetifyjs.com/en/labs/introduction/) registration
38
+ - 🎭 **Icons**: pure-CSS icons (UnoCSS), [icon fonts](https://vuetifyjs.com/en/features/icon-fonts/) (CDN or local), SVG packs ([@mdi/js](https://www.npmjs.com/package/@mdi/js), [FontAwesome](https://www.npmjs.com/package/@fortawesome/vue-fontawesome)), and [multiple icon sets](https://vuetifyjs.com/en/features/icon-fonts/#multiple-icon-sets)
39
+ - 🌍 **I18n**: integrate [@nuxtjs/i18n](https://i18n.nuxtjs.org/) for Vuetify [internationalization](https://vuetifyjs.com/en/features/internationalization/), with auto-imported Vuetify locale messages
40
+ - 📆 **Date Components**: use Vuetify [date components](https://vuetifyjs.com/en/features/dates/) via the [@date-io](https://github.com/dmtrKovalenko/date-io#projects) adapters
41
+ - 🎨 **Blueprints**: scaffold quickly with [Vuetify Blueprints](https://vuetifyjs.com/en/features/blueprints/)
48
42
  - 🦾 **Type Strong**: written in [TypeScript](https://www.typescriptlang.org/)
49
43
 
50
44
  ## 📦 Install
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.10",
7
+ "version": "1.0.0-beta.11",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { existsSync, statSync, readFileSync } from 'node:fs';
2
2
  import { pathToFileURL, fileURLToPath } from 'node:url';
3
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';
4
+ import { isAbsolute, resolve, dirname } from 'pathe';
5
5
  import semver from 'semver';
6
6
  import { createFilter, version as version$1 } from 'vite';
7
7
  import defu from 'defu';
@@ -10,11 +10,10 @@ import Styles from '@vuetify/unplugin-styles/vite';
10
10
  import { isPackageExists } from 'local-pkg';
11
11
  import { parseQuery, parseURL } from 'ufo';
12
12
  import { readFile } from 'node:fs/promises';
13
- import { debounce } from 'perfect-debounce';
14
13
  import process from 'node:process';
15
14
  import { createConfigLoader } from 'unconfig';
16
15
 
17
- const version = "1.0.0-beta.10";
16
+ const version = "1.0.0-beta.11";
18
17
 
19
18
  const VIRTUAL_VUETIFY_CONFIGURATION = "virtual:vuetify-configuration";
20
19
  const RESOLVED_VIRTUAL_VUETIFY_CONFIGURATION = `\0${VIRTUAL_VUETIFY_CONFIGURATION}`;
@@ -354,6 +353,11 @@ function vuetifyConfigurationPlugin(ctx) {
354
353
  },
355
354
  async load(id) {
356
355
  if (id === RESOLVED_VIRTUAL_VUETIFY_CONFIGURATION) {
356
+ if (ctx.isDev && ctx.canHmrConfig) {
357
+ for (const file of ctx.vuetifyFilesToWatch) {
358
+ this.addWatchFile(file);
359
+ }
360
+ }
357
361
  const {
358
362
  directives: _directives,
359
363
  date: _date,
@@ -375,7 +379,12 @@ function vuetifyConfigurationPlugin(ctx) {
375
379
  }
376
380
  const result = await buildConfiguration(ctx);
377
381
  const deepCopy = result.messages.length > 0;
378
- return `${result.imports}
382
+ let configDepImports = "";
383
+ if (ctx.isDev && ctx.canHmrConfig && this.environment?.name === "ssr") {
384
+ configDepImports = ctx.vuetifyFilesToWatch.map((file) => `import ${JSON.stringify(file)}`).join("\n");
385
+ }
386
+ return `${configDepImports}
387
+ ${result.imports}
379
388
 
380
389
  export const isDev = ${ctx.isDev}
381
390
  export function vuetifyConfiguration() {
@@ -669,6 +678,11 @@ function vuetifyDateConfigurationPlugin(ctx) {
669
678
  },
670
679
  async load(id) {
671
680
  if (id === RESOLVED_VIRTUAL_VUETIFY_DATE_CONFIGURATION) {
681
+ if (ctx.isDev && ctx.canHmrConfig) {
682
+ for (const file of ctx.vuetifyFilesToWatch) {
683
+ this.addWatchFile(file);
684
+ }
685
+ }
672
686
  if (!ctx.dateAdapter) {
673
687
  return `
674
688
  export const enabled = false
@@ -741,6 +755,11 @@ function vuetifyIconsPlugin(ctx) {
741
755
  },
742
756
  async load(id) {
743
757
  if (id === RESOLVED_VIRTUAL_VUETIFY_ICONS_CONFIGURATION) {
758
+ if (ctx.isDev && ctx.canHmrConfig) {
759
+ for (const file of ctx.vuetifyFilesToWatch) {
760
+ this.addWatchFile(file);
761
+ }
762
+ }
744
763
  const {
745
764
  enabled,
746
765
  unocss,
@@ -1399,14 +1418,8 @@ async function mergeVuetifyModules(options, nuxt) {
1399
1418
  options.vuetifyOptions
1400
1419
  );
1401
1420
  if (nuxt.options.dev && resolvedOptions.sources.length > 0) {
1402
- if (nuxt.options.ssr) {
1403
- for (const s of resolvedOptions.sources) {
1404
- nuxt.options.watch.push(s.replace(/\\/g, "/"));
1405
- }
1406
- } else {
1407
- for (const s of resolvedOptions.sources) {
1408
- vuetifyConfigurationFilesToWatch.add(s.replace(/\\/g, "/"));
1409
- }
1421
+ for (const s of resolvedOptions.sources) {
1422
+ vuetifyConfigurationFilesToWatch.add(s.replace(/\\/g, "/"));
1410
1423
  }
1411
1424
  }
1412
1425
  moduleOptions.unshift({
@@ -1523,7 +1536,7 @@ function prepareSSRClientHints(baseUrl, ctx) {
1523
1536
  return clientHints;
1524
1537
  }
1525
1538
 
1526
- async function load(options, nuxt, ctx) {
1539
+ async function load(options, nuxt, ctx, reload = false) {
1527
1540
  const {
1528
1541
  configuration,
1529
1542
  vuetifyConfigurationFilesToWatch
@@ -1568,9 +1581,11 @@ async function load(options, nuxt, ctx) {
1568
1581
  ctx.dateAdapter = date[0];
1569
1582
  }
1570
1583
  }
1571
- const oldIcons = ctx.icons;
1572
- if (oldIcons && oldIcons.cdn?.length && nuxt.options.app.head.link) {
1573
- nuxt.options.app.head.link = nuxt.options.app.head.link.filter((link) => !link.key || !oldIcons.cdn.some(([key]) => link.key === key));
1584
+ if (!reload) {
1585
+ const oldIcons = ctx.icons;
1586
+ if (oldIcons && oldIcons.cdn?.length && nuxt.options.app.head.link) {
1587
+ nuxt.options.app.head.link = nuxt.options.app.head.link.filter((link) => !link.key || !oldIcons.cdn.some(([key]) => link.key === key));
1588
+ }
1574
1589
  }
1575
1590
  ctx.moduleOptions = configuration.moduleOptions;
1576
1591
  ctx.vuetifyOptions = configuration.vuetifyOptions;
@@ -1582,7 +1597,7 @@ async function load(options, nuxt, ctx) {
1582
1597
  if (ctx.isSSR && !ctx.ssrClientHints.prefersColorScheme && ctx.vuetifyOptions.theme && typeof ctx.vuetifyOptions.theme === "object" && ctx.vuetifyOptions.theme.defaultTheme === "system") {
1583
1598
  ctx.logger.warn('`theme.defaultTheme: "system"` cannot be resolved during SSR/SSG: the server has no access to the OS color-scheme preference, so the first paint defaults to light and may flash on dark systems. Set explicit dark/light themes and enable `moduleOptions.ssrClientHints.prefersColorScheme` (optionally `prefersColorSchemeOptions.useBrowserThemeOnly`). See the SSR guide.');
1584
1599
  }
1585
- if (ctx.icons.enabled) {
1600
+ if (!reload && ctx.icons.enabled) {
1586
1601
  if (ctx.icons.local) {
1587
1602
  for (const css of ctx.icons.local) {
1588
1603
  nuxt.options.css.push(css);
@@ -1602,43 +1617,67 @@ async function load(options, nuxt, ctx) {
1602
1617
  }
1603
1618
  }
1604
1619
  }
1605
- function registerWatcher(options, nuxt, ctx) {
1606
- if (nuxt.options.dev) {
1607
- let pageReload;
1608
- nuxt.hooks.hook("builder:watch", (_event, path) => {
1609
- path = relative(nuxt.options.srcDir, resolve(nuxt.options.srcDir, path));
1610
- if (!pageReload && ctx.vuetifyFilesToWatch.includes(path)) {
1611
- return nuxt.callHook("restart");
1620
+ function bindInvalidator(graph) {
1621
+ return () => {
1622
+ for (const id of RESOLVED_VIRTUAL_MODULES) {
1623
+ const mod = graph.getModuleById(id);
1624
+ if (mod) {
1625
+ graph.invalidateModule(mod);
1612
1626
  }
1613
- });
1614
- nuxt.hook("vite:serverCreated", (server, { isClient }) => {
1615
- if (!server.ws || !isClient) {
1616
- return;
1617
- }
1618
- pageReload = debounce(async () => {
1619
- const modules = [];
1620
- for (const v of RESOLVED_VIRTUAL_MODULES) {
1621
- const module = server.moduleGraph.getModuleById(v);
1622
- if (module) {
1623
- modules.push(module);
1624
- }
1625
- }
1626
- await load(options, nuxt, ctx);
1627
- if (modules.length > 0) {
1628
- await Promise.all(modules.map((m) => server.reloadModule(m)));
1629
- }
1630
- }, 50, { trailing: false });
1631
- });
1632
- addVitePlugin({
1633
- name: "vuetify:configuration:watch",
1634
- enforce: "pre",
1635
- handleHotUpdate({ file }) {
1636
- if (pageReload && ctx.vuetifyFilesToWatch.includes(file)) {
1637
- return pageReload();
1638
- }
1627
+ }
1628
+ };
1629
+ }
1630
+ function registerWatcher(options, nuxt, ctx) {
1631
+ if (!nuxt.options.dev) {
1632
+ return;
1633
+ }
1634
+ if (!ctx.canHmrConfig) {
1635
+ for (const file of ctx.vuetifyFilesToWatch) {
1636
+ nuxt.options.watch.push(file);
1637
+ }
1638
+ return;
1639
+ }
1640
+ let clientServer;
1641
+ let invalidateSsrModules;
1642
+ nuxt.hook("vite:serverCreated", (server, { isClient }) => {
1643
+ if (!isClient) {
1644
+ invalidateSsrModules = bindInvalidator(server.moduleGraph);
1645
+ return;
1646
+ }
1647
+ if (!server.ws) {
1648
+ return;
1649
+ }
1650
+ clientServer = server;
1651
+ const ssrEnv = server.environments?.ssr;
1652
+ if (ssrEnv) {
1653
+ invalidateSsrModules ??= bindInvalidator(ssrEnv.moduleGraph);
1654
+ }
1655
+ server.watcher.add(ctx.vuetifyFilesToWatch);
1656
+ });
1657
+ async function reloadConfig() {
1658
+ await load(options, nuxt, ctx, true);
1659
+ invalidateSsrModules?.();
1660
+ clientServer?.ws.send({ type: "full-reload" });
1661
+ }
1662
+ addVitePlugin({
1663
+ name: "vuetify:configuration:watch",
1664
+ enforce: "pre",
1665
+ async handleHotUpdate({ file }) {
1666
+ if (clientServer && ctx.vuetifyFilesToWatch.includes(file)) {
1667
+ await reloadConfig();
1668
+ return [];
1639
1669
  }
1640
- });
1670
+ }
1671
+ });
1672
+ }
1673
+
1674
+ const MIN_NUXT_VERSION_FOR_SSR_CONFIG_HMR = "3.18.0";
1675
+ function supportsSsrConfigHmr(nuxtVersion) {
1676
+ const parsed = semver.parse(nuxtVersion) ?? semver.coerce(nuxtVersion);
1677
+ if (!parsed) {
1678
+ return false;
1641
1679
  }
1680
+ return semver.gte(parsed.version, MIN_NUXT_VERSION_FOR_SSR_CONFIG_HMR);
1642
1681
  }
1643
1682
 
1644
1683
  const CONFIG_KEY = "vuetify";
@@ -1687,6 +1726,7 @@ const module$1 = defineNuxtModule({
1687
1726
  moduleOptions: void 0,
1688
1727
  vuetifyOptions: void 0,
1689
1728
  vuetifyFilesToWatch: [],
1729
+ canHmrConfig: !nuxt.options.ssr || supportsSsrConfigHmr(getNuxtVersion(nuxt)),
1690
1730
  isSSR: nuxt.options.ssr,
1691
1731
  isDev: nuxt.options.dev,
1692
1732
  isNuxtGenerate: !!nuxt.options.nitro.static,
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.10",
4
+ "version": "1.0.0-beta.11",
5
5
  "description": "Zero-Config Nuxt Module for Vuetify",
6
6
  "author": "userquin <userquin@gmail.com>",
7
7
  "license": "MIT",
@@ -54,7 +54,7 @@
54
54
  "@nuxt/kit": "^4.3.1",
55
55
  "@vuetify/loader-shared": "^2.1.2",
56
56
  "@vuetify/unplugin-styles": "^1.0.0-beta.11",
57
- "defu": "^6.1.4",
57
+ "defu": "^6.1.7",
58
58
  "local-pkg": "^1.1.2",
59
59
  "pathe": "^2.0.3",
60
60
  "perfect-debounce": "^2.1.0",
@@ -93,7 +93,7 @@
93
93
  "rimraf": "^6.1.3",
94
94
  "sass": "^1.97.3",
95
95
  "typescript": "^5.9.3",
96
- "vite": "7.3.1",
96
+ "vite": "7.3.5",
97
97
  "vitest": "^4.0.18",
98
98
  "vue-tsc": "^3.2.5",
99
99
  "vuetify": "^4.0.1"