@unvuetify/vite-styles-plugin
Version:
Vuetify Vite plugin for styles
147 lines (144 loc) • 5.22 kB
JavaScript
import fs from 'node:fs';
import fsp from 'node:fs/promises';
import process from 'node:process';
import { pathToFileURL } from 'node:url';
import { resolveVuetifyBase } from '@unvuetify/shared';
import { relative, isAbsolute } from 'pathe';
import path from 'upath';
import { version } from 'vite';
function VuetifyStylesVitePlugin(options = {}) {
let configFile;
const vuetifyBase = resolveVuetifyBase();
const noneFiles = /* @__PURE__ */ new Set();
let isNone = false;
let cssVariables = false;
let fileImport = false;
const PREFIX = `${options.viteSSR ? "virtual:" : ""}vuetify-styles/`;
const SSR_PREFIX = options.viteSSR ? `\0${PREFIX}` : `/@${PREFIX}`;
const resolveCss = resolveCssFactory();
const api = options.registerApi ?? "modern-compiler";
const [major, minor, patch] = version.split(".").map((v) => v.includes("-") ? v.split("-")[0] : v).map((v) => Number.parseInt(v));
return {
name: "@unvuetify:vite-styles-plugin",
enforce: "pre",
config(config) {
if (!api)
return null;
if (api === "modern-compiler" || api === "legacy") {
return {
css: {
preprocessorOptions: {
sass: { api },
scss: { api }
}
}
};
}
if (config.css && !("preprocessorMaxWorkers" in config.css)) {
return {
css: {
preprocessorOptions: {
sass: { api },
scss: { api }
}
}
};
}
return {
css: {
preprocessorOptions: {
sass: { api },
scss: { api }
},
preprocessorMaxWorkers: true
}
};
},
configResolved(config) {
if (config.plugins.findIndex((plugin) => plugin.name === "vuetify:styles") > -1)
throw new Error(`The "vite-plugin-vuetify" styles plugin is incompatible with this plugin. Please remove "vite-plugin-vuetify" or set the styles to 'true' in your Vite configuration file.`);
if (isObject(options.mode)) {
cssVariables = true;
fileImport = major > 5 || major === 5 && minor > 4 || major === 5 && minor === 4 && patch > 2;
if (path.isAbsolute(options.mode.configFile))
configFile = path.resolve(options.mode.configFile);
else
configFile = path.resolve(path.join(config.root || process.cwd(), options.mode.configFile));
configFile = fileImport ? pathToFileURL(configFile).href : normalizePath(configFile);
} else {
isNone = options.mode === "none";
}
},
async resolveId(source, importer, { custom, ssr }) {
if (!options.mode)
return void 0;
if (source.startsWith(PREFIX) || source.startsWith(SSR_PREFIX)) {
if (source.match(/\.s[ca]ss$/))
return source;
const idx = source.indexOf("?");
return idx > -1 ? source.slice(0, idx) : source;
}
if (source === "vuetify/styles" || importer && source.endsWith(".css") && isSubdir(vuetifyBase, path.isAbsolute(source) ? source : importer)) {
if (options.mode === "source")
return this.resolve(await resolveCss(source), importer, { skipSelf: true, custom });
const resolution = await this.resolve(source, importer, { skipSelf: true, custom });
if (!resolution)
return void 0;
const target = await resolveCss(resolution.id);
if (isNone) {
noneFiles.add(target);
return target;
}
return `${ssr ? SSR_PREFIX : PREFIX}${path.relative(vuetifyBase, target)}`;
}
return void 0;
},
load(id) {
if (!options.mode)
return void 0;
if (cssVariables) {
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;
if (target) {
const suffix = target.match(/\.scss/) ? ";\n" : "\n";
return {
code: `@use "${configFile}"${suffix}@use "${fileImport ? pathToFileURL(target).href : normalizePath(target)}"${suffix}`,
map: {
mappings: ""
}
};
}
}
return isNone && noneFiles.has(id) ? "" : void 0;
}
};
}
function resolveCssFactory() {
const mappings = /* @__PURE__ */ new Map();
return async (source) => {
let mapping = mappings.get(source);
if (!mapping) {
try {
mapping = source.replace(/\.css$/, ".sass");
await fsp.access(mapping, fs.constants.R_OK);
} catch (err) {
if (!(err instanceof Error && "code" in err && err.code === "ENOENT"))
throw err;
mapping = source.replace(/\.css$/, ".scss");
}
mappings.set(source, mapping);
}
return mapping;
};
}
function isObject(value) {
return value !== null && typeof value === "object";
}
function normalizePath(p) {
p = path.normalize(p);
return /^[a-z]:\//i.test(p) ? `/${p}` : p;
}
function isSubdir(root, test) {
const relative$1 = relative(root, test);
return relative$1 && !relative$1.startsWith("..") && !isAbsolute(relative$1);
}
export { VuetifyStylesVitePlugin };