vuetify-nuxt-module 1.0.0-beta.4 → 1.0.0-beta.5

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/dist/module.d.mts CHANGED
@@ -251,6 +251,18 @@ interface MOptions {
251
251
  * Path to the custom Vuetify SASS configuration file.
252
252
  */
253
253
  configFile: string;
254
+ /**
255
+ * Caching options forwarded to `@vuetify/unplugin-styles`.
256
+ *
257
+ * @default true
258
+ */
259
+ cache?: boolean | {
260
+ path?: string;
261
+ sassOptions?: Record<string, unknown>;
262
+ };
263
+ /**
264
+ * @deprecated Use `styles.cache` instead.
265
+ */
254
266
  experimental?: {
255
267
  cache?: boolean;
256
268
  };
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.4",
7
+ "version": "1.0.0-beta.5",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -4,20 +4,19 @@ import semver from 'semver';
4
4
  import { createFilter, version as version$1 } from 'vite';
5
5
  import defu from 'defu';
6
6
  import { transformAssetUrls } from 'vite-plugin-vuetify';
7
- import { createHash } from 'node:crypto';
8
- import fs, { existsSync, readdirSync, rmSync, statSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
9
- import { isAbsolute, resolve, join, relative, dirname } from 'pathe';
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
+ import Styles from '@vuetify/unplugin-styles/vite';
10
11
  import { pathToFileURL } from 'node:url';
11
- import { generateImports, isObject, resolveVuetifyBase, normalizePath } from '@vuetify/loader-shared';
12
12
  import destr from 'destr';
13
13
  import { parseQuery, parseURL } from 'ufo';
14
- import fsp, { readFile } from 'node:fs/promises';
15
- import path from 'upath';
14
+ import { readFile } from 'node:fs/promises';
16
15
  import { debounce } from 'perfect-debounce';
17
16
  import process from 'node:process';
18
17
  import { createConfigLoader } from 'unconfig';
19
18
 
20
- const version = "1.0.0-beta.4";
19
+ const version = "1.0.0-beta.5";
21
20
 
22
21
  const VIRTUAL_VUETIFY_CONFIGURATION = "virtual:vuetify-configuration";
23
22
  const RESOLVED_VIRTUAL_VUETIFY_CONFIGURATION = `\0${VIRTUAL_VUETIFY_CONFIGURATION}`;
@@ -138,52 +137,6 @@ function resolveVuetifyConfigFile(configFile, nuxt) {
138
137
  }
139
138
  return configFile;
140
139
  }
141
- function createStylesCacheHash(vuetifyVersion, viteVersion, configContent, configFile) {
142
- return createHash("sha256").update(vuetifyVersion).update(viteVersion).update(configContent).update(configFile).digest("hex").slice(0, 8);
143
- }
144
- function resolveStylesCachePaths(rootDir, hash) {
145
- const stylesDir = resolve(rootDir, "node_modules/.cache/vuetify-nuxt-module/styles");
146
- const cacheDir = join(stylesDir, hash);
147
- return {
148
- stylesDir,
149
- cacheDir
150
- };
151
- }
152
- function cleanupOldStylesCaches(stylesDir, currentHash) {
153
- if (!existsSync(stylesDir)) {
154
- return;
155
- }
156
- const dirents = readdirSync(stylesDir, { withFileTypes: true });
157
- for (const dirent of dirents) {
158
- if (dirent.isDirectory() && dirent.name !== currentHash) {
159
- rmSync(join(stylesDir, dirent.name), { recursive: true, force: true });
160
- }
161
- }
162
- }
163
- function collectVuetifyCssFiles(vuetifyBase) {
164
- const files = [];
165
- findCssFiles(join(vuetifyBase, "lib/components"), files);
166
- findCssFiles(join(vuetifyBase, "lib/styles"), files);
167
- return files;
168
- }
169
- function findCssFiles(dir, fileList = []) {
170
- if (!existsSync(dir)) {
171
- return fileList;
172
- }
173
- const files = readdirSync(dir);
174
- for (const file of files) {
175
- const filePath = join(dir, file);
176
- const stat = statSync(filePath);
177
- if (stat.isDirectory()) {
178
- findCssFiles(filePath, fileList);
179
- } else {
180
- if (file.endsWith(".css")) {
181
- fileList.push(filePath);
182
- }
183
- }
184
- }
185
- return fileList;
186
- }
187
140
 
188
141
  function addVuetifyNuxtPlugins(nuxt, ctx) {
189
142
  addVuetifyNuxtPlugin(nuxt, ctx, "client");
@@ -948,125 +901,6 @@ function vuetifySSRClientHintsPlugin(ctx) {
948
901
  };
949
902
  }
950
903
 
951
- function vuetifyStylesPlugin(ctx) {
952
- let configFile;
953
- let vuetifyBase;
954
- const options = { styles: ctx.moduleOptions.styles };
955
- const noneFiles = /* @__PURE__ */ new Set();
956
- let isNone = false;
957
- let sassVariables = false;
958
- let fileImport = false;
959
- const PREFIX = "vuetify-styles/";
960
- const SSR_PREFIX = `/@${PREFIX}`;
961
- const resolveCss = resolveCssFactory();
962
- const toPath = (file) => fileImport ? pathToFileURL(file).href : normalizePath(file);
963
- return {
964
- name: "vuetify:styles:nuxt",
965
- enforce: "pre",
966
- async configResolved(config) {
967
- if (config.plugins.some((plugin) => plugin.name === "vuetify:styles")) {
968
- throw new Error("Remove vite-plugin-vuetify from your Nuxt config file, this module registers a modified version.");
969
- }
970
- if (isObject(options.styles) && "configFile" in options.styles) {
971
- sassVariables = true;
972
- fileImport = semver.gt(ctx.viteVersion, "5.4.2");
973
- configFile = ctx.stylesConfigFile ?? await resolvePath(options.styles.configFile);
974
- } else {
975
- isNone = options.styles === "none";
976
- }
977
- vuetifyBase = await resolveVuetifyBase();
978
- },
979
- async resolveId(source, importer, { custom, ssr }) {
980
- if (!sassVariables) {
981
- return;
982
- }
983
- if (source.startsWith(PREFIX) || source.startsWith(SSR_PREFIX)) {
984
- if (/\.s[ca]ss$/.test(source)) {
985
- return source;
986
- }
987
- const idx = source.indexOf("?");
988
- return idx === -1 ? source : source.slice(0, idx);
989
- }
990
- if (vuetifyBase && importer && source.endsWith(".css") && isSubdir(vuetifyBase, path.isAbsolute(source) ? source : importer)) {
991
- let resolutionId;
992
- if (source.startsWith(".")) {
993
- resolutionId = path.resolve(path.dirname(importer), source);
994
- } else if (path.isAbsolute(source)) {
995
- resolutionId = source;
996
- } else {
997
- const resolution = await this.resolve(source, importer, { skipSelf: true, custom });
998
- if (resolution) {
999
- resolutionId = resolution.id;
1000
- }
1001
- }
1002
- if (!resolutionId) {
1003
- return;
1004
- }
1005
- const target = await resolveCss(resolutionId);
1006
- if (isNone) {
1007
- noneFiles.add(target);
1008
- return target;
1009
- }
1010
- if (ctx.stylesCachePath) {
1011
- const relative = path.relative(vuetifyBase, target);
1012
- const cacheFile = path.resolve(ctx.stylesCachePath, relative.replace(/\.s[ac]ss$/, ".css"));
1013
- if (fs.existsSync(cacheFile)) {
1014
- return cacheFile;
1015
- }
1016
- }
1017
- return `${ssr ? SSR_PREFIX : PREFIX}${path.relative(vuetifyBase, target)}`;
1018
- }
1019
- return void 0;
1020
- },
1021
- load(id) {
1022
- if (sassVariables) {
1023
- if (!vuetifyBase) {
1024
- return;
1025
- }
1026
- 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;
1027
- if (target) {
1028
- const suffix = /\.scss/.test(target) ? ";\n" : "\n";
1029
- return {
1030
- code: `@use "${toPath(configFile)}"${suffix}@use "${toPath(target)}"${suffix}`,
1031
- map: {
1032
- mappings: ""
1033
- }
1034
- };
1035
- }
1036
- }
1037
- return isNone && noneFiles.has(id) ? "" : void 0;
1038
- }
1039
- };
1040
- }
1041
- function resolveCssFactory() {
1042
- const mappings = /* @__PURE__ */ new Map();
1043
- return async (source) => {
1044
- let mapping = mappings.get(source);
1045
- if (!mapping) {
1046
- try {
1047
- mapping = source.replace(/\.css$/, ".sass");
1048
- await fsp.access(mapping, fs.constants.R_OK);
1049
- } catch (error) {
1050
- if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) {
1051
- throw error;
1052
- }
1053
- try {
1054
- mapping = source.replace(/\.css$/, ".scss");
1055
- await fsp.access(mapping, fs.constants.R_OK);
1056
- } catch {
1057
- mapping = source;
1058
- }
1059
- }
1060
- mappings.set(source, mapping);
1061
- }
1062
- return mapping;
1063
- };
1064
- }
1065
- function isSubdir(root, test) {
1066
- const relative$1 = relative(root, test);
1067
- return relative$1 && !relative$1.startsWith("..") && !isAbsolute(relative$1);
1068
- }
1069
-
1070
904
  function detectDate() {
1071
905
  const result = [];
1072
906
  for (const adapter of [
@@ -1124,6 +958,9 @@ function resolveVuetifyComponents(resolver) {
1124
958
  }
1125
959
  }
1126
960
 
961
+ function resolveStylesCache(stylesOption) {
962
+ return stylesOption.cache ?? stylesOption.experimental?.cache;
963
+ }
1127
964
  function configureVite(configKey, nuxt, ctx) {
1128
965
  nuxt.hook("vite:extend", ({ config }) => checkVuetifyPlugins(config));
1129
966
  nuxt.hook("vite:extendConfig", (viteInlineConfig) => {
@@ -1176,8 +1013,18 @@ function configureVite(configKey, nuxt, ctx) {
1176
1013
  autoImport.ignore = Array.isArray(ignoreDirectives) ? ignoreDirectives : [ignoreDirectives];
1177
1014
  }
1178
1015
  viteInlineConfig.plugins.push(vuetifyImportPlugin({ autoImport }));
1179
- if (ctx.moduleOptions.styles !== false && ctx.moduleOptions.styles !== "none") {
1180
- viteInlineConfig.plugins.push(vuetifyStylesPlugin(ctx));
1016
+ const stylesOption = ctx.moduleOptions.styles;
1017
+ if (stylesOption === "none") {
1018
+ viteInlineConfig.plugins.push(Styles({ styles: "none" }));
1019
+ } else if (isObject(stylesOption) && "configFile" in stylesOption) {
1020
+ if (!ctx.stylesConfigFile) {
1021
+ throw new Error("vuetify-nuxt-module: styles.configFile could not be resolved");
1022
+ }
1023
+ const cache = resolveStylesCache(stylesOption);
1024
+ viteInlineConfig.plugins.push(Styles({
1025
+ settings: ctx.stylesConfigFile,
1026
+ ...cache === void 0 ? {} : { cache }
1027
+ }));
1181
1028
  }
1182
1029
  viteInlineConfig.plugins.push(vuetifyConfigurationPlugin(ctx), vuetifyIconsPlugin(ctx), vuetifyDateConfigurationPlugin(ctx));
1183
1030
  if (ctx.ssrClientHints.enabled) {
@@ -1556,102 +1403,6 @@ function prepareSSRClientHints(baseUrl, ctx) {
1556
1403
  return clientHints;
1557
1404
  }
1558
1405
 
1559
- async function prepareVuetifyStyles(nuxt, ctx) {
1560
- const stylesConfig = ctx.moduleOptions.styles;
1561
- if (!isObject(stylesConfig) || !("configFile" in stylesConfig)) {
1562
- return;
1563
- }
1564
- if (stylesConfig.experimental?.cache === false) {
1565
- return;
1566
- }
1567
- const vuetifyBase = await resolveVuetifyBase();
1568
- let configFile;
1569
- let configContent = "";
1570
- if (stylesConfig.configFile) {
1571
- configFile = await resolvePath(resolveVuetifyConfigFile(stylesConfig.configFile, nuxt));
1572
- ctx.stylesConfigFile = configFile;
1573
- if (existsSync(configFile)) {
1574
- configContent = readFileSync(configFile, "utf8");
1575
- if (!ctx.vuetifyFilesToWatch.includes(configFile)) {
1576
- ctx.vuetifyFilesToWatch.push(configFile);
1577
- }
1578
- }
1579
- }
1580
- if (!configFile) {
1581
- return;
1582
- }
1583
- const hash = createStylesCacheHash(
1584
- ctx.vuetifyVersion,
1585
- ctx.viteVersion,
1586
- configContent,
1587
- configFile
1588
- );
1589
- const { stylesDir, cacheDir } = resolveStylesCachePaths(nuxt.options.rootDir, hash);
1590
- ctx.stylesCachePath = cacheDir;
1591
- cleanupOldStylesCaches(stylesDir, hash);
1592
- if (existsSync(cacheDir)) {
1593
- return;
1594
- }
1595
- ctx.logger.info("Compiling Vuetify styles...");
1596
- let sass;
1597
- try {
1598
- sass = await import('sass');
1599
- } catch {
1600
- try {
1601
- sass = await import('sass-embedded');
1602
- } catch {
1603
- ctx.logger.warn('Could not load "sass" or "sass-embedded". Skipping styles pre-compilation.');
1604
- return;
1605
- }
1606
- }
1607
- const files = collectVuetifyCssFiles(vuetifyBase);
1608
- for (const file of files) {
1609
- const relativePath = relative(vuetifyBase, file);
1610
- const cacheFile = join(cacheDir, relativePath);
1611
- const sassFile = file.replace(/\.css$/, ".sass");
1612
- const scssFile = file.replace(/\.css$/, ".scss");
1613
- let targetFile;
1614
- if (existsSync(sassFile)) {
1615
- targetFile = sassFile;
1616
- } else if (existsSync(scssFile)) {
1617
- targetFile = scssFile;
1618
- }
1619
- if (targetFile) {
1620
- const dir = dirname(cacheFile);
1621
- if (!existsSync(dir)) {
1622
- mkdirSync(dir, { recursive: true });
1623
- }
1624
- const content = `@use "${normalizePath(configFile)}";
1625
- @use "${normalizePath(targetFile)}";
1626
- `;
1627
- try {
1628
- const result = sass.compileString(content, {
1629
- loadPaths: [
1630
- dirname(configFile),
1631
- dirname(targetFile),
1632
- resolve(vuetifyBase, ".."),
1633
- resolve(vuetifyBase, "../.."),
1634
- // In case of monorepo/hoisting issues, but standard is enough
1635
- vuetifyBase
1636
- ],
1637
- url: new URL(pathToFileURL(cacheFile).href)
1638
- });
1639
- writeFileSync(cacheFile, result.css, "utf8");
1640
- } catch (error) {
1641
- ctx.logger.error(`Failed to compile ${targetFile}:`, error);
1642
- }
1643
- }
1644
- }
1645
- const metadata = {
1646
- hash,
1647
- vuetifyVersion: ctx.vuetifyVersion,
1648
- viteVersion: ctx.viteVersion,
1649
- configFile,
1650
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
1651
- };
1652
- writeFileSync(join(cacheDir, "metadata.json"), JSON.stringify(metadata, null, 2), "utf8");
1653
- }
1654
-
1655
1406
  async function load(options, nuxt, ctx) {
1656
1407
  const {
1657
1408
  configuration,
@@ -1727,7 +1478,6 @@ async function load(options, nuxt, ctx) {
1727
1478
  }
1728
1479
  }
1729
1480
  }
1730
- await prepareVuetifyStyles(nuxt, ctx);
1731
1481
  }
1732
1482
  function registerWatcher(options, nuxt, ctx) {
1733
1483
  if (nuxt.options.dev) {
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.4",
4
+ "version": "1.0.0-beta.5",
5
5
  "description": "Zero-Config Nuxt Module for Vuetify",
6
6
  "author": "userquin <userquin@gmail.com>",
7
7
  "license": "MIT",
@@ -52,6 +52,7 @@
52
52
  ],
53
53
  "dependencies": {
54
54
  "@nuxt/kit": "^4.3.1",
55
+ "@vuetify/unplugin-styles": "^1.0.0-beta.10",
55
56
  "defu": "^6.1.4",
56
57
  "destr": "^2.0.5",
57
58
  "local-pkg": "^1.1.2",
@@ -60,7 +61,6 @@
60
61
  "semver": "^7.7.4",
61
62
  "ufo": "^1.6.3",
62
63
  "unconfig": "^7.5.0",
63
- "upath": "^2.0.1",
64
64
  "vite-plugin-vuetify": "^2.1.3",
65
65
  "vuetify": "^4.0.1"
66
66
  },
@@ -87,6 +87,7 @@
87
87
  "eslint": "^10.0.2",
88
88
  "luxon": "^3.7.2",
89
89
  "nuxt": "^4.3.1",
90
+ "playwright-core": "^1.58.0",
90
91
  "publint": "^0.3.18",
91
92
  "rimraf": "^6.1.3",
92
93
  "sass": "^1.97.3",
@@ -98,6 +99,7 @@
98
99
  "build": {
99
100
  "externals": [
100
101
  "@vuetify/loader-shared",
102
+ "@vuetify/unplugin-styles",
101
103
  "node:child_process",
102
104
  "node:fs",
103
105
  "consola",
@@ -109,7 +111,6 @@
109
111
  "rollup",
110
112
  "sass",
111
113
  "sass-embedded",
112
- "upath",
113
114
  "ufo",
114
115
  "unconfig",
115
116
  "vite",
@@ -139,8 +140,9 @@
139
140
  "lint": "eslint .",
140
141
  "lint:fix": "nr lint --fix",
141
142
  "publint": "publint",
142
- "test": "vitest run",
143
- "test:watch": "vitest watch",
143
+ "test": "vitest run --exclude 'test/e2e/**'",
144
+ "test:watch": "vitest watch --exclude 'test/e2e/**'",
145
+ "test:e2e": "vitest run test/e2e",
144
146
  "release": "bumpp"
145
147
  }
146
148
  }