vuetify-nuxt-module 1.0.0-alpha.4 → 1.0.0-alpha.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.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3.15.0"
6
6
  },
7
- "version": "1.0.0-alpha.4",
7
+ "version": "1.0.0-alpha.5",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -2,7 +2,7 @@ import { addPluginTemplate, addTemplate, resolvePath, extendWebpackConfig, isNux
2
2
  import { isPackageExists, getPackageInfo } from 'local-pkg';
3
3
  import semver from 'semver';
4
4
  import { createFilter, version as version$1 } from 'vite';
5
- import fs, { existsSync, statSync } from 'node:fs';
5
+ import fs, { existsSync, statSync, readFileSync, readdirSync, rmSync, mkdirSync, writeFileSync } from 'node:fs';
6
6
  import { isAbsolute, resolve, relative } from 'pathe';
7
7
  import defu from 'defu';
8
8
  import { transformAssetUrls } from 'vite-plugin-vuetify';
@@ -12,12 +12,13 @@ import destr from 'destr';
12
12
  import { parseQuery, parseURL } from 'ufo';
13
13
  import fsp, { readFile } from 'node:fs/promises';
14
14
  import path from 'upath';
15
- import { resolve as resolve$1, dirname, relative as relative$1 } from 'node:path';
15
+ import { resolve as resolve$1, dirname, join, relative as relative$1 } from 'node:path';
16
16
  import { debounce } from 'perfect-debounce';
17
17
  import process from 'node:process';
18
18
  import { createConfigLoader } from 'unconfig';
19
+ import { createHash } from 'node:crypto';
19
20
 
20
- const version = "1.0.0-alpha.4";
21
+ const version = "1.0.0-alpha.5";
21
22
 
22
23
  const VIRTUAL_VUETIFY_CONFIGURATION = "virtual:vuetify-configuration";
23
24
  const RESOLVED_VIRTUAL_VUETIFY_CONFIGURATION = `\0${VIRTUAL_VUETIFY_CONFIGURATION}`;
@@ -900,12 +901,11 @@ function vuetifySSRClientHintsPlugin(ctx) {
900
901
  };
901
902
  }
902
903
 
903
- function vuetifyStylesPlugin(options, viteVersion, _logger) {
904
+ function vuetifyStylesPlugin(ctx) {
904
905
  let configFile;
905
- let useLoadCache = false;
906
+ const options = { styles: ctx.moduleOptions.styles };
906
907
  const vuetifyBase = resolveVuetifyBase();
907
908
  const noneFiles = /* @__PURE__ */ new Set();
908
- const loadCache = /* @__PURE__ */ new Map();
909
909
  let isNone = false;
910
910
  let sassVariables = false;
911
911
  let fileImport = false;
@@ -922,8 +922,7 @@ function vuetifyStylesPlugin(options, viteVersion, _logger) {
922
922
  }
923
923
  if (isObject(options.styles) && "configFile" in options.styles) {
924
924
  sassVariables = true;
925
- useLoadCache = !config.isProduction && !!options.styles.experimental?.cache;
926
- fileImport = semver.gt(viteVersion, "5.4.2");
925
+ fileImport = semver.gt(ctx.viteVersion, "5.4.2");
927
926
  configFile = await resolvePath(options.styles.configFile);
928
927
  } else {
929
928
  isNone = options.styles === "none";
@@ -941,18 +940,32 @@ function vuetifyStylesPlugin(options, viteVersion, _logger) {
941
940
  return idx === -1 ? source : source.slice(0, idx);
942
941
  }
943
942
  if (importer && source.endsWith(".css") && isSubdir(vuetifyBase, path.isAbsolute(source) ? source : importer)) {
944
- const resolution = await this.resolve(source, importer, { skipSelf: true, custom });
945
- if (!resolution) {
946
- return;
943
+ let resolutionId;
944
+ if (source.startsWith(".")) {
945
+ resolutionId = path.resolve(path.dirname(importer), source);
946
+ } else if (path.isAbsolute(source)) {
947
+ resolutionId = source;
948
+ } else {
949
+ const resolution = await this.resolve(source, importer, { skipSelf: true, custom });
950
+ if (resolution) {
951
+ resolutionId = resolution.id;
952
+ }
947
953
  }
948
- const target = await resolveCss(resolution.id);
949
- if (target.startsWith(PREFIX) || target.startsWith(SSR_PREFIX)) {
950
- return target;
954
+ if (!resolutionId) {
955
+ return;
951
956
  }
957
+ const target = await resolveCss(resolutionId);
952
958
  if (isNone) {
953
959
  noneFiles.add(target);
954
960
  return target;
955
961
  }
962
+ if (ctx.stylesCachePath) {
963
+ const relative = path.relative(vuetifyBase, target);
964
+ const cacheFile = path.resolve(ctx.stylesCachePath, relative.replace(/\.s[ac]ss$/, ".css"));
965
+ if (fs.existsSync(cacheFile)) {
966
+ return cacheFile;
967
+ }
968
+ }
956
969
  return `${ssr ? SSR_PREFIX : PREFIX}${path.relative(vuetifyBase, target)}`;
957
970
  }
958
971
  return void 0;
@@ -961,35 +974,16 @@ function vuetifyStylesPlugin(options, viteVersion, _logger) {
961
974
  if (sassVariables) {
962
975
  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;
963
976
  if (target) {
964
- if (useLoadCache) {
965
- const cached = loadCache.get(id);
966
- if (cached) {
967
- return cached;
968
- }
969
- }
970
977
  const suffix = /\.scss/.test(target) ? ";\n" : "\n";
971
- const result = {
978
+ return {
972
979
  code: `@use "${toPath(configFile)}"${suffix}@use "${toPath(target)}"${suffix}`,
973
980
  map: {
974
981
  mappings: ""
975
982
  }
976
983
  };
977
- if (useLoadCache) {
978
- loadCache.set(id, result);
979
- }
980
- return result;
981
984
  }
982
985
  }
983
986
  return isNone && noneFiles.has(id) ? "" : void 0;
984
- },
985
- handleHotUpdate({ file }) {
986
- if (!useLoadCache) {
987
- return;
988
- }
989
- const normalizedFile = normalizePath(file);
990
- if (normalizedFile === normalizePath(configFile || "") || normalizedFile.endsWith(".sass") || normalizedFile.endsWith(".scss")) {
991
- loadCache.clear();
992
- }
993
987
  }
994
988
  };
995
989
  }
@@ -1005,7 +999,12 @@ function resolveCssFactory() {
1005
999
  if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) {
1006
1000
  throw error;
1007
1001
  }
1008
- mapping = source.replace(/\.css$/, ".scss");
1002
+ try {
1003
+ mapping = source.replace(/\.css$/, ".scss");
1004
+ await fsp.access(mapping, fs.constants.R_OK);
1005
+ } catch {
1006
+ mapping = source;
1007
+ }
1009
1008
  }
1010
1009
  mappings.set(source, mapping);
1011
1010
  }
@@ -1127,7 +1126,7 @@ function configureVite(configKey, nuxt, ctx) {
1127
1126
  }
1128
1127
  viteInlineConfig.plugins.push(vuetifyImportPlugin({ autoImport }));
1129
1128
  if (ctx.moduleOptions.styles !== false && ctx.moduleOptions.styles !== "none") {
1130
- viteInlineConfig.plugins.push(vuetifyStylesPlugin({ styles: ctx.moduleOptions.styles }, ctx.viteVersion, ctx.logger));
1129
+ viteInlineConfig.plugins.push(vuetifyStylesPlugin(ctx));
1131
1130
  }
1132
1131
  viteInlineConfig.plugins.push(vuetifyConfigurationPlugin(ctx), vuetifyIconsPlugin(ctx), vuetifyDateConfigurationPlugin(ctx));
1133
1132
  if (ctx.ssrClientHints.enabled) {
@@ -1506,6 +1505,124 @@ function prepareSSRClientHints(baseUrl, ctx) {
1506
1505
  return clientHints;
1507
1506
  }
1508
1507
 
1508
+ async function prepareVuetifyStyles(nuxt, ctx) {
1509
+ const stylesConfig = ctx.moduleOptions.styles;
1510
+ if (!isObject(stylesConfig) || !("configFile" in stylesConfig)) {
1511
+ return;
1512
+ }
1513
+ if (stylesConfig.experimental?.cache === false) {
1514
+ return;
1515
+ }
1516
+ const vuetifyBase = resolveVuetifyBase();
1517
+ let configFile;
1518
+ let configContent = "";
1519
+ if (stylesConfig.configFile) {
1520
+ configFile = await resolvePath(stylesConfig.configFile);
1521
+ if (existsSync(configFile)) {
1522
+ configContent = readFileSync(configFile, "utf8");
1523
+ if (!ctx.vuetifyFilesToWatch.includes(configFile)) {
1524
+ ctx.vuetifyFilesToWatch.push(configFile);
1525
+ }
1526
+ }
1527
+ }
1528
+ if (!configFile) {
1529
+ return;
1530
+ }
1531
+ const hash = createHash("sha256").update(ctx.vuetifyVersion).update(ctx.viteVersion).update(configContent).update(configFile).digest("hex").slice(0, 8);
1532
+ const stylesDir = resolve$1(nuxt.options.rootDir, "node_modules/.cache/vuetify-nuxt-module/styles");
1533
+ const cacheDir = join(stylesDir, hash);
1534
+ ctx.stylesCachePath = cacheDir;
1535
+ if (existsSync(stylesDir)) {
1536
+ const dirents = readdirSync(stylesDir, { withFileTypes: true });
1537
+ for (const dirent of dirents) {
1538
+ if (dirent.isDirectory() && dirent.name !== hash) {
1539
+ rmSync(join(stylesDir, dirent.name), { recursive: true, force: true });
1540
+ }
1541
+ }
1542
+ }
1543
+ if (existsSync(cacheDir)) {
1544
+ return;
1545
+ }
1546
+ ctx.logger.info("Compiling Vuetify styles...");
1547
+ let sass;
1548
+ try {
1549
+ sass = await import('sass');
1550
+ } catch {
1551
+ try {
1552
+ sass = await import('sass-embedded');
1553
+ } catch {
1554
+ ctx.logger.warn('Could not load "sass" or "sass-embedded". Skipping styles pre-compilation.');
1555
+ return;
1556
+ }
1557
+ }
1558
+ const files = [];
1559
+ findCssFiles(join(vuetifyBase, "lib/components"), files);
1560
+ findCssFiles(join(vuetifyBase, "lib/styles"), files);
1561
+ for (const file of files) {
1562
+ const relativePath = relative$1(vuetifyBase, file);
1563
+ const cacheFile = join(cacheDir, relativePath);
1564
+ const sassFile = file.replace(/\.css$/, ".sass");
1565
+ const scssFile = file.replace(/\.css$/, ".scss");
1566
+ let targetFile;
1567
+ if (existsSync(sassFile)) {
1568
+ targetFile = sassFile;
1569
+ } else if (existsSync(scssFile)) {
1570
+ targetFile = scssFile;
1571
+ }
1572
+ if (targetFile) {
1573
+ const dir = dirname(cacheFile);
1574
+ if (!existsSync(dir)) {
1575
+ mkdirSync(dir, { recursive: true });
1576
+ }
1577
+ const content = `@use "${normalizePath(configFile)}";
1578
+ @use "${normalizePath(targetFile)}";
1579
+ `;
1580
+ try {
1581
+ const result = sass.compileString(content, {
1582
+ loadPaths: [
1583
+ dirname(configFile),
1584
+ dirname(targetFile),
1585
+ resolve$1(vuetifyBase, ".."),
1586
+ resolve$1(vuetifyBase, "../.."),
1587
+ // In case of monorepo/hoisting issues, but standard is enough
1588
+ vuetifyBase
1589
+ ],
1590
+ url: new URL(pathToFileURL(cacheFile).href)
1591
+ });
1592
+ writeFileSync(cacheFile, result.css, "utf8");
1593
+ } catch (error) {
1594
+ ctx.logger.error(`Failed to compile ${targetFile}:`, error);
1595
+ }
1596
+ }
1597
+ }
1598
+ const metadata = {
1599
+ hash,
1600
+ vuetifyVersion: ctx.vuetifyVersion,
1601
+ viteVersion: ctx.viteVersion,
1602
+ configFile,
1603
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
1604
+ };
1605
+ writeFileSync(join(cacheDir, "metadata.json"), JSON.stringify(metadata, null, 2), "utf8");
1606
+ }
1607
+ function findCssFiles(dir, fileList = []) {
1608
+ if (!existsSync(dir)) {
1609
+ return fileList;
1610
+ }
1611
+ const files = readdirSync(dir);
1612
+ for (const file of files) {
1613
+ const filePath = join(dir, file);
1614
+ const stat = statSync(filePath);
1615
+ if (stat.isDirectory()) {
1616
+ findCssFiles(filePath, fileList);
1617
+ } else {
1618
+ if (file.endsWith(".css")) {
1619
+ fileList.push(filePath);
1620
+ }
1621
+ }
1622
+ }
1623
+ return fileList;
1624
+ }
1625
+
1509
1626
  async function load(options, nuxt, ctx) {
1510
1627
  const {
1511
1628
  configuration,
@@ -1581,6 +1698,7 @@ async function load(options, nuxt, ctx) {
1581
1698
  }
1582
1699
  }
1583
1700
  }
1701
+ await prepareVuetifyStyles(nuxt, ctx);
1584
1702
  }
1585
1703
  function registerWatcher(options, nuxt, ctx) {
1586
1704
  if (nuxt.options.dev) {
@@ -1680,6 +1798,7 @@ const module$1 = defineNuxtModule({
1680
1798
  componentsPromise: void 0,
1681
1799
  labComponentsPromise: void 0,
1682
1800
  vuetifyGte,
1801
+ vuetifyVersion: currentVersion || "0.0.0",
1683
1802
  viteVersion
1684
1803
  };
1685
1804
  await load(options, nuxt, ctx);
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-alpha.4",
4
+ "version": "1.0.0-alpha.5",
5
5
  "description": "Zero-Config Nuxt Module for Vuetify",
6
6
  "author": "userquin <userquin@gmail.com>",
7
7
  "license": "MIT",
@@ -107,6 +107,8 @@
107
107
  "pathe",
108
108
  "perfect-debounce",
109
109
  "rollup",
110
+ "sass",
111
+ "sass-embedded",
110
112
  "upath",
111
113
  "ufo",
112
114
  "unconfig",