vuetify-nuxt4-module 1.2.0 → 1.2.2

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
@@ -3,27 +3,50 @@
3
3
  [![npm version](https://img.shields.io/npm/v/vuetify-nuxt4-module.svg)](https://npmjs.com/package/vuetify-nuxt4-module)
4
4
  [![npm downloads](https://img.shields.io/npm/dm/vuetify-nuxt4-module.svg?style=flat&colorA=020420&colorB=00DC82)](https://npm.chart.dev/vuetify-nuxt4-module)
5
5
  [![License](https://img.shields.io/npm/l/vuetify-nuxt4-module.svg)](https://npmjs.com/package/vuetify-nuxt4-module)
6
- [![CI](https://github.com/KHNexTech/Vuetify-Nuxt4-Module/actions/workflows/ci.yml/badge.svg)](https://github.com/KHNexTech/Vuetify-Nuxt4-Module/actions/workflows/ci.yml)
7
6
  [![Nuxt](https://img.shields.io/badge/Nuxt-020420?logo=nuxt.js)](https://nuxt.com)
8
7
 
9
- Zero-config Vuetify 3 module for Nuxt 4 with performance optimizations.
8
+ Zero-config Vuetify 3 module for Nuxt 4 with performance optimizations, SSR support, and full TypeScript integration.
10
9
 
11
10
  - [✨ Release Notes](/CHANGELOG.md)
11
+ - [📖 Documentation](#documentation)
12
12
 
13
13
  ## Features
14
14
 
15
15
  - ⚡ **Auto-import** - Automatic tree-shaking with vite-plugin-vuetify
16
- - 🎨 **Theme Persistence** - Cookie/localStorage/sessionStorage support
16
+ - 🎨 **Theme Persistence** - SSR-safe cookie/localStorage/sessionStorage support
17
+ - 🌍 **i18n Integration** - Seamless @nuxtjs/i18n support with vue-i18n adapter
17
18
  - 🔧 **Date Adapters** - Support for date-fns, dayjs, luxon, moment
18
- - 🎯 **Icon Sets** – MDI, FontAwesome, and SVG variants
19
- - 🌍 **Locale Support** – Multiple languages with RTL support
19
+ - 🎯 **Icon Sets** – MDI, FontAwesome, Material Design (font & SVG variants)
20
+ - 🌐 **Locale Support** – Multiple languages with RTL support
20
21
  - 🎭 **Blueprints** - Material Design MD1/MD2/MD3 presets
21
- - 🚀 **Performance** – Optimized chunking and tree-shaking
22
- - 🔌 **Hooks** – Extend Vuetify configuration via hooks
22
+ - 🚀 **Performance** – Optimized chunking, tree-shaking, no duplicate CSS
23
+ - 🔌 **Hooks** – Extend Vuetify configuration via lifecycle hooks
24
+ - 📦 **SSR Ready** – No hydration mismatches
25
+
26
+ ---
27
+
28
+ ## Table of Contents
29
+
30
+ - [Quick Setup](#quick-setup)
31
+ - [Configuration](#configuration)
32
+ - [Usage](#usage)
33
+ - [i18n Integration](#i18n-integration)
34
+ - [Icon Configuration](#icon-configuration)
35
+ - [Theme Persistence](#theme-persistence)
36
+ - [Date Adapters](#date-adapters)
37
+ - [Custom SASS Variables](#custom-sass-variables)
38
+ - [Hooks](#hooks)
39
+ - [Performance Tips](#performance-tips)
40
+ - [TypeScript](#typescript)
41
+ - [Troubleshooting](#troubleshooting)
42
+ - [Local Development](#local-development)
43
+
44
+ ---
23
45
 
24
46
  ## Quick Setup
25
47
 
26
- Install the module:
48
+ ### Installation
49
+
27
50
  ```bash
28
51
  # npm
29
52
  npm install vuetify-nuxt4-module vuetify vite-plugin-vuetify
@@ -35,61 +58,68 @@ pnpm add vuetify-nuxt4-module vuetify vite-plugin-vuetify
35
58
  yarn add vuetify-nuxt4-module vuetify vite-plugin-vuetify
36
59
  ```
37
60
 
38
- Add to your `nuxt.config.ts`:
61
+ ### Optional Dependencies
62
+
63
+ ```bash
64
+ # Icons (choose one)
65
+ npm install @mdi/font # MDI font icons
66
+ npm install @mdi/js # MDI SVG icons (tree-shakeable)
67
+
68
+ # i18n support
69
+ npm install @nuxtjs/i18n vue-i18n
70
+
71
+ # Date adapters (choose one if needed)
72
+ npm install @date-io/date-fns date-fns
73
+ npm install @date-io/dayjs dayjs
74
+ npm install @date-io/luxon luxon
75
+ npm install @date-io/moment moment
76
+ ```
77
+
78
+ ### Minimal Configuration
79
+
39
80
  ```typescript
81
+ // nuxt.config.ts
40
82
  export default defineNuxtConfig({
41
83
  modules: ['vuetify-nuxt4-module'],
42
-
43
- vuetify: {
44
- moduleOptions: {
45
- themePersistence: true,
46
- defaultTheme: 'light',
47
- },
48
-
49
- vuetifyOptions: {
50
- theme: {
51
- defaultTheme: 'light',
52
- themes: {
53
- light: {
54
- dark: false,
55
- colors: {
56
- primary: '#1976D2',
57
- secondary: '#424242',
58
- background: '#FFFFFF',
59
- },
60
- },
61
- dark: {
62
- dark: true,
63
- colors: {
64
- primary: '#2196F3',
65
- background: '#121212',
66
- },
67
- },
68
- },
69
- },
70
- },
71
- },
72
84
  })
73
-
74
85
  ```
75
86
 
87
+ That's it! Vuetify is now ready to use with sensible defaults.
88
+
89
+ ---
90
+
76
91
  ## Configuration
77
92
 
78
- ### Full Example
93
+ ### Full Configuration Example
94
+
79
95
  ```typescript
96
+ // nuxt.config.ts
80
97
  export default defineNuxtConfig({
81
- modules: ['vuetify-nuxt4-module'],
98
+ modules: [
99
+ '@nuxtjs/i18n', // Optional: for i18n integration
100
+ 'vuetify-nuxt4-module',
101
+ ],
82
102
 
83
103
  vuetify: {
104
+ // Vuetify instance options
84
105
  vuetifyOptions: {
85
106
  ssr: true,
86
- blueprint: 'md3', // 'md1' | 'md2' | 'md3'
87
- dateAdapter: 'vuetify', // 'vuetify' | 'date-fns' | 'dayjs' | 'luxon' | 'moment'
107
+ blueprint: 'md3', // 'md1' | 'md2' | 'md3'
108
+ dateAdapter: 'vuetify', // 'vuetify' | 'date-fns' | 'dayjs' | 'luxon' | 'moment'
88
109
 
89
110
  icons: {
90
- defaultSet: 'mdi', // 'mdi' | 'mdi-svg' | 'fa' | 'fa-svg'
111
+ defaultSet: 'mdi', // 'mdi' | 'mdi-svg' | 'fa' | 'fa-svg' | 'md'
91
112
  aliases: {
92
- // Custom icon aliases
113
+ // Custom aliases for font icons
114
+ },
115
+ svg: {
116
+ mdi: {
117
+ aliases: {
118
+ // Custom aliases for SVG icons (maps to @mdi/js exports)
119
+ account: 'mdiAccount',
120
+ home: 'mdiHome',
121
+ },
122
+ },
93
123
  },
94
124
  },
95
125
 
@@ -98,6 +128,7 @@ export default defineNuxtConfig({
98
128
  fallback: 'en',
99
129
  rtl: {
100
130
  ar: true,
131
+ he: true,
101
132
  },
102
133
  },
103
134
 
@@ -105,15 +136,26 @@ export default defineNuxtConfig({
105
136
  defaultTheme: 'light',
106
137
  themes: {
107
138
  light: {
139
+ dark: false,
108
140
  colors: {
109
- primary: '#6200EE',
110
- secondary: '#03DAC6',
141
+ primary: '#1976D2',
142
+ secondary: '#424242',
143
+ accent: '#82B1FF',
144
+ error: '#FF5252',
145
+ info: '#2196F3',
146
+ success: '#4CAF50',
147
+ warning: '#FFC107',
148
+ background: '#FFFFFF',
149
+ surface: '#FFFFFF',
111
150
  },
112
151
  },
113
152
  dark: {
153
+ dark: true,
114
154
  colors: {
115
- primary: '#BB86FC',
116
- secondary: '#03DAC6',
155
+ primary: '#2196F3',
156
+ secondary: '#424242',
157
+ background: '#121212',
158
+ surface: '#212121',
117
159
  },
118
160
  },
119
161
  },
@@ -126,27 +168,43 @@ export default defineNuxtConfig({
126
168
  },
127
169
  VCard: {
128
170
  elevation: 4,
171
+ rounded: 'lg',
172
+ },
173
+ VTextField: {
174
+ variant: 'outlined',
175
+ density: 'comfortable',
129
176
  },
130
177
  },
131
178
  },
132
179
 
133
180
  // Module options
134
- importComposables: true,
135
- prefixComposables: false, // Set true to prefix: useVTheme, useVDisplay, etc.
136
- transformAssetUrls: true,
137
- autoImport: true, // or { labs: true, ignore: [] }
138
- styles: true, // true | 'sass' | 'none' | { configFile: 'path/to/settings.scss' }
139
-
181
+ importComposables: true, // Auto-import Vuetify composables
182
+ prefixComposables: false, // Prefix with 'V': useVTheme, useVDisplay
183
+ transformAssetUrls: true, // Transform asset URLs in templates
184
+ autoImport: true, // Auto-import components via vite-plugin-vuetify
185
+ styles: true, // true | 'sass' | 'none' | { configFile: string }
186
+ i18n: true, // Enable vue-i18n integration
187
+
188
+ // Theme persistence
140
189
  persistence: {
141
190
  enabled: true,
142
191
  key: 'nuxt-vuetify-theme',
143
- storage: 'cookie', // 'cookie' | 'localStorage' | 'sessionStorage'
192
+ storage: 'cookie', // 'cookie' | 'localStorage' | 'sessionStorage'
144
193
  cookieOptions: {
145
- maxAge: 60 * 60 * 24 * 365,
194
+ maxAge: 60 * 60 * 24 * 365, // 1 year
146
195
  path: '/',
147
196
  sameSite: 'lax',
148
197
  },
149
198
  },
199
+
200
+ // Lazy loading (optional)
201
+ lazyComponents: false, // or { components: ['VDataTable'], delay: 200 }
202
+
203
+ // Preload options (optional)
204
+ preload: {
205
+ fonts: false,
206
+ criticalCSS: true,
207
+ },
150
208
  },
151
209
  })
152
210
  ```
@@ -157,195 +215,634 @@ export default defineNuxtConfig({
157
215
  |--------|------|---------|-------------|
158
216
  | `vuetifyOptions.ssr` | `boolean` | `true` | Enable SSR support |
159
217
  | `vuetifyOptions.blueprint` | `'md1' \| 'md2' \| 'md3'` | `'md3'` | Material Design blueprint |
160
- | `vuetifyOptions.dateAdapter` | `string` | `'vuetify'` | Date adapter to use |
218
+ | `vuetifyOptions.dateAdapter` | `string` | `'vuetify'` | Date adapter for date pickers |
161
219
  | `vuetifyOptions.icons` | `object` | `{ defaultSet: 'mdi' }` | Icon configuration |
162
- | `vuetifyOptions.locale` | `object` | - | Locale configuration |
220
+ | `vuetifyOptions.locale` | `object` | - | Locale and RTL configuration |
163
221
  | `vuetifyOptions.theme` | `object` | - | Theme configuration |
164
- | `vuetifyOptions.defaults` | `object` | - | Component defaults |
222
+ | `vuetifyOptions.defaults` | `object` | - | Component default props |
165
223
  | `importComposables` | `boolean` | `true` | Auto-import Vuetify composables |
166
224
  | `prefixComposables` | `boolean` | `false` | Prefix composables with 'V' |
167
- | `transformAssetUrls` | `boolean` | `true` | Transform asset URLs in templates |
168
- | `autoImport` | `boolean \| object` | `true` | Enable auto-import via vite-plugin-vuetify |
169
- | `styles` | `boolean \| string \| object` | `true` | Style configuration |
170
- | `persistence` | `object` | `{ enabled: true, ... }` | Theme persistence |
225
+ | `transformAssetUrls` | `boolean` | `true` | Transform asset URLs |
226
+ | `autoImport` | `boolean \| object` | `true` | Enable vite-plugin-vuetify |
227
+ | `styles` | `true \| 'sass' \| 'none' \| object` | `true` | Style configuration |
228
+ | `i18n` | `boolean \| object` | `true` | Enable vue-i18n integration |
229
+ | `persistence` | `object` | `{ enabled: true, storage: 'cookie' }` | Theme persistence |
230
+ | `lazyComponents` | `boolean \| object` | `false` | Lazy load heavy components |
231
+
232
+ ---
171
233
 
172
234
  ## Usage
173
235
 
174
- ### Using the Composable
236
+ ### Using the `useVuetify` Composable
237
+
175
238
  ```vue
239
+
176
240
  <script setup lang="ts">
177
- const {
178
- isDark,
179
- isMobile,
180
- currentTheme,
181
- currentBreakpoint,
182
- toggleTheme,
183
- setTheme,
184
- setLocale,
185
- } = useVuetify()
241
+ const {
242
+ isDark,
243
+ isMobile,
244
+ currentTheme,
245
+ currentBreakpoint,
246
+ toggleTheme,
247
+ setTheme,
248
+ setLocale,
249
+ } = useVuetify()
186
250
  </script>
187
251
 
188
252
  <template>
189
253
  <v-app>
190
- <v-btn @click="toggleTheme">
191
- {{ isDark ? 'Light' : 'Dark' }} Mode
192
- </v-btn>
254
+ <v-app-bar>
255
+ <v-app-bar-title>My App</v-app-bar-title>
256
+ <v-spacer></v-spacer>
257
+ <v-btn :icon="isDark ? 'mdi-white-balance-sunny' : 'mdi-moon-waning-crescent'"
258
+ @click="toggleTheme"></v-btn>
259
+ </v-app-bar>
260
+
261
+ <v-main>
262
+ <v-container>
263
+ <p>Current theme: {{ currentTheme }}</p>
264
+ <p>Breakpoint: {{ currentBreakpoint }}</p>
265
+ <p>Mobile: {{ isMobile }}</p>
266
+ </v-container>
267
+ </v-main>
193
268
  </v-app>
194
269
  </template>
195
270
  ```
196
271
 
197
- ### Using Hooks
272
+ ### Using Vuetify Composables Directly
273
+
274
+ The module auto-imports all Vuetify composables:
275
+
276
+ ```vue
277
+ <script setup lang="ts">
278
+ // These are auto-imported
279
+ const theme = useTheme()
280
+ const display = useDisplay()
281
+ const locale = useLocale()
282
+
283
+ // Toggle theme
284
+ const toggleDark = () => {
285
+ theme.global.name.value = theme.global.current.value.dark ? 'light' : 'dark'
286
+ }
287
+ </script>
288
+ ```
289
+
290
+ If you have naming conflicts, enable `prefixComposables: true`:
198
291
 
199
- Create a plugin to hook into Vuetify lifecycle:
200
292
  ```typescript
201
- // plugins/vuetify-custom.ts
202
- export default defineNuxtPlugin((nuxtApp) => {
203
- // Modify options before Vuetify is created
204
- onVuetifyHook(nuxtApp, 'vuetify:before-create', ({ vuetifyOptions }) => {
205
- vuetifyOptions.defaults = {
206
- ...vuetifyOptions.defaults,
207
- VAlert: {
208
- variant: 'tonal',
209
- },
210
- }
211
- })
293
+ // nuxt.config.ts
294
+ vuetify: {
295
+ prefixComposables: true, // useTheme -> useVTheme
296
+ }
297
+ ```
212
298
 
213
- // Access Vuetify instance when ready
214
- onVuetifyHook(nuxtApp, 'vuetify:ready', (vuetify) => {
215
- console.log('Vuetify ready:', vuetify.theme.global.name.value)
216
- })
299
+ ---
300
+
301
+ ## i18n Integration
302
+
303
+ The module seamlessly integrates with `@nuxtjs/i18n` for Vuetify's locale system.
304
+
305
+ ### Setup
306
+
307
+ ```bash
308
+ npm install @nuxtjs/i18n vue-i18n
309
+ ```
310
+
311
+ ```typescript
312
+ // nuxt.config.ts
313
+ export default defineNuxtConfig({
314
+ modules: [
315
+ '@nuxtjs/i18n',
316
+ 'vuetify-nuxt4-module',
317
+ ],
318
+
319
+ i18n: {
320
+ locales: [
321
+ { code: 'en', file: 'en.json', name: 'English' },
322
+ { code: 'km', file: 'km.json', name: 'ខ្មែរ' },
323
+ { code: 'ar', file: 'ar.json', name: 'العربية', dir: 'rtl' },
324
+ ],
325
+ defaultLocale: 'en',
326
+ langDir: 'locales/',
327
+ },
328
+
329
+ vuetify: {
330
+ i18n: true, // Enable vue-i18n adapter
331
+ },
217
332
  })
218
333
  ```
219
334
 
220
- ### Available Hooks
335
+ ### Locale Files
336
+
337
+ Create locale files with Vuetify translations under `$vuetify` key:
338
+
339
+ ```json
340
+ // locales/en.json
341
+ {
342
+ "welcome": "Welcome",
343
+ "$vuetify": {
344
+ "badge": "Badge",
345
+ "open": "Open",
346
+ "close": "Close",
347
+ "dataIterator": {
348
+ "noResultsText": "No matching records found",
349
+ "loadingText": "Loading items..."
350
+ },
351
+ "dataTable": {
352
+ "itemsPerPageText": "Rows per page:",
353
+ "ariaLabel": {
354
+ "sortDescending": "Sorted descending.",
355
+ "sortAscending": "Sorted ascending.",
356
+ "sortNone": "Not sorted."
357
+ }
358
+ },
359
+ "pagination": {
360
+ "ariaLabel": {
361
+ "root": "Pagination Navigation",
362
+ "next": "Next page",
363
+ "previous": "Previous page",
364
+ "page": "Go to page {0}",
365
+ "currentPage": "Page {0}, Current page"
366
+ }
367
+ }
368
+ }
369
+ }
370
+ ```
221
371
 
222
- | Hook | Payload | Description |
223
- |------|---------|-------------|
224
- | `vuetify:before-create` | `{ vuetifyOptions }` | Modify options before Vuetify is created |
225
- | `vuetify:configuration` | `{ vuetifyOptions }` | After configuration is applied |
226
- | `vuetify:ready` | `vuetify` | When Vuetify instance is ready |
372
+ ```json
373
+ // locales/km.json
374
+ {
375
+ "welcome": "សូមស្វាគមន៍",
376
+ "$vuetify": {
377
+ "badge": "ផ្លាកសញ្ញា",
378
+ "open": "បើក",
379
+ "close": "បិទ",
380
+ "dataIterator": {
381
+ "noResultsText": "រកមិនឃើញទិន្នន័យ",
382
+ "loadingText": "កំពុងផ្ទុក..."
383
+ },
384
+ "dataTable": {
385
+ "itemsPerPageText": "ជួរក្នុងមួយទំព័រ:"
386
+ }
387
+ }
388
+ }
389
+ ```
390
+
391
+ ### Switching Locales
392
+
393
+ ```vue
394
+ <script setup lang="ts">
395
+ const { locale, setLocale } = useI18n()
396
+
397
+ const switchLocale = (code: string) => {
398
+ setLocale(code)
399
+ // Vuetify locale updates automatically via the adapter
400
+ }
401
+ </script>
402
+
403
+ <template>
404
+ <v-btn-toggle v-model="locale">
405
+ <v-btn value="en">EN</v-btn>
406
+ <v-btn value="km">KM</v-btn>
407
+ <v-btn value="ar">AR</v-btn>
408
+ </v-btn-toggle>
409
+ </template>
410
+ ```
411
+
412
+ ---
413
+
414
+ ## Icon Configuration
415
+
416
+ ### Font Icons (MDI)
417
+
418
+ ```bash
419
+ npm install @mdi/font
420
+ ```
421
+
422
+ ```typescript
423
+ // nuxt.config.ts
424
+ vuetify: {
425
+ vuetifyOptions: {
426
+ icons: {
427
+ defaultSet: 'mdi',
428
+ },
429
+ },
430
+ }
431
+ ```
432
+
433
+ ```vue
434
+ <template>
435
+ <v-icon icon="mdi-home" />
436
+ <v-icon>mdi-account</v-icon>
437
+ <v-btn icon="mdi-menu" />
438
+ </template>
439
+ ```
440
+
441
+ ### SVG Icons (MDI-SVG) - Recommended for Performance
442
+
443
+ ```bash
444
+ npm install @mdi/js
445
+ ```
446
+
447
+ ```typescript
448
+ // nuxt.config.ts
449
+ vuetify: {
450
+ vuetifyOptions: {
451
+ icons: {
452
+ defaultSet: 'mdi-svg',
453
+ svg: {
454
+ mdi: {
455
+ aliases: {
456
+ // Map alias names to @mdi/js export names
457
+ account: 'mdiAccount',
458
+ home: 'mdiHome',
459
+ menu: 'mdiMenu',
460
+ settings: 'mdiCog',
461
+ search: 'mdiMagnify',
462
+ },
463
+ },
464
+ },
465
+ },
466
+ },
467
+ }
468
+ ```
469
+
470
+ Usage in templates:
471
+
472
+ ```vue
473
+ <script setup lang="ts">
474
+ // Direct import for icons not in aliases
475
+ import { mdiHeart, mdiStar } from '@mdi/js'
476
+ </script>
477
+
478
+ <template>
479
+ <!-- Using aliases (resolved at build time) -->
480
+ <v-icon icon="$account" />
481
+ <v-icon icon="$home" />
482
+
483
+ <!-- Using direct imports -->
484
+ <v-icon :icon="mdiHeart" />
485
+ <v-icon :icon="mdiStar" />
486
+ </template>
487
+ ```
488
+
489
+ ### FontAwesome Icons
490
+
491
+ ```bash
492
+ npm install @fortawesome/fontawesome-free
493
+ ```
494
+
495
+ ```typescript
496
+ vuetify: {
497
+ vuetifyOptions: {
498
+ icons: {
499
+ defaultSet: 'fa', // or 'fa-svg' for SVG version
500
+ },
501
+ },
502
+ }
503
+ ```
504
+
505
+ ---
506
+
507
+ ## Theme Persistence
508
+
509
+ The module provides SSR-safe theme persistence using cookies (recommended) or client-side storage.
510
+
511
+ ### Cookie Storage (SSR-Safe) - Recommended
512
+
513
+ ```typescript
514
+ vuetify: {
515
+ persistence: {
516
+ enabled: true,
517
+ storage: 'cookie',
518
+ key: 'nuxt-vuetify-theme',
519
+ cookieOptions: {
520
+ maxAge: 60 * 60 * 24 * 365, // 1 year
521
+ path: '/',
522
+ sameSite: 'lax',
523
+ },
524
+ },
525
+ }
526
+ ```
527
+
528
+ This prevents hydration mismatches because:
529
+ 1. Server reads theme from cookie in request headers
530
+ 2. Client reads theme from `document.cookie`
531
+ 3. Both render with the same theme
532
+
533
+ ### LocalStorage (Client-Only)
534
+
535
+ ```typescript
536
+ vuetify: {
537
+ persistence: {
538
+ enabled: true,
539
+ storage: 'localStorage',
540
+ key: 'my-app-theme',
541
+ },
542
+ }
543
+ ```
544
+
545
+ > ⚠️ **Note:** LocalStorage may cause hydration mismatches on first load since the server doesn't have access to localStorage.
546
+
547
+ ### Disable Persistence
548
+
549
+ ```typescript
550
+ vuetify: {
551
+ persistence: {
552
+ enabled: false,
553
+ },
554
+ }
555
+ ```
556
+
557
+ ---
227
558
 
228
559
  ## Date Adapters
229
560
 
230
- To use a date adapter other than the built-in one, install the required packages:
561
+ ### Using date-fns
562
+
231
563
  ```bash
232
- # date-fns
233
564
  npm install @date-io/date-fns date-fns
565
+ ```
566
+
567
+ ```typescript
568
+ vuetify: {
569
+ vuetifyOptions: {
570
+ dateAdapter: 'date-fns',
571
+ },
572
+ }
573
+ ```
234
574
 
235
- # dayjs
575
+ ### Using dayjs
576
+
577
+ ```bash
236
578
  npm install @date-io/dayjs dayjs
579
+ ```
237
580
 
238
- # luxon
239
- npm install @date-io/luxon luxon
581
+ ```typescript
582
+ vuetify: {
583
+ vuetifyOptions: {
584
+ dateAdapter: 'dayjs',
585
+ },
586
+ }
587
+ ```
240
588
 
241
- # moment
242
- npm install @date-io/moment moment
589
+ ### Using luxon
590
+
591
+ ```bash
592
+ npm install @date-io/luxon luxon
243
593
  ```
244
594
 
245
- Then configure:
246
595
  ```typescript
247
596
  vuetify: {
248
597
  vuetifyOptions: {
249
- dateAdapter: 'date-fns'
250
- }
598
+ dateAdapter: 'luxon',
599
+ },
251
600
  }
252
601
  ```
253
602
 
603
+ ---
604
+
254
605
  ## Custom SASS Variables
255
606
 
256
- To customize Vuetify's SASS variables:
607
+ ### Setup
257
608
 
258
609
  1. Create a settings file:
610
+
259
611
  ```scss
260
- // assets/settings.scss
612
+ // assets/vuetify-settings.scss
261
613
  @use 'vuetify/settings' with (
262
- $body-font-family: 'Inter',
614
+ $body-font-family: 'Inter, sans-serif',
263
615
  $border-radius-root: 8px,
264
616
  $button-height: 44px,
617
+ $card-border-radius: 12px,
265
618
  );
266
619
  ```
267
620
 
268
621
  2. Configure in nuxt.config.ts:
622
+
269
623
  ```typescript
270
624
  vuetify: {
271
625
  styles: {
272
- configFile: 'assets/settings.scss'
273
- }
626
+ configFile: 'assets/vuetify-settings.scss',
627
+ },
274
628
  }
275
629
  ```
276
630
 
277
- > **Note:** When using a custom config file with SSR, disable inline SSR styles:
278
- > ```typescript
279
- > experimental: {
280
- > inlineSSRStyles: false
281
- > }
282
- > ```
631
+ 3. **Important for SSR:** Disable inline SSR styles:
283
632
 
284
- ## Performance Tips
285
-
286
- ### 1. Use SVG Icons for Better Performance
287
633
  ```typescript
288
- vuetify: {
289
- vuetifyOptions: {
290
- icons: {
291
- defaultSet: 'mdi-svg' // SVG icons are tree-shaken
292
- }
293
- }
294
- }
634
+ // nuxt.config.ts
635
+ export default defineNuxtConfig({
636
+ experimental: {
637
+ inlineSSRStyles: false,
638
+ },
639
+ vuetify: {
640
+ styles: {
641
+ configFile: 'assets/vuetify-settings.scss',
642
+ },
643
+ },
644
+ })
295
645
  ```
296
646
 
297
- ### 2. Import Only Needed Icons (with mdi-svg)
298
- ```typescript
299
- // plugins/vuetify-icons.ts
300
- import { mdiAccount, mdiHome, mdiMenu } from '@mdi/js'
647
+ ---
648
+
649
+ ## Hooks
650
+
651
+ Use hooks to customize Vuetify at different lifecycle stages.
301
652
 
653
+ ### Available Hooks
654
+
655
+ | Hook | Payload | Description |
656
+ |------|---------|-------------|
657
+ | `vuetify:before-create` | `{ vuetifyOptions }` | Modify options before Vuetify is created |
658
+ | `vuetify:configuration` | `{ vuetifyOptions }` | After configuration is applied |
659
+ | `vuetify:ready` | `vuetify` | When Vuetify instance is ready |
660
+
661
+ ### Example: Custom Plugin
662
+
663
+ ```typescript
664
+ // plugins/vuetify-custom.ts
302
665
  export default defineNuxtPlugin((nuxtApp) => {
666
+ // Modify options before Vuetify is created
303
667
  onVuetifyHook(nuxtApp, 'vuetify:before-create', ({ vuetifyOptions }) => {
304
- vuetifyOptions.icons = {
305
- defaultSet: 'mdi-svg',
306
- aliases: {
307
- account: mdiAccount,
308
- home: mdiHome,
309
- menu: mdiMenu,
668
+ // Add custom defaults
669
+ vuetifyOptions.defaults = {
670
+ ...vuetifyOptions.defaults,
671
+ VAlert: {
672
+ variant: 'tonal',
673
+ rounded: 'lg',
310
674
  },
675
+ VChip: {
676
+ rounded: 'pill',
677
+ },
678
+ }
679
+
680
+ // Add custom theme
681
+ if (vuetifyOptions.theme?.themes) {
682
+ vuetifyOptions.theme.themes.corporate = {
683
+ dark: false,
684
+ colors: {
685
+ primary: '#0066CC',
686
+ secondary: '#6C757D',
687
+ },
688
+ }
311
689
  }
312
690
  })
691
+
692
+ // Access Vuetify instance when ready
693
+ onVuetifyHook(nuxtApp, 'vuetify:ready', (vuetify) => {
694
+ console.log('Current theme:', vuetify.theme.global.name.value)
695
+ })
313
696
  })
314
697
  ```
315
698
 
699
+ ---
700
+
701
+ ## Performance Tips
702
+
703
+ ### 1. Use SVG Icons (Tree-Shakeable)
704
+
705
+ ```typescript
706
+ vuetify: {
707
+ vuetifyOptions: {
708
+ icons: {
709
+ defaultSet: 'mdi-svg',
710
+ },
711
+ },
712
+ }
713
+ ```
714
+
715
+ ### 2. Enable Labs Components Only When Needed
716
+
717
+ ```typescript
718
+ vuetify: {
719
+ autoImport: {
720
+ labs: true, // Only if using lab components
721
+ },
722
+ }
723
+ ```
724
+
316
725
  ### 3. Lazy Load Heavy Components
726
+
317
727
  ```vue
318
728
  <script setup>
319
- // Lazy load data tables, calendars, etc.
320
729
  const VDataTable = defineAsyncComponent(() =>
321
730
  import('vuetify/components/VDataTable').then(m => m.VDataTable)
322
731
  )
323
732
  </script>
324
733
  ```
325
734
 
326
- ### 4. Use CSS Instead of JS for Themes
735
+ Or use the built-in lazy loading:
736
+
327
737
  ```typescript
328
- // nuxt.config.ts
329
738
  vuetify: {
330
- styles: {
331
- configFile: 'assets/vuetify.scss'
332
- }
739
+ lazyComponents: {
740
+ components: ['VDataTable', 'VDatePicker', 'VCalendar'],
741
+ delay: 200,
742
+ },
333
743
  }
334
744
  ```
335
745
 
336
- ### 5. Enable Compression
746
+ ### 4. Enable Compression
747
+
337
748
  ```typescript
338
749
  // nuxt.config.ts
339
750
  nitro: {
340
- compressPublicAssets: true
751
+ compressPublicAssets: true,
341
752
  }
342
753
  ```
343
754
 
755
+ ### 5. Analyze Bundle Size
756
+
757
+ ```bash
758
+ npm run analyze
759
+ ```
760
+
761
+ ---
762
+
344
763
  ## TypeScript
345
764
 
346
- The module provides full TypeScript support. Types are automatically generated.
765
+ The module provides full TypeScript support with auto-generated types.
766
+
767
+ ### Type Augmentation
768
+
769
+ ```typescript
770
+ // types/vuetify.d.ts
771
+ declare module 'vuetify' {
772
+ interface ThemeDefinition {
773
+ // Add custom theme properties
774
+ }
775
+ }
776
+ ```
777
+
778
+ ### Typed Composable
779
+
780
+ ```typescript
781
+ const { isDark, toggleTheme } = useVuetify()
782
+ // isDark: ComputedRef<boolean>
783
+ // toggleTheme: () => void
784
+ ```
785
+
786
+ ---
787
+
788
+ ## Troubleshooting
789
+
790
+ ### Hydration Mismatch with Theme
791
+
792
+ **Problem:** Server renders light theme, client shows dark theme briefly.
793
+
794
+ **Solution:** Use cookie storage (default):
795
+
796
+ ```typescript
797
+ vuetify: {
798
+ persistence: {
799
+ storage: 'cookie', // Not 'localStorage'
800
+ },
801
+ }
802
+ ```
803
+
804
+ ### Duplicate CSS Loading
805
+
806
+ **Problem:** Vuetify CSS is loaded twice.
807
+
808
+ **Solution:** The module handles this automatically. Make sure you don't manually import Vuetify styles in your nuxt.config.ts:
809
+
810
+ ```typescript
811
+ // ❌ Don't do this
812
+ css: ['vuetify/styles'],
813
+
814
+ // ✅ Let the module handle it
815
+ vuetify: {
816
+ styles: true,
817
+ }
818
+ ```
819
+
820
+ ### i18n Not Working
821
+
822
+ **Problem:** Vuetify doesn't use vue-i18n translations.
823
+
824
+ **Solution:**
825
+ 1. Ensure `@nuxtjs/i18n` is listed **before** `vuetify-nuxt4-module` in modules
826
+ 2. Add translations under `$vuetify` key in locale files
827
+
828
+ ### Icons Not Showing
829
+
830
+ **Problem:** Icons appear as empty boxes.
831
+
832
+ **Solution:** Install the icon package:
833
+
834
+ ```bash
835
+ # For font icons
836
+ npm install @mdi/font
837
+
838
+ # For SVG icons
839
+ npm install @mdi/js
840
+ ```
841
+
842
+ ---
347
843
 
348
844
  ## Local Development
845
+
349
846
  ```bash
350
847
  # Install dependencies
351
848
  npm install
@@ -353,23 +850,45 @@ npm install
353
850
  # Generate type stubs
354
851
  npm run dev:prepare
355
852
 
356
- # Develop with the playground
853
+ # Develop with playground
357
854
  npm run dev
358
855
 
359
- # Build the playground
856
+ # Build playground
360
857
  npm run dev:build
361
858
 
362
- # Run ESLint
859
+ # Run linter
363
860
  npm run lint
364
861
 
365
- # Run Vitest
862
+ # Run tests
366
863
  npm run test
367
864
  npm run test:watch
368
865
 
866
+ # Type check
867
+ npm run test:types
868
+
869
+ # Analyze bundle
870
+ npm run analyze
871
+
369
872
  # Release new version
370
873
  npm run release
371
874
  ```
372
875
 
876
+ ---
877
+
878
+ ## Contributing
879
+
880
+ Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) before submitting a Pull Request.
881
+
882
+ ---
883
+
373
884
  ## License
374
885
 
375
886
  [MIT License](LICENSE)
887
+
888
+ ---
889
+
890
+ ## Credits
891
+
892
+ - [Vuetify](https://vuetifyjs.com/) - The Vue UI Library
893
+ - [Nuxt](https://nuxt.com/) - The Intuitive Vue Framework
894
+ - [@nuxtjs/i18n](https://i18n.nuxtjs.org/) - Internationalization for Nuxt
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=4.0.0"
6
6
  },
7
- "version": "1.2.0",
7
+ "version": "1.2.2",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -90,16 +90,19 @@ const module$1 = defineNuxtModule({
90
90
  }
91
91
  ]);
92
92
  const useVitePlugin = options.autoImport !== false;
93
- let vitePluginStyles = "none";
94
93
  if (options.autoImport && useVitePlugin) {
94
+ let vitePluginStyles = "none";
95
95
  if (typeof options.styles === "object" && options.styles.configFile) {
96
96
  vitePluginStyles = { configFile: options.styles.configFile };
97
97
  } else if (options.styles === "sass") {
98
98
  vitePluginStyles = "sass";
99
99
  } else if (options.styles === true || options.styles === void 0) {
100
- vitePluginStyles = true;
100
+ vitePluginStyles = "none";
101
101
  }
102
102
  await setupAutoImport(options.autoImport, vitePluginStyles, logger);
103
+ if (options.styles !== "none") {
104
+ addStyles(nuxt, options.styles);
105
+ }
103
106
  } else {
104
107
  addStyles(nuxt, options.styles);
105
108
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vuetify-nuxt4-module",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "Zero-config Vuetify 3 module for Nuxt 4 with performance optimizations.",
5
5
  "repository": {
6
6
  "type": "git",