vuetify-vite-plugin 1.0.0

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 ADDED
@@ -0,0 +1,229 @@
1
+ # vuetify-vite-plugin
2
+
3
+ > Vite plugin for **Vuetify 4** — tree-shaking auto-import, CSS/SASS/configFile
4
+ > style strategies, and Labs support. **Zero dependency on `@vuetify/loader-shared`
5
+ > or `vite-plugin-vuetify`** — a clean, self-contained implementation.
6
+
7
+ ## Why?
8
+
9
+ The official `vite-plugin-vuetify` (v2.x) depends on `@vuetify/loader-shared` which
10
+ currently boots the Vuetify 3 runtime under Vuetify 4, producing unstyled output
11
+ (see [vuetify-loader#352](https://github.com/vuetifyjs/vuetify-loader/issues/352)).
12
+ This plugin reimplements the same transform from scratch, targeting Vuetify 4
13
+ exclusively.
14
+
15
+ ## Requirements
16
+
17
+ | Peer | Version |
18
+ | ------------- | --------------- |
19
+ | `vite` | ≥ 5.0 |
20
+ | `vue` | ^3.4 |
21
+ | `vuetify` | ^4.0 |
22
+ | Node | ^18 or ≥ 20 |
23
+
24
+ ---
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ npm install -D vuetify-vite-plugin
30
+ ```
31
+
32
+ ---
33
+
34
+ ## Usage
35
+
36
+ ### Plain Vite
37
+
38
+ ```ts
39
+ // vite.config.ts
40
+ import { defineConfig } from 'vite'
41
+ import vue from '@vitejs/plugin-vue'
42
+ import vuetify from 'vuetify-vite-plugin'
43
+
44
+ export default defineConfig({
45
+ plugins: [
46
+ // Pass transformAssetUrls so Vite processes image props on Vuetify components
47
+ vue({ template: { transformAssetUrls: vuetify.transformAssetUrls } }),
48
+ // vuetify() MUST come AFTER vue()
49
+ vuetify(),
50
+ ],
51
+ })
52
+ ```
53
+
54
+ ### Nuxt 4
55
+
56
+ ```ts
57
+ // nuxt.config.ts
58
+ export default defineNuxtConfig({
59
+ vite: {
60
+ plugins: [
61
+ // Nuxt already adds the Vue plugin internally — just add vuetify after
62
+ ],
63
+ },
64
+ // Or use a Nuxt module that calls addVitePlugin(vuetify(...))
65
+ })
66
+ ```
67
+
68
+ When used inside a **Nuxt module**, call `addVitePlugin` in your module's
69
+ `setup()`:
70
+
71
+ ```ts
72
+ import { defineNuxtModule, addVitePlugin } from '@nuxt/kit'
73
+ import vuetify from 'vuetify-vite-plugin'
74
+
75
+ export default defineNuxtModule({
76
+ setup (options, nuxt) {
77
+ addVitePlugin(vuetify({
78
+ styles: { configFile: 'assets/styles/vuetify-settings.scss' },
79
+ }))
80
+ },
81
+ })
82
+ ```
83
+
84
+ ---
85
+
86
+ ## Options
87
+
88
+ ```ts
89
+ vuetify({
90
+ autoImport?: boolean | {
91
+ labs?: boolean // include labs components
92
+ ignore?: (keyof Components | keyof Directives)[] // skip specific names
93
+ },
94
+ styles?: true | 'none' | 'sass' | { configFile: string },
95
+ })
96
+ ```
97
+
98
+ ### `autoImport`
99
+
100
+ | Value | Behaviour |
101
+ | --------------- | ---------------------------------------------------- |
102
+ | `true` (default)| Auto-import all stable components + directives |
103
+ | `false` | Disable — you import manually or use a full bundle |
104
+ | `{ labs: true }`| Also auto-import `vuetify/labs` components |
105
+ | `{ ignore: [] }`| Exclude named components / directives |
106
+
107
+ ```ts
108
+ vuetify({
109
+ autoImport: {
110
+ labs: true,
111
+ ignore: ['VDataTable'], // you register this one manually
112
+ },
113
+ })
114
+ ```
115
+
116
+ ### `styles`
117
+
118
+ | Value | Behaviour |
119
+ | ------------------- | ------------------------------------------------------------------ |
120
+ | `true` (default) | Use pre-compiled CSS — fastest, no SASS toolchain needed |
121
+ | `'none'` | Suppress all Vuetify CSS — bring your own |
122
+ | `'sass'` | Use raw `.sass`/`.scss` sources (requires `sass` installed) |
123
+ | `{ configFile }` | Prefix every stylesheet with `@use "your-settings"` (SASS vars) |
124
+
125
+ ```ts
126
+ // SASS variable customisation
127
+ vuetify({
128
+ styles: { configFile: 'src/styles/vuetify-settings.scss' },
129
+ })
130
+ ```
131
+
132
+ ```scss
133
+ // src/styles/vuetify-settings.scss
134
+ @use 'vuetify/settings' with (
135
+ $color-pack: false,
136
+ $utilities: false,
137
+ );
138
+ ```
139
+
140
+ ### `transformAssetUrls`
141
+
142
+ ```ts
143
+ import vuetify from 'vuetify-vite-plugin'
144
+
145
+ // Pass to @vitejs/plugin-vue so Vuetify image props are processed by Vite
146
+ vue({ template: { transformAssetUrls: vuetify.transformAssetUrls } })
147
+ ```
148
+
149
+ Covers: `VAppBar`, `VAvatar`, `VBanner`, `VCard`, `VCardItem`, `VCarouselItem`,
150
+ `VChip`, `VImg`, `VListItem`, `VNavigationDrawer`, `VParallax`, `VToolbar`.
151
+
152
+ ---
153
+
154
+ ## Named Exports
155
+
156
+ ```ts
157
+ import vuetify, {
158
+ // Sub-plugins (for Nuxt modules / custom composition)
159
+ importPlugin,
160
+ stylesPlugin,
161
+
162
+ // Core transform utilities
163
+ generateImports,
164
+ parseTemplate,
165
+
166
+ // Asset URL map
167
+ transformAssetUrls,
168
+ } from 'vuetify-vite-plugin'
169
+
170
+ // Types
171
+ import type {
172
+ Options,
173
+ ImportPluginOptions,
174
+ StylesOption,
175
+ StylesConfigFile,
176
+ ResolvedOptions,
177
+ } from 'vuetify-vite-plugin'
178
+ ```
179
+
180
+ ---
181
+
182
+ ## How it works
183
+
184
+ ### Auto-import (`autoImport`)
185
+
186
+ After the Vue plugin compiles `.vue` files, the compiled JS contains calls like:
187
+
188
+ ```js
189
+ const _component_VBtn = _resolveComponent("VBtn")
190
+ ```
191
+
192
+ `vuetify4:import` intercepts these files, reads `vuetify/dist/json/importMap.json`
193
+ to find each component's subpath export, then:
194
+
195
+ 1. Adds a static import at the top of the file:
196
+ ```js
197
+ import { VBtn as _component_VBtn } from "vuetify/lib/components/VBtn/VBtn.mjs"
198
+ ```
199
+ 2. Blanks out the `_resolveComponent(...)` call (preserving source-map columns).
200
+
201
+ The result: only the components you actually *use* in templates are bundled.
202
+
203
+ ### Styles (`styles`)
204
+
205
+ `vuetify4:styles` (only active for non-default strategies) runs `enforce: 'pre'`
206
+ and intercepts Vuetify's internal `.css` imports via `resolveId`. Depending on
207
+ strategy it either voids the CSS, redirects to the SASS source, or wraps the SASS
208
+ source in a virtual module prefixed with your settings `@use`.
209
+
210
+ ---
211
+
212
+ ## Comparison with `vite-plugin-vuetify`
213
+
214
+ | Feature | `vite-plugin-vuetify` (official) | `vuetify-vite-plugin` |
215
+ | ----------------------------- | -------------------------------- |-----------------------|
216
+ | Vuetify 4 compatible | ❌ (issue #352) | ✅ |
217
+ | `@vuetify/loader-shared` dep | ✅ required | ❌ none |
218
+ | Auto-import + tree-shaking | ✅ | ✅ |
219
+ | CSS / SASS / configFile styles| ✅ | ✅ |
220
+ | Labs components | ✅ | ✅ |
221
+ | `transformAssetUrls` | ✅ | ✅ |
222
+ | Nuxt module friendly | ✅ | ✅ |
223
+ | ESM + CJS dual output | ✅ | ✅ |
224
+
225
+ ---
226
+
227
+ ## License
228
+
229
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,357 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ default: () => index_default,
34
+ generateImports: () => generateImports,
35
+ importPlugin: () => importPlugin,
36
+ parseTemplate: () => parseTemplate,
37
+ stylesPlugin: () => stylesPlugin,
38
+ transformAssetUrls: () => transformAssetUrls
39
+ });
40
+ module.exports = __toCommonJS(index_exports);
41
+
42
+ // src/types.ts
43
+ function resolveOptions(raw) {
44
+ const autoImport = raw.autoImport === false ? false : raw.autoImport === true || raw.autoImport == null ? {} : raw.autoImport;
45
+ return {
46
+ autoImport,
47
+ styles: raw.styles ?? true
48
+ };
49
+ }
50
+
51
+ // src/importPlugin.ts
52
+ var import_vite = require("vite");
53
+
54
+ // src/imports/parseTemplate.ts
55
+ var import_vue = require("vue");
56
+ function parseTemplate(source) {
57
+ const components = collectMatches(
58
+ source.matchAll(/(?:var|const) (\w+) *?= *?_resolveComponent\("([\w-.]+)"\);?/gm)
59
+ );
60
+ const directives = collectMatches(
61
+ source.matchAll(/(?:var|const) (\w+) *?= *?_resolveDirective\("([\w-.]+)"\);?/gm)
62
+ );
63
+ return { components, directives };
64
+ }
65
+ function collectMatches(iter) {
66
+ return new Set(
67
+ Array.from(iter, (m) => ({
68
+ symbol: m[1],
69
+ name: (0, import_vue.capitalize)((0, import_vue.camelize)(m[2])),
70
+ index: m.index,
71
+ length: m[0].length
72
+ }))
73
+ );
74
+ }
75
+
76
+ // src/utils.ts
77
+ var import_node_module = require("module");
78
+ var import_node_path = __toESM(require("path"), 1);
79
+ var _require = (0, import_node_module.createRequire)(__filename);
80
+ function resolveVuetifyBase() {
81
+ return import_node_path.default.dirname(
82
+ _require.resolve("vuetify/package.json", { paths: [process.cwd()] })
83
+ );
84
+ }
85
+ function loadImportMap() {
86
+ return _require("vuetify/dist/json/importMap.json");
87
+ }
88
+ function loadImportMapLabs() {
89
+ return _require("vuetify/dist/json/importMap-labs.json");
90
+ }
91
+ function normalizePath(p) {
92
+ p = import_node_path.default.normalize(p).replace(/\\/g, "/");
93
+ if (/^[a-z]:\//i.test(p)) p = "/" + p;
94
+ return p;
95
+ }
96
+ function isObject(value) {
97
+ return value !== null && typeof value === "object";
98
+ }
99
+ function isSubdir(root, test) {
100
+ const rel = import_node_path.default.relative(root, test);
101
+ return !!rel && !rel.startsWith("..") && !import_node_path.default.isAbsolute(rel);
102
+ }
103
+
104
+ // src/imports/getImports.ts
105
+ function getImports(source, options) {
106
+ const importMap = loadImportMap();
107
+ const importMapLabs = loadImportMapLabs();
108
+ const { components, directives } = parseTemplate(source);
109
+ const resolvedComponents = [];
110
+ const resolvedDirectives = [];
111
+ const imports = /* @__PURE__ */ new Map();
112
+ const ignore = options.ignore ?? null;
113
+ const includeLabs = !!options.labs;
114
+ const componentMap = includeLabs ? { ...importMap.components, ...importMapLabs.components } : { ...importMap.components };
115
+ components.forEach((c) => {
116
+ if (ignore?.includes(c.name)) return;
117
+ if (c.name in componentMap) resolvedComponents.push(c);
118
+ });
119
+ directives.forEach((d) => {
120
+ if (importMap.directives.includes(d.name) && !ignore?.includes(d.name)) {
121
+ resolvedDirectives.push(d);
122
+ }
123
+ });
124
+ resolvedComponents.forEach((c) => {
125
+ const { from } = componentMap[c.name];
126
+ const specifier = from.endsWith(".mjs") ? `vuetify/lib/${from}` : `vuetify/${from}`;
127
+ addImport(imports, c.name, c.symbol, specifier);
128
+ });
129
+ resolvedDirectives.forEach((d) => {
130
+ addImport(imports, d.name, d.symbol, "vuetify/directives");
131
+ });
132
+ return { imports, components: resolvedComponents, directives: resolvedDirectives };
133
+ }
134
+ function addImport(imports, name, as, from) {
135
+ if (!imports.has(from)) imports.set(from, []);
136
+ imports.get(from).push(`${name} as ${as}`);
137
+ }
138
+
139
+ // src/imports/generateImports.ts
140
+ function generateImports(source, options) {
141
+ const { imports, components, directives } = getImports(source, options);
142
+ let code = "";
143
+ if (components.length || directives.length) {
144
+ code += "\n\n/* Vuetify */\n";
145
+ Array.from(imports).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).forEach(([from, names]) => {
146
+ code += `import { ${names.join(", ")} } from "${from}"
147
+ `;
148
+ });
149
+ code += "\n";
150
+ source = [...components, ...directives].reduce((acc, v) => {
151
+ return acc.slice(0, v.index) + " ".repeat(v.length) + acc.slice(v.index + v.length);
152
+ }, source);
153
+ if (!source.includes("_resolveComponent(")) {
154
+ source = source.replace("resolveComponent as _resolveComponent, ", "");
155
+ }
156
+ if (!source.includes("_resolveDirective(")) {
157
+ source = source.replace("resolveDirective as _resolveDirective, ", "");
158
+ }
159
+ }
160
+ return { code, source };
161
+ }
162
+
163
+ // src/importPlugin.ts
164
+ function parseId(id) {
165
+ const [pathname, query] = id.split("?");
166
+ return {
167
+ path: pathname ?? id,
168
+ query: query ? Object.fromEntries(new URLSearchParams(query)) : null
169
+ };
170
+ }
171
+ function importPlugin(options) {
172
+ const importOptions = options.autoImport;
173
+ let filter = () => true;
174
+ return {
175
+ name: "vuetify4:import",
176
+ configResolved(config) {
177
+ const selfIdx = config.plugins.findIndex((p) => p.name === "vuetify4:import");
178
+ const vueIdx = config.plugins.findIndex(
179
+ (p) => ["vite:vue", "unplugin-vue"].includes(p.name)
180
+ );
181
+ if (vueIdx === -1) {
182
+ config.logger.warn(
183
+ "[vite-plugin-vuetify4] No Vue plugin found \u2014 auto-import is a no-op. Add @vitejs/plugin-vue (Nuxt provides this automatically)."
184
+ );
185
+ return;
186
+ }
187
+ if (selfIdx !== -1 && selfIdx < vueIdx) {
188
+ throw new Error(
189
+ "[vite-plugin-vuetify4] This plugin must be registered AFTER the Vue plugin. Move it below `vue()` in your plugins array."
190
+ );
191
+ }
192
+ const vuePlugin = config.plugins[vueIdx];
193
+ const vueOptions = vuePlugin?.api?.options ?? {};
194
+ filter = (0, import_vite.createFilter)(vueOptions.include, vueOptions.exclude);
195
+ },
196
+ transform(code, id) {
197
+ const { path, query } = parseId(id);
198
+ const isVueVirtual = !!query && "vue" in query;
199
+ const isVueFile = !isVueVirtual && filter(path) && // Skip render-only re-export stubs that the Vue plugin emits
200
+ !/^import \{ render as _sfc_render \} from ".*"$/m.test(code);
201
+ const isVueTemplate = isVueVirtual && (query.type === "template" || query.type === "script" && query.setup === "true");
202
+ if (isVueFile || isVueTemplate) {
203
+ const { code: importCode, source } = generateImports(code, importOptions);
204
+ return { code: source + importCode, map: null };
205
+ }
206
+ return null;
207
+ }
208
+ };
209
+ }
210
+
211
+ // src/stylesPlugin.ts
212
+ var import_node_path2 = __toESM(require("path"), 1);
213
+ var import_promises = __toESM(require("fs/promises"), 1);
214
+ var VIRTUAL_PREFIX = "virtual:";
215
+ var PLUGIN_VIRTUAL_NAME = "plugin-vuetify4";
216
+ var VIRTUAL_MODULE_ID = `${VIRTUAL_PREFIX}${PLUGIN_VIRTUAL_NAME}`;
217
+ function stylesPlugin(options) {
218
+ const vuetifyBase = resolveVuetifyBase();
219
+ let configFile = "";
220
+ const tempFiles = /* @__PURE__ */ new Map();
221
+ const cssToSass = /* @__PURE__ */ new Map();
222
+ async function resolveSass(target) {
223
+ let cached = cssToSass.get(target);
224
+ if (!cached) {
225
+ cached = target.replace(/\.css$/, ".sass");
226
+ try {
227
+ await import_promises.default.access(cached, import_promises.default.constants.R_OK);
228
+ } catch (err) {
229
+ if (err instanceof Error && "code" in err && err.code === "ENOENT") {
230
+ cached = target.replace(/\.css$/, ".scss");
231
+ } else {
232
+ throw err;
233
+ }
234
+ }
235
+ cssToSass.set(target, cached);
236
+ }
237
+ return cached;
238
+ }
239
+ return {
240
+ name: "vuetify4:styles",
241
+ enforce: "pre",
242
+ // Must run before Vite's default CSS resolution
243
+ configResolved(config) {
244
+ if (isObject(options.styles) && "configFile" in options.styles) {
245
+ const cf = options.styles.configFile;
246
+ configFile = import_node_path2.default.isAbsolute(cf) ? cf : import_node_path2.default.join(config.root || process.cwd(), cf);
247
+ }
248
+ },
249
+ async resolveId(source, importer, ctx) {
250
+ const isVuetifyStyles = source === "vuetify/styles" || importer && source.endsWith(".css") && isSubdir(
251
+ vuetifyBase,
252
+ import_node_path2.default.isAbsolute(source) ? source : importer
253
+ );
254
+ if (isVuetifyStyles) {
255
+ if (options.styles === "none") {
256
+ return `${VIRTUAL_PREFIX}__void__`;
257
+ }
258
+ if (options.styles === "sass") {
259
+ const resolution = await this.resolve(source, importer, {
260
+ skipSelf: true,
261
+ custom: ctx.custom
262
+ });
263
+ if (!resolution) return null;
264
+ return resolveSass(resolution.id);
265
+ }
266
+ if (isObject(options.styles) && "configFile" in options.styles) {
267
+ const resolution = await this.resolve(source, importer, {
268
+ skipSelf: true,
269
+ custom: ctx.custom
270
+ });
271
+ if (!resolution) return null;
272
+ const sassFile = await resolveSass(resolution.id);
273
+ const relFile = import_node_path2.default.relative(import_node_path2.default.join(vuetifyBase, "lib"), sassFile);
274
+ const suffix = sassFile.endsWith(".scss") ? ";\n" : "\n";
275
+ const contents = `@use "${normalizePath(configFile)}"${suffix}@use "${normalizePath(sassFile)}"${suffix}`;
276
+ tempFiles.set(relFile, contents);
277
+ return `${VIRTUAL_MODULE_ID}:${relFile}`;
278
+ }
279
+ }
280
+ if (source.startsWith(`/${PLUGIN_VIRTUAL_NAME}:`)) {
281
+ return VIRTUAL_PREFIX + source.slice(1);
282
+ }
283
+ if (source.startsWith(`/@id/__x00__${PLUGIN_VIRTUAL_NAME}:`)) {
284
+ return VIRTUAL_PREFIX + source.slice(12);
285
+ }
286
+ if (source.startsWith(`/${VIRTUAL_MODULE_ID}:`)) {
287
+ return source.slice(1);
288
+ }
289
+ return null;
290
+ },
291
+ load(id) {
292
+ if (new RegExp(`^${VIRTUAL_PREFIX}__void__(\\?.*)?$`).test(id)) {
293
+ return "";
294
+ }
295
+ if (id.startsWith(VIRTUAL_MODULE_ID)) {
296
+ const file = new RegExp(`^${VIRTUAL_MODULE_ID}:(.*?)(\\?.*)?$`).exec(id)?.[1];
297
+ if (file) return tempFiles.get(file) ?? null;
298
+ }
299
+ return null;
300
+ }
301
+ };
302
+ }
303
+
304
+ // src/index.ts
305
+ function toKebabCase(str = "") {
306
+ return str.replace(/[^a-z]/gi, "-").replace(/\B([A-Z])/g, "-$1").toLowerCase();
307
+ }
308
+ var _transformAssetUrls = {
309
+ VAppBar: ["image"],
310
+ VAvatar: ["image"],
311
+ VBanner: ["avatar"],
312
+ VCard: ["image", "prependAvatar", "appendAvatar"],
313
+ VCardItem: ["prependAvatar", "appendAvatar"],
314
+ VCarouselItem: ["src", "lazySrc", "srcset"],
315
+ VChip: ["prependAvatar", "appendAvatar"],
316
+ VImg: ["src", "lazySrc", "srcset"],
317
+ VListItem: ["prependAvatar", "appendAvatar"],
318
+ VNavigationDrawer: ["image"],
319
+ VParallax: ["src", "lazySrc", "srcset"],
320
+ VToolbar: ["image"]
321
+ };
322
+ for (const [tag, attrs] of Object.entries(_transformAssetUrls)) {
323
+ attrs.forEach((attr) => {
324
+ if (/[A-Z]/.test(attr)) attrs.push(toKebabCase(attr));
325
+ });
326
+ _transformAssetUrls[toKebabCase(tag)] = attrs;
327
+ }
328
+ Object.assign(_transformAssetUrls, {
329
+ video: ["src", "poster"],
330
+ source: ["src"],
331
+ img: ["src"],
332
+ image: ["xlink:href", "href"],
333
+ use: ["xlink:href", "href"]
334
+ });
335
+ var transformAssetUrls = _transformAssetUrls;
336
+ function vuetify(rawOptions = {}) {
337
+ const options = resolveOptions(rawOptions);
338
+ const plugins = [];
339
+ if (options.autoImport !== false) {
340
+ plugins.push(importPlugin(options));
341
+ }
342
+ if (options.styles === "none" || options.styles === "sass" || typeof options.styles === "object" && "configFile" in options.styles) {
343
+ plugins.push(stylesPlugin(options));
344
+ }
345
+ return plugins;
346
+ }
347
+ vuetify.transformAssetUrls = transformAssetUrls;
348
+ var index_default = vuetify;
349
+ // Annotate the CommonJS export names for ESM import in node:
350
+ 0 && (module.exports = {
351
+ generateImports,
352
+ importPlugin,
353
+ parseTemplate,
354
+ stylesPlugin,
355
+ transformAssetUrls
356
+ });
357
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/importPlugin.ts","../src/imports/parseTemplate.ts","../src/utils.ts","../src/imports/getImports.ts","../src/imports/generateImports.ts","../src/stylesPlugin.ts"],"sourcesContent":["import type { Plugin } from 'vite'\nimport { resolveOptions } from './types'\nimport { importPlugin } from './importPlugin'\nimport { stylesPlugin } from './stylesPlugin'\nimport type { Options } from './types'\n\n// ─── transformAssetUrls ───────────────────────────────────────────────────────\n// Tells @vitejs/plugin-vue which Vuetify component props carry asset URLs\n// (images, posters, etc.) so Vite can process them as static assets.\n// Mirrors the official plugin's export exactly.\n\nfunction toKebabCase (str = '') {\n return str\n .replace(/[^a-z]/gi, '-')\n .replace(/\\B([A-Z])/g, '-$1')\n .toLowerCase()\n}\n\nconst _transformAssetUrls: Record<string, string[]> = {\n VAppBar: ['image'],\n VAvatar: ['image'],\n VBanner: ['avatar'],\n VCard: ['image', 'prependAvatar', 'appendAvatar'],\n VCardItem: ['prependAvatar', 'appendAvatar'],\n VCarouselItem: ['src', 'lazySrc', 'srcset'],\n VChip: ['prependAvatar', 'appendAvatar'],\n VImg: ['src', 'lazySrc', 'srcset'],\n VListItem: ['prependAvatar', 'appendAvatar'],\n VNavigationDrawer:['image'],\n VParallax: ['src', 'lazySrc', 'srcset'],\n VToolbar: ['image'],\n}\n\n// Add kebab-case aliases and default HTML tag attrs\nfor (const [tag, attrs] of Object.entries(_transformAssetUrls)) {\n attrs.forEach(attr => {\n if (/[A-Z]/.test(attr)) attrs.push(toKebabCase(attr))\n })\n _transformAssetUrls[toKebabCase(tag)] = attrs\n}\nObject.assign(_transformAssetUrls, {\n video: ['src', 'poster'],\n source: ['src'],\n img: ['src'],\n image: ['xlink:href', 'href'],\n use: ['xlink:href', 'href'],\n})\n\nexport const transformAssetUrls = _transformAssetUrls\n\n// ─── Main plugin factory ──────────────────────────────────────────────────────\n\n/**\n * `vite-plugin-vuetify4`\n *\n * Drop-in Vite plugin for Vuetify 4 with:\n * - Tree-shaking auto-import (no `@vuetify/loader-shared` dependency)\n * - CSS / SASS / configFile style strategies\n * - Lab component support\n * - `transformAssetUrls` for @vitejs/plugin-vue\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { defineConfig } from 'vite'\n * import vue from '@vitejs/plugin-vue'\n * import vuetify from 'vite-plugin-vuetify4'\n *\n * export default defineConfig({\n * plugins: [\n * vue({ template: { transformAssetUrls: vuetify.transformAssetUrls } }),\n * vuetify({ styles: { configFile: 'src/styles/settings.scss' } }),\n * ],\n * })\n * ```\n */\nfunction vuetify (rawOptions: Options = {}): Plugin[] {\n const options = resolveOptions(rawOptions)\n const plugins: Plugin[] = []\n\n if (options.autoImport !== false) {\n plugins.push(importPlugin(options))\n }\n\n // Style plugin is only needed for non-default strategies\n if (\n options.styles === 'none' ||\n options.styles === 'sass' ||\n (typeof options.styles === 'object' && 'configFile' in options.styles)\n ) {\n plugins.push(stylesPlugin(options))\n }\n\n return plugins\n}\n\nvuetify.transformAssetUrls = transformAssetUrls\n\nexport default vuetify\n\n// Named exports for Nuxt module / programmatic usage\nexport type { Options, ImportPluginOptions, StylesOption, StylesConfigFile, ResolvedOptions } from './types'\nexport { importPlugin } from './importPlugin'\nexport { stylesPlugin } from './stylesPlugin'\nexport { generateImports } from './imports/generateImports'\nexport { parseTemplate } from './imports/parseTemplate'\n","import type * as Components from 'vuetify/components'\nimport type * as Directives from 'vuetify/directives'\n\n// ─── Auto-import options ──────────────────────────────────────────────────────\n\nexport interface ImportPluginOptions {\n /**\n * Include Vuetify Labs components (`vuetify/labs/*`).\n * @default false\n */\n labs?: boolean\n /**\n * Component or directive names to exclude from auto-import.\n * Useful when you want to manually register a component with a custom impl.\n */\n ignore?: (keyof typeof Components | keyof typeof Directives)[]\n}\n\n// ─── Styles options ───────────────────────────────────────────────────────────\n\nexport interface StylesConfigFile {\n /**\n * Path to a SASS/SCSS config file that is @use-d before every Vuetify\n * component stylesheet. Relative to `vite.config` root, or absolute.\n *\n * Example:\n * ```ts\n * styles: { configFile: 'src/styles/vuetify-settings.scss' }\n * ```\n */\n configFile: string\n}\n\n/**\n * How to handle Vuetify stylesheets:\n * - `true` — use the pre-compiled CSS (default, fastest)\n * - `'none'` — suppress all Vuetify CSS (you bring your own)\n * - `'sass'` — use the raw SASS/SCSS sources (requires sass)\n * - `{ configFile }` — use SASS sources prefixed with your settings file\n */\nexport type StylesOption = true | 'none' | 'sass' | StylesConfigFile\n\n// ─── Top-level options ────────────────────────────────────────────────────────\n\nexport interface Options {\n /**\n * Enable/configure component + directive auto-import with tree-shaking.\n * - `true` — auto-import everything (default)\n * - `false` — disable (you import manually or use a full bundle)\n * - `{ labs, ignore }` — fine-grained control\n */\n autoImport?: boolean | ImportPluginOptions\n\n /**\n * Stylesheet handling strategy.\n * @default true\n */\n styles?: StylesOption\n}\n\n// ─── Internal resolved types ──────────────────────────────────────────────────\n\nexport interface ResolvedOptions {\n autoImport: false | ImportPluginOptions\n styles: StylesOption\n}\n\nexport function resolveOptions (raw: Options): ResolvedOptions {\n const autoImport: ResolvedOptions['autoImport'] =\n raw.autoImport === false\n ? false\n : raw.autoImport === true || raw.autoImport == null\n ? {}\n : raw.autoImport\n\n return {\n autoImport,\n styles: raw.styles ?? true,\n }\n}\n","import { createFilter } from 'vite'\nimport type { Plugin, ResolvedConfig } from 'vite'\nimport { generateImports } from './imports/generateImports'\nimport type { ResolvedOptions } from './types'\n\nfunction parseId (id: string) {\n const [pathname, query] = id.split('?')\n return {\n path: pathname ?? id,\n query: query ? Object.fromEntries(new URLSearchParams(query)) : null,\n }\n}\n\n/**\n * `vuetify4:import`\n *\n * Intercepts every compiled Vue file / template chunk and replaces dynamic\n * `_resolveComponent(...)` calls with static tree-shakeable imports from the\n * Vuetify package.\n *\n * Must be placed AFTER the Vue plugin in the plugins array (enforced at\n * `configResolved` time).\n */\nexport function importPlugin (options: ResolvedOptions): Plugin {\n // Narrowed: if we reach here, autoImport is not false\n const importOptions = options.autoImport as Exclude<ResolvedOptions['autoImport'], false>\n let filter: (id: unknown) => boolean = () => true\n\n return {\n name: 'vuetify4:import',\n\n configResolved (config: ResolvedConfig) {\n const selfIdx = config.plugins.findIndex(p => p.name === 'vuetify4:import')\n const vueIdx = config.plugins.findIndex(p =>\n ['vite:vue', 'unplugin-vue'].includes(p.name)\n )\n\n if (vueIdx === -1) {\n config.logger.warn(\n '[vite-plugin-vuetify4] No Vue plugin found — ' +\n 'auto-import is a no-op. Add @vitejs/plugin-vue ' +\n '(Nuxt provides this automatically).'\n )\n return\n }\n\n if (selfIdx !== -1 && selfIdx < vueIdx) {\n throw new Error(\n '[vite-plugin-vuetify4] This plugin must be registered AFTER the Vue plugin. ' +\n 'Move it below `vue()` in your plugins array.'\n )\n }\n\n const vuePlugin = config.plugins[vueIdx] as any\n const vueOptions = vuePlugin?.api?.options ?? {}\n filter = createFilter(vueOptions.include, vueOptions.exclude)\n },\n\n transform (code, id) {\n const { path, query } = parseId(id)\n\n // A virtual sub-request appended by the Vue plugin (e.g. ?vue&type=template)\n const isVueVirtual = !!query && 'vue' in query\n const isVueFile =\n !isVueVirtual &&\n filter(path) &&\n // Skip render-only re-export stubs that the Vue plugin emits\n !/^import \\{ render as _sfc_render \\} from \".*\"$/m.test(code)\n const isVueTemplate =\n isVueVirtual &&\n (query!.type === 'template' ||\n (query!.type === 'script' && query!.setup === 'true'))\n\n if (isVueFile || isVueTemplate) {\n const { code: importCode, source } = generateImports(code, importOptions)\n return { code: source + importCode, map: null }\n }\n\n return null\n },\n }\n}\n","import { camelize, capitalize } from 'vue'\n\nexport interface TemplateMatch {\n /** The local JS symbol name, e.g. `_component_VBtn` */\n symbol: string\n /** PascalCase component/directive name, e.g. `VBtn` */\n name: string\n /** Byte offset of the match inside the source string */\n index: number\n /** Byte length of the matched substring */\n length: number\n}\n\n/**\n * Parse compiled Vue template code for `_resolveComponent(...)` and\n * `_resolveDirective(...)` calls and return typed match sets.\n *\n * The regex patterns mirror those in `@vuetify/loader-shared` exactly so\n * behaviour is identical.\n */\nexport function parseTemplate (source: string) {\n const components = collectMatches(\n source.matchAll(/(?:var|const) (\\w+) *?= *?_resolveComponent\\(\"([\\w-.]+)\"\\);?/gm)\n )\n const directives = collectMatches(\n source.matchAll(/(?:var|const) (\\w+) *?= *?_resolveDirective\\(\"([\\w-.]+)\"\\);?/gm)\n )\n return { components, directives }\n}\n\nfunction collectMatches (\n iter: IterableIterator<RegExpMatchArray>\n): Set<TemplateMatch> {\n return new Set(\n Array.from(iter, m => ({\n symbol: m[1],\n name: capitalize(camelize(m[2])),\n index: m.index!,\n length: m[0].length,\n }))\n )\n}\n","import { createRequire } from 'node:module'\nimport nodePath from 'node:path'\n\n// `__filename` is available in both output formats:\n// - CJS: provided natively by Node\n// - ESM: shimmed from `import.meta.url` via the tsup banner\nconst _require = createRequire(__filename)\n\n/**\n * Resolves the directory of the installed `vuetify` package.\n */\nexport function resolveVuetifyBase (): string {\n return nodePath.dirname(\n _require.resolve('vuetify/package.json', { paths: [process.cwd()] })\n )\n}\n\nexport function loadImportMap () {\n return _require('vuetify/dist/json/importMap.json') as ImportMap\n}\n\nexport function loadImportMapLabs () {\n return _require('vuetify/dist/json/importMap-labs.json') as ImportMap\n}\n\nexport interface ImportMap {\n components: Record<string, { from: string }>\n directives: string[]\n}\n\n/** Forward-slash paths on Windows for Vite/esbuild compatibility. */\nexport function normalizePath (p: string): string {\n p = nodePath.normalize(p).replace(/\\\\/g, '/')\n if (/^[a-z]:\\//i.test(p)) p = '/' + p\n return p\n}\n\nexport function isObject (value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object'\n}\n\nexport function isSubdir (root: string, test: string): boolean {\n const rel = nodePath.relative(root, test)\n return !!rel && !rel.startsWith('..') && !nodePath.isAbsolute(rel)\n}\n","import { parseTemplate } from './parseTemplate'\nimport { loadImportMap, loadImportMapLabs } from '../utils'\nimport type { TemplateMatch } from './parseTemplate'\nimport type { ImportPluginOptions } from '../types'\n\n/**\n * Given compiled Vue template source, returns:\n * - `imports` Map<from-specifier, [\"Name as _symbol\", ...]>\n * - `components` matched component descriptors (for source-rewriting)\n * - `directives` matched directive descriptors (for source-rewriting)\n */\nexport function getImports (source: string, options: ImportPluginOptions) {\n const importMap = loadImportMap()\n const importMapLabs = loadImportMapLabs()\n\n const { components, directives } = parseTemplate(source)\n const resolvedComponents: TemplateMatch[] = []\n const resolvedDirectives: TemplateMatch[] = []\n const imports = new Map<string, string[]>()\n\n const ignore = options.ignore ?? null\n const includeLabs = !!options.labs\n\n // Merge labs into the lookup when requested\n const componentMap: Record<string, { from: string }> = includeLabs\n ? { ...importMap.components, ...importMapLabs.components }\n : { ...importMap.components }\n\n components.forEach(c => {\n if (ignore?.includes(c.name as never)) return\n if (c.name in componentMap) resolvedComponents.push(c)\n })\n\n directives.forEach(d => {\n if (importMap.directives.includes(d.name) && !ignore?.includes(d.name as never)) {\n resolvedDirectives.push(d)\n }\n })\n\n resolvedComponents.forEach(c => {\n const { from } = componentMap[c.name]\n // Vuetify ≥3.7.11 / v4: `from` ends in `.mjs` and is a subpath export.\n // Older builds use a bare lib path.\n const specifier = from.endsWith('.mjs') ? `vuetify/lib/${from}` : `vuetify/${from}`\n addImport(imports, c.name, c.symbol, specifier)\n })\n\n resolvedDirectives.forEach(d => {\n addImport(imports, d.name, d.symbol, 'vuetify/directives')\n })\n\n return { imports, components: resolvedComponents, directives: resolvedDirectives }\n}\n\nfunction addImport (\n imports: Map<string, string[]>,\n name: string,\n as: string,\n from: string\n) {\n if (!imports.has(from)) imports.set(from, [])\n imports.get(from)!.push(`${name} as ${as}`)\n}\n","import { getImports } from './getImports'\nimport type { ImportPluginOptions } from '../types'\n\n/**\n * Core transform: given compiled Vue template `source`, generates static\n * Vuetify import statements and erases the `_resolveComponent(...)` /\n * `_resolveDirective(...)` declarations those imports replace.\n *\n * Returns `{ code, source }` where:\n * - `source` is the (possibly mutated) original code with dynamic-resolve\n * calls blanked out (spaces, preserving source-map columns).\n * - `code` is the new import block to prepend / append.\n */\nexport function generateImports (\n source: string,\n options: ImportPluginOptions\n): { code: string; source: string } {\n const { imports, components, directives } = getImports(source, options)\n\n let code = ''\n\n if (components.length || directives.length) {\n code += '\\n\\n/* Vuetify */\\n'\n\n // Sort import specifiers alphabetically for deterministic output\n Array.from(imports)\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n .forEach(([from, names]) => {\n code += `import { ${names.join(', ')} } from \"${from}\"\\n`\n })\n\n code += '\\n'\n\n // Replace matched substrings with spaces to preserve source-map columns\n source = [...components, ...directives].reduce((acc, v) => {\n return acc.slice(0, v.index) + ' '.repeat(v.length) + acc.slice(v.index + v.length)\n }, source)\n\n // If all resolveComponent / resolveDirective calls are gone, also strip\n // the named imports from the Vue runtime import at the top of the file.\n if (!source.includes('_resolveComponent(')) {\n source = source.replace('resolveComponent as _resolveComponent, ', '')\n }\n if (!source.includes('_resolveDirective(')) {\n source = source.replace('resolveDirective as _resolveDirective, ', '')\n }\n }\n\n return { code, source }\n}\n","import nodePath from 'node:path'\nimport fs from 'node:fs/promises'\nimport { resolveVuetifyBase, normalizePath, isObject, isSubdir } from './utils'\nimport type { Plugin, ResolvedConfig } from 'vite'\nimport type { ResolvedOptions, StylesConfigFile } from './types'\n\nconst VIRTUAL_PREFIX = 'virtual:'\nconst PLUGIN_VIRTUAL_NAME = 'plugin-vuetify4'\nconst VIRTUAL_MODULE_ID = `${VIRTUAL_PREFIX}${PLUGIN_VIRTUAL_NAME}`\n\n/**\n * `vuetify4:styles`\n *\n * Intercepts Vuetify's internal `.css` imports and redirects them according to\n * `options.styles`:\n *\n * - `'none'` → return empty module (suppress all Vuetify CSS)\n * - `'sass'` → resolve to the companion `.sass` / `.scss` source\n * - `{ configFile }` → prefix every component stylesheet with `@use configFile`\n *\n * When `styles: true` (default), this plugin is not added at all — Vite\n * handles the pre-compiled CSS normally.\n */\nexport function stylesPlugin (options: ResolvedOptions): Plugin {\n const vuetifyBase = resolveVuetifyBase()\n\n let configFile = ''\n // Virtual file contents keyed by relative path (configFile strategy)\n const tempFiles = new Map<string, string>()\n // Cache css → sass/scss path resolutions\n const cssToSass = new Map<string, string>()\n\n async function resolveSass (target: string): Promise<string> {\n let cached = cssToSass.get(target)\n if (!cached) {\n cached = target.replace(/\\.css$/, '.sass')\n try {\n await fs.access(cached, fs.constants.R_OK)\n } catch (err) {\n // Fallback to .scss\n if (err instanceof Error && 'code' in err && (err as NodeJS.ErrnoException).code === 'ENOENT') {\n cached = target.replace(/\\.css$/, '.scss')\n } else {\n throw err\n }\n }\n cssToSass.set(target, cached)\n }\n return cached\n }\n\n return {\n name: 'vuetify4:styles',\n enforce: 'pre', // Must run before Vite's default CSS resolution\n\n configResolved (config: ResolvedConfig) {\n if (isObject(options.styles) && 'configFile' in options.styles) {\n const cf = (options.styles as StylesConfigFile).configFile\n configFile = nodePath.isAbsolute(cf)\n ? cf\n : nodePath.join(config.root || process.cwd(), cf)\n }\n },\n\n async resolveId (source, importer, ctx) {\n const isVuetifyStyles =\n source === 'vuetify/styles' ||\n (\n importer &&\n source.endsWith('.css') &&\n isSubdir(\n vuetifyBase,\n nodePath.isAbsolute(source) ? source : importer\n )\n )\n\n if (isVuetifyStyles) {\n // ── Strategy: none ────────────────────────────────────────────────────\n if (options.styles === 'none') {\n return `${VIRTUAL_PREFIX}__void__`\n }\n\n // ── Strategy: sass ────────────────────────────────────────────────────\n if (options.styles === 'sass') {\n const resolution = await this.resolve(source, importer, {\n skipSelf: true,\n custom: ctx.custom,\n })\n if (!resolution) return null\n return resolveSass(resolution.id)\n }\n\n // ── Strategy: { configFile } ──────────────────────────────────────────\n if (isObject(options.styles) && 'configFile' in options.styles) {\n const resolution = await this.resolve(source, importer, {\n skipSelf: true,\n custom: ctx.custom,\n })\n if (!resolution) return null\n\n const sassFile = await resolveSass(resolution.id)\n const relFile = nodePath.relative(nodePath.join(vuetifyBase, 'lib'), sassFile)\n const suffix = sassFile.endsWith('.scss') ? ';\\n' : '\\n'\n const contents =\n `@use \"${normalizePath(configFile)}\"${suffix}` +\n `@use \"${normalizePath(sassFile)}\"${suffix}`\n\n tempFiles.set(relFile, contents)\n return `${VIRTUAL_MODULE_ID}:${relFile}`\n }\n }\n\n // ── Vite SSR virtual re-entry aliases ─────────────────────────────────\n if (source.startsWith(`/${PLUGIN_VIRTUAL_NAME}:`)) {\n return VIRTUAL_PREFIX + source.slice(1)\n }\n if (source.startsWith(`/@id/__x00__${PLUGIN_VIRTUAL_NAME}:`)) {\n return VIRTUAL_PREFIX + source.slice(12)\n }\n if (source.startsWith(`/${VIRTUAL_MODULE_ID}:`)) {\n return source.slice(1)\n }\n\n return null\n },\n\n load (id) {\n // __void__ — suppress CSS (styles: 'none')\n // Vite may append a version hash: `?v=abc123`\n if (new RegExp(`^${VIRTUAL_PREFIX}__void__(\\\\?.*)?$`).test(id)) {\n return ''\n }\n\n // Virtual config-prefixed sass files\n if (id.startsWith(VIRTUAL_MODULE_ID)) {\n const file = new RegExp(`^${VIRTUAL_MODULE_ID}:(.*?)(\\\\?.*)?$`).exec(id)?.[1]\n if (file) return tempFiles.get(file) ?? null\n }\n\n return null\n },\n }\n}\n"],"mappings":"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","names":["nodePath","import_node_path","fs","nodePath"]}
@@ -0,0 +1,150 @@
1
+ import { Plugin } from 'vite';
2
+ import * as Components from 'vuetify/components';
3
+ import * as Directives from 'vuetify/directives';
4
+
5
+ interface ImportPluginOptions {
6
+ /**
7
+ * Include Vuetify Labs components (`vuetify/labs/*`).
8
+ * @default false
9
+ */
10
+ labs?: boolean;
11
+ /**
12
+ * Component or directive names to exclude from auto-import.
13
+ * Useful when you want to manually register a component with a custom impl.
14
+ */
15
+ ignore?: (keyof typeof Components | keyof typeof Directives)[];
16
+ }
17
+ interface StylesConfigFile {
18
+ /**
19
+ * Path to a SASS/SCSS config file that is @use-d before every Vuetify
20
+ * component stylesheet. Relative to `vite.config` root, or absolute.
21
+ *
22
+ * Example:
23
+ * ```ts
24
+ * styles: { configFile: 'src/styles/vuetify-settings.scss' }
25
+ * ```
26
+ */
27
+ configFile: string;
28
+ }
29
+ /**
30
+ * How to handle Vuetify stylesheets:
31
+ * - `true` — use the pre-compiled CSS (default, fastest)
32
+ * - `'none'` — suppress all Vuetify CSS (you bring your own)
33
+ * - `'sass'` — use the raw SASS/SCSS sources (requires sass)
34
+ * - `{ configFile }` — use SASS sources prefixed with your settings file
35
+ */
36
+ type StylesOption = true | 'none' | 'sass' | StylesConfigFile;
37
+ interface Options {
38
+ /**
39
+ * Enable/configure component + directive auto-import with tree-shaking.
40
+ * - `true` — auto-import everything (default)
41
+ * - `false` — disable (you import manually or use a full bundle)
42
+ * - `{ labs, ignore }` — fine-grained control
43
+ */
44
+ autoImport?: boolean | ImportPluginOptions;
45
+ /**
46
+ * Stylesheet handling strategy.
47
+ * @default true
48
+ */
49
+ styles?: StylesOption;
50
+ }
51
+ interface ResolvedOptions {
52
+ autoImport: false | ImportPluginOptions;
53
+ styles: StylesOption;
54
+ }
55
+
56
+ /**
57
+ * `vuetify4:import`
58
+ *
59
+ * Intercepts every compiled Vue file / template chunk and replaces dynamic
60
+ * `_resolveComponent(...)` calls with static tree-shakeable imports from the
61
+ * Vuetify package.
62
+ *
63
+ * Must be placed AFTER the Vue plugin in the plugins array (enforced at
64
+ * `configResolved` time).
65
+ */
66
+ declare function importPlugin(options: ResolvedOptions): Plugin;
67
+
68
+ /**
69
+ * `vuetify4:styles`
70
+ *
71
+ * Intercepts Vuetify's internal `.css` imports and redirects them according to
72
+ * `options.styles`:
73
+ *
74
+ * - `'none'` → return empty module (suppress all Vuetify CSS)
75
+ * - `'sass'` → resolve to the companion `.sass` / `.scss` source
76
+ * - `{ configFile }` → prefix every component stylesheet with `@use configFile`
77
+ *
78
+ * When `styles: true` (default), this plugin is not added at all — Vite
79
+ * handles the pre-compiled CSS normally.
80
+ */
81
+ declare function stylesPlugin(options: ResolvedOptions): Plugin;
82
+
83
+ /**
84
+ * Core transform: given compiled Vue template `source`, generates static
85
+ * Vuetify import statements and erases the `_resolveComponent(...)` /
86
+ * `_resolveDirective(...)` declarations those imports replace.
87
+ *
88
+ * Returns `{ code, source }` where:
89
+ * - `source` is the (possibly mutated) original code with dynamic-resolve
90
+ * calls blanked out (spaces, preserving source-map columns).
91
+ * - `code` is the new import block to prepend / append.
92
+ */
93
+ declare function generateImports(source: string, options: ImportPluginOptions): {
94
+ code: string;
95
+ source: string;
96
+ };
97
+
98
+ interface TemplateMatch {
99
+ /** The local JS symbol name, e.g. `_component_VBtn` */
100
+ symbol: string;
101
+ /** PascalCase component/directive name, e.g. `VBtn` */
102
+ name: string;
103
+ /** Byte offset of the match inside the source string */
104
+ index: number;
105
+ /** Byte length of the matched substring */
106
+ length: number;
107
+ }
108
+ /**
109
+ * Parse compiled Vue template code for `_resolveComponent(...)` and
110
+ * `_resolveDirective(...)` calls and return typed match sets.
111
+ *
112
+ * The regex patterns mirror those in `@vuetify/loader-shared` exactly so
113
+ * behaviour is identical.
114
+ */
115
+ declare function parseTemplate(source: string): {
116
+ components: Set<TemplateMatch>;
117
+ directives: Set<TemplateMatch>;
118
+ };
119
+
120
+ declare const transformAssetUrls: Record<string, string[]>;
121
+ /**
122
+ * `vite-plugin-vuetify4`
123
+ *
124
+ * Drop-in Vite plugin for Vuetify 4 with:
125
+ * - Tree-shaking auto-import (no `@vuetify/loader-shared` dependency)
126
+ * - CSS / SASS / configFile style strategies
127
+ * - Lab component support
128
+ * - `transformAssetUrls` for @vitejs/plugin-vue
129
+ *
130
+ * @example
131
+ * ```ts
132
+ * // vite.config.ts
133
+ * import { defineConfig } from 'vite'
134
+ * import vue from '@vitejs/plugin-vue'
135
+ * import vuetify from 'vite-plugin-vuetify4'
136
+ *
137
+ * export default defineConfig({
138
+ * plugins: [
139
+ * vue({ template: { transformAssetUrls: vuetify.transformAssetUrls } }),
140
+ * vuetify({ styles: { configFile: 'src/styles/settings.scss' } }),
141
+ * ],
142
+ * })
143
+ * ```
144
+ */
145
+ declare function vuetify(rawOptions?: Options): Plugin[];
146
+ declare namespace vuetify {
147
+ var transformAssetUrls: Record<string, string[]>;
148
+ }
149
+
150
+ export { type ImportPluginOptions, type Options, type ResolvedOptions, type StylesConfigFile, type StylesOption, vuetify as default, generateImports, importPlugin, parseTemplate, stylesPlugin, transformAssetUrls };
package/dist/index.js ADDED
@@ -0,0 +1,319 @@
1
+ import { fileURLToPath as __fileURLToPath } from 'node:url';
2
+ const __filename = __fileURLToPath(import.meta.url);
3
+
4
+ // src/types.ts
5
+ function resolveOptions(raw) {
6
+ const autoImport = raw.autoImport === false ? false : raw.autoImport === true || raw.autoImport == null ? {} : raw.autoImport;
7
+ return {
8
+ autoImport,
9
+ styles: raw.styles ?? true
10
+ };
11
+ }
12
+
13
+ // src/importPlugin.ts
14
+ import { createFilter } from "vite";
15
+
16
+ // src/imports/parseTemplate.ts
17
+ import { camelize, capitalize } from "vue";
18
+ function parseTemplate(source) {
19
+ const components = collectMatches(
20
+ source.matchAll(/(?:var|const) (\w+) *?= *?_resolveComponent\("([\w-.]+)"\);?/gm)
21
+ );
22
+ const directives = collectMatches(
23
+ source.matchAll(/(?:var|const) (\w+) *?= *?_resolveDirective\("([\w-.]+)"\);?/gm)
24
+ );
25
+ return { components, directives };
26
+ }
27
+ function collectMatches(iter) {
28
+ return new Set(
29
+ Array.from(iter, (m) => ({
30
+ symbol: m[1],
31
+ name: capitalize(camelize(m[2])),
32
+ index: m.index,
33
+ length: m[0].length
34
+ }))
35
+ );
36
+ }
37
+
38
+ // src/utils.ts
39
+ import { createRequire } from "module";
40
+ import nodePath from "path";
41
+ var _require = createRequire(__filename);
42
+ function resolveVuetifyBase() {
43
+ return nodePath.dirname(
44
+ _require.resolve("vuetify/package.json", { paths: [process.cwd()] })
45
+ );
46
+ }
47
+ function loadImportMap() {
48
+ return _require("vuetify/dist/json/importMap.json");
49
+ }
50
+ function loadImportMapLabs() {
51
+ return _require("vuetify/dist/json/importMap-labs.json");
52
+ }
53
+ function normalizePath(p) {
54
+ p = nodePath.normalize(p).replace(/\\/g, "/");
55
+ if (/^[a-z]:\//i.test(p)) p = "/" + p;
56
+ return p;
57
+ }
58
+ function isObject(value) {
59
+ return value !== null && typeof value === "object";
60
+ }
61
+ function isSubdir(root, test) {
62
+ const rel = nodePath.relative(root, test);
63
+ return !!rel && !rel.startsWith("..") && !nodePath.isAbsolute(rel);
64
+ }
65
+
66
+ // src/imports/getImports.ts
67
+ function getImports(source, options) {
68
+ const importMap = loadImportMap();
69
+ const importMapLabs = loadImportMapLabs();
70
+ const { components, directives } = parseTemplate(source);
71
+ const resolvedComponents = [];
72
+ const resolvedDirectives = [];
73
+ const imports = /* @__PURE__ */ new Map();
74
+ const ignore = options.ignore ?? null;
75
+ const includeLabs = !!options.labs;
76
+ const componentMap = includeLabs ? { ...importMap.components, ...importMapLabs.components } : { ...importMap.components };
77
+ components.forEach((c) => {
78
+ if (ignore?.includes(c.name)) return;
79
+ if (c.name in componentMap) resolvedComponents.push(c);
80
+ });
81
+ directives.forEach((d) => {
82
+ if (importMap.directives.includes(d.name) && !ignore?.includes(d.name)) {
83
+ resolvedDirectives.push(d);
84
+ }
85
+ });
86
+ resolvedComponents.forEach((c) => {
87
+ const { from } = componentMap[c.name];
88
+ const specifier = from.endsWith(".mjs") ? `vuetify/lib/${from}` : `vuetify/${from}`;
89
+ addImport(imports, c.name, c.symbol, specifier);
90
+ });
91
+ resolvedDirectives.forEach((d) => {
92
+ addImport(imports, d.name, d.symbol, "vuetify/directives");
93
+ });
94
+ return { imports, components: resolvedComponents, directives: resolvedDirectives };
95
+ }
96
+ function addImport(imports, name, as, from) {
97
+ if (!imports.has(from)) imports.set(from, []);
98
+ imports.get(from).push(`${name} as ${as}`);
99
+ }
100
+
101
+ // src/imports/generateImports.ts
102
+ function generateImports(source, options) {
103
+ const { imports, components, directives } = getImports(source, options);
104
+ let code = "";
105
+ if (components.length || directives.length) {
106
+ code += "\n\n/* Vuetify */\n";
107
+ Array.from(imports).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).forEach(([from, names]) => {
108
+ code += `import { ${names.join(", ")} } from "${from}"
109
+ `;
110
+ });
111
+ code += "\n";
112
+ source = [...components, ...directives].reduce((acc, v) => {
113
+ return acc.slice(0, v.index) + " ".repeat(v.length) + acc.slice(v.index + v.length);
114
+ }, source);
115
+ if (!source.includes("_resolveComponent(")) {
116
+ source = source.replace("resolveComponent as _resolveComponent, ", "");
117
+ }
118
+ if (!source.includes("_resolveDirective(")) {
119
+ source = source.replace("resolveDirective as _resolveDirective, ", "");
120
+ }
121
+ }
122
+ return { code, source };
123
+ }
124
+
125
+ // src/importPlugin.ts
126
+ function parseId(id) {
127
+ const [pathname, query] = id.split("?");
128
+ return {
129
+ path: pathname ?? id,
130
+ query: query ? Object.fromEntries(new URLSearchParams(query)) : null
131
+ };
132
+ }
133
+ function importPlugin(options) {
134
+ const importOptions = options.autoImport;
135
+ let filter = () => true;
136
+ return {
137
+ name: "vuetify4:import",
138
+ configResolved(config) {
139
+ const selfIdx = config.plugins.findIndex((p) => p.name === "vuetify4:import");
140
+ const vueIdx = config.plugins.findIndex(
141
+ (p) => ["vite:vue", "unplugin-vue"].includes(p.name)
142
+ );
143
+ if (vueIdx === -1) {
144
+ config.logger.warn(
145
+ "[vite-plugin-vuetify4] No Vue plugin found \u2014 auto-import is a no-op. Add @vitejs/plugin-vue (Nuxt provides this automatically)."
146
+ );
147
+ return;
148
+ }
149
+ if (selfIdx !== -1 && selfIdx < vueIdx) {
150
+ throw new Error(
151
+ "[vite-plugin-vuetify4] This plugin must be registered AFTER the Vue plugin. Move it below `vue()` in your plugins array."
152
+ );
153
+ }
154
+ const vuePlugin = config.plugins[vueIdx];
155
+ const vueOptions = vuePlugin?.api?.options ?? {};
156
+ filter = createFilter(vueOptions.include, vueOptions.exclude);
157
+ },
158
+ transform(code, id) {
159
+ const { path, query } = parseId(id);
160
+ const isVueVirtual = !!query && "vue" in query;
161
+ const isVueFile = !isVueVirtual && filter(path) && // Skip render-only re-export stubs that the Vue plugin emits
162
+ !/^import \{ render as _sfc_render \} from ".*"$/m.test(code);
163
+ const isVueTemplate = isVueVirtual && (query.type === "template" || query.type === "script" && query.setup === "true");
164
+ if (isVueFile || isVueTemplate) {
165
+ const { code: importCode, source } = generateImports(code, importOptions);
166
+ return { code: source + importCode, map: null };
167
+ }
168
+ return null;
169
+ }
170
+ };
171
+ }
172
+
173
+ // src/stylesPlugin.ts
174
+ import nodePath2 from "path";
175
+ import fs from "fs/promises";
176
+ var VIRTUAL_PREFIX = "virtual:";
177
+ var PLUGIN_VIRTUAL_NAME = "plugin-vuetify4";
178
+ var VIRTUAL_MODULE_ID = `${VIRTUAL_PREFIX}${PLUGIN_VIRTUAL_NAME}`;
179
+ function stylesPlugin(options) {
180
+ const vuetifyBase = resolveVuetifyBase();
181
+ let configFile = "";
182
+ const tempFiles = /* @__PURE__ */ new Map();
183
+ const cssToSass = /* @__PURE__ */ new Map();
184
+ async function resolveSass(target) {
185
+ let cached = cssToSass.get(target);
186
+ if (!cached) {
187
+ cached = target.replace(/\.css$/, ".sass");
188
+ try {
189
+ await fs.access(cached, fs.constants.R_OK);
190
+ } catch (err) {
191
+ if (err instanceof Error && "code" in err && err.code === "ENOENT") {
192
+ cached = target.replace(/\.css$/, ".scss");
193
+ } else {
194
+ throw err;
195
+ }
196
+ }
197
+ cssToSass.set(target, cached);
198
+ }
199
+ return cached;
200
+ }
201
+ return {
202
+ name: "vuetify4:styles",
203
+ enforce: "pre",
204
+ // Must run before Vite's default CSS resolution
205
+ configResolved(config) {
206
+ if (isObject(options.styles) && "configFile" in options.styles) {
207
+ const cf = options.styles.configFile;
208
+ configFile = nodePath2.isAbsolute(cf) ? cf : nodePath2.join(config.root || process.cwd(), cf);
209
+ }
210
+ },
211
+ async resolveId(source, importer, ctx) {
212
+ const isVuetifyStyles = source === "vuetify/styles" || importer && source.endsWith(".css") && isSubdir(
213
+ vuetifyBase,
214
+ nodePath2.isAbsolute(source) ? source : importer
215
+ );
216
+ if (isVuetifyStyles) {
217
+ if (options.styles === "none") {
218
+ return `${VIRTUAL_PREFIX}__void__`;
219
+ }
220
+ if (options.styles === "sass") {
221
+ const resolution = await this.resolve(source, importer, {
222
+ skipSelf: true,
223
+ custom: ctx.custom
224
+ });
225
+ if (!resolution) return null;
226
+ return resolveSass(resolution.id);
227
+ }
228
+ if (isObject(options.styles) && "configFile" in options.styles) {
229
+ const resolution = await this.resolve(source, importer, {
230
+ skipSelf: true,
231
+ custom: ctx.custom
232
+ });
233
+ if (!resolution) return null;
234
+ const sassFile = await resolveSass(resolution.id);
235
+ const relFile = nodePath2.relative(nodePath2.join(vuetifyBase, "lib"), sassFile);
236
+ const suffix = sassFile.endsWith(".scss") ? ";\n" : "\n";
237
+ const contents = `@use "${normalizePath(configFile)}"${suffix}@use "${normalizePath(sassFile)}"${suffix}`;
238
+ tempFiles.set(relFile, contents);
239
+ return `${VIRTUAL_MODULE_ID}:${relFile}`;
240
+ }
241
+ }
242
+ if (source.startsWith(`/${PLUGIN_VIRTUAL_NAME}:`)) {
243
+ return VIRTUAL_PREFIX + source.slice(1);
244
+ }
245
+ if (source.startsWith(`/@id/__x00__${PLUGIN_VIRTUAL_NAME}:`)) {
246
+ return VIRTUAL_PREFIX + source.slice(12);
247
+ }
248
+ if (source.startsWith(`/${VIRTUAL_MODULE_ID}:`)) {
249
+ return source.slice(1);
250
+ }
251
+ return null;
252
+ },
253
+ load(id) {
254
+ if (new RegExp(`^${VIRTUAL_PREFIX}__void__(\\?.*)?$`).test(id)) {
255
+ return "";
256
+ }
257
+ if (id.startsWith(VIRTUAL_MODULE_ID)) {
258
+ const file = new RegExp(`^${VIRTUAL_MODULE_ID}:(.*?)(\\?.*)?$`).exec(id)?.[1];
259
+ if (file) return tempFiles.get(file) ?? null;
260
+ }
261
+ return null;
262
+ }
263
+ };
264
+ }
265
+
266
+ // src/index.ts
267
+ function toKebabCase(str = "") {
268
+ return str.replace(/[^a-z]/gi, "-").replace(/\B([A-Z])/g, "-$1").toLowerCase();
269
+ }
270
+ var _transformAssetUrls = {
271
+ VAppBar: ["image"],
272
+ VAvatar: ["image"],
273
+ VBanner: ["avatar"],
274
+ VCard: ["image", "prependAvatar", "appendAvatar"],
275
+ VCardItem: ["prependAvatar", "appendAvatar"],
276
+ VCarouselItem: ["src", "lazySrc", "srcset"],
277
+ VChip: ["prependAvatar", "appendAvatar"],
278
+ VImg: ["src", "lazySrc", "srcset"],
279
+ VListItem: ["prependAvatar", "appendAvatar"],
280
+ VNavigationDrawer: ["image"],
281
+ VParallax: ["src", "lazySrc", "srcset"],
282
+ VToolbar: ["image"]
283
+ };
284
+ for (const [tag, attrs] of Object.entries(_transformAssetUrls)) {
285
+ attrs.forEach((attr) => {
286
+ if (/[A-Z]/.test(attr)) attrs.push(toKebabCase(attr));
287
+ });
288
+ _transformAssetUrls[toKebabCase(tag)] = attrs;
289
+ }
290
+ Object.assign(_transformAssetUrls, {
291
+ video: ["src", "poster"],
292
+ source: ["src"],
293
+ img: ["src"],
294
+ image: ["xlink:href", "href"],
295
+ use: ["xlink:href", "href"]
296
+ });
297
+ var transformAssetUrls = _transformAssetUrls;
298
+ function vuetify(rawOptions = {}) {
299
+ const options = resolveOptions(rawOptions);
300
+ const plugins = [];
301
+ if (options.autoImport !== false) {
302
+ plugins.push(importPlugin(options));
303
+ }
304
+ if (options.styles === "none" || options.styles === "sass" || typeof options.styles === "object" && "configFile" in options.styles) {
305
+ plugins.push(stylesPlugin(options));
306
+ }
307
+ return plugins;
308
+ }
309
+ vuetify.transformAssetUrls = transformAssetUrls;
310
+ var index_default = vuetify;
311
+ export {
312
+ index_default as default,
313
+ generateImports,
314
+ importPlugin,
315
+ parseTemplate,
316
+ stylesPlugin,
317
+ transformAssetUrls
318
+ };
319
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/importPlugin.ts","../src/imports/parseTemplate.ts","../src/utils.ts","../src/imports/getImports.ts","../src/imports/generateImports.ts","../src/stylesPlugin.ts","../src/index.ts"],"sourcesContent":["import type * as Components from 'vuetify/components'\nimport type * as Directives from 'vuetify/directives'\n\n// ─── Auto-import options ──────────────────────────────────────────────────────\n\nexport interface ImportPluginOptions {\n /**\n * Include Vuetify Labs components (`vuetify/labs/*`).\n * @default false\n */\n labs?: boolean\n /**\n * Component or directive names to exclude from auto-import.\n * Useful when you want to manually register a component with a custom impl.\n */\n ignore?: (keyof typeof Components | keyof typeof Directives)[]\n}\n\n// ─── Styles options ───────────────────────────────────────────────────────────\n\nexport interface StylesConfigFile {\n /**\n * Path to a SASS/SCSS config file that is @use-d before every Vuetify\n * component stylesheet. Relative to `vite.config` root, or absolute.\n *\n * Example:\n * ```ts\n * styles: { configFile: 'src/styles/vuetify-settings.scss' }\n * ```\n */\n configFile: string\n}\n\n/**\n * How to handle Vuetify stylesheets:\n * - `true` — use the pre-compiled CSS (default, fastest)\n * - `'none'` — suppress all Vuetify CSS (you bring your own)\n * - `'sass'` — use the raw SASS/SCSS sources (requires sass)\n * - `{ configFile }` — use SASS sources prefixed with your settings file\n */\nexport type StylesOption = true | 'none' | 'sass' | StylesConfigFile\n\n// ─── Top-level options ────────────────────────────────────────────────────────\n\nexport interface Options {\n /**\n * Enable/configure component + directive auto-import with tree-shaking.\n * - `true` — auto-import everything (default)\n * - `false` — disable (you import manually or use a full bundle)\n * - `{ labs, ignore }` — fine-grained control\n */\n autoImport?: boolean | ImportPluginOptions\n\n /**\n * Stylesheet handling strategy.\n * @default true\n */\n styles?: StylesOption\n}\n\n// ─── Internal resolved types ──────────────────────────────────────────────────\n\nexport interface ResolvedOptions {\n autoImport: false | ImportPluginOptions\n styles: StylesOption\n}\n\nexport function resolveOptions (raw: Options): ResolvedOptions {\n const autoImport: ResolvedOptions['autoImport'] =\n raw.autoImport === false\n ? false\n : raw.autoImport === true || raw.autoImport == null\n ? {}\n : raw.autoImport\n\n return {\n autoImport,\n styles: raw.styles ?? true,\n }\n}\n","import { createFilter } from 'vite'\nimport type { Plugin, ResolvedConfig } from 'vite'\nimport { generateImports } from './imports/generateImports'\nimport type { ResolvedOptions } from './types'\n\nfunction parseId (id: string) {\n const [pathname, query] = id.split('?')\n return {\n path: pathname ?? id,\n query: query ? Object.fromEntries(new URLSearchParams(query)) : null,\n }\n}\n\n/**\n * `vuetify4:import`\n *\n * Intercepts every compiled Vue file / template chunk and replaces dynamic\n * `_resolveComponent(...)` calls with static tree-shakeable imports from the\n * Vuetify package.\n *\n * Must be placed AFTER the Vue plugin in the plugins array (enforced at\n * `configResolved` time).\n */\nexport function importPlugin (options: ResolvedOptions): Plugin {\n // Narrowed: if we reach here, autoImport is not false\n const importOptions = options.autoImport as Exclude<ResolvedOptions['autoImport'], false>\n let filter: (id: unknown) => boolean = () => true\n\n return {\n name: 'vuetify4:import',\n\n configResolved (config: ResolvedConfig) {\n const selfIdx = config.plugins.findIndex(p => p.name === 'vuetify4:import')\n const vueIdx = config.plugins.findIndex(p =>\n ['vite:vue', 'unplugin-vue'].includes(p.name)\n )\n\n if (vueIdx === -1) {\n config.logger.warn(\n '[vite-plugin-vuetify4] No Vue plugin found — ' +\n 'auto-import is a no-op. Add @vitejs/plugin-vue ' +\n '(Nuxt provides this automatically).'\n )\n return\n }\n\n if (selfIdx !== -1 && selfIdx < vueIdx) {\n throw new Error(\n '[vite-plugin-vuetify4] This plugin must be registered AFTER the Vue plugin. ' +\n 'Move it below `vue()` in your plugins array.'\n )\n }\n\n const vuePlugin = config.plugins[vueIdx] as any\n const vueOptions = vuePlugin?.api?.options ?? {}\n filter = createFilter(vueOptions.include, vueOptions.exclude)\n },\n\n transform (code, id) {\n const { path, query } = parseId(id)\n\n // A virtual sub-request appended by the Vue plugin (e.g. ?vue&type=template)\n const isVueVirtual = !!query && 'vue' in query\n const isVueFile =\n !isVueVirtual &&\n filter(path) &&\n // Skip render-only re-export stubs that the Vue plugin emits\n !/^import \\{ render as _sfc_render \\} from \".*\"$/m.test(code)\n const isVueTemplate =\n isVueVirtual &&\n (query!.type === 'template' ||\n (query!.type === 'script' && query!.setup === 'true'))\n\n if (isVueFile || isVueTemplate) {\n const { code: importCode, source } = generateImports(code, importOptions)\n return { code: source + importCode, map: null }\n }\n\n return null\n },\n }\n}\n","import { camelize, capitalize } from 'vue'\n\nexport interface TemplateMatch {\n /** The local JS symbol name, e.g. `_component_VBtn` */\n symbol: string\n /** PascalCase component/directive name, e.g. `VBtn` */\n name: string\n /** Byte offset of the match inside the source string */\n index: number\n /** Byte length of the matched substring */\n length: number\n}\n\n/**\n * Parse compiled Vue template code for `_resolveComponent(...)` and\n * `_resolveDirective(...)` calls and return typed match sets.\n *\n * The regex patterns mirror those in `@vuetify/loader-shared` exactly so\n * behaviour is identical.\n */\nexport function parseTemplate (source: string) {\n const components = collectMatches(\n source.matchAll(/(?:var|const) (\\w+) *?= *?_resolveComponent\\(\"([\\w-.]+)\"\\);?/gm)\n )\n const directives = collectMatches(\n source.matchAll(/(?:var|const) (\\w+) *?= *?_resolveDirective\\(\"([\\w-.]+)\"\\);?/gm)\n )\n return { components, directives }\n}\n\nfunction collectMatches (\n iter: IterableIterator<RegExpMatchArray>\n): Set<TemplateMatch> {\n return new Set(\n Array.from(iter, m => ({\n symbol: m[1],\n name: capitalize(camelize(m[2])),\n index: m.index!,\n length: m[0].length,\n }))\n )\n}\n","import { createRequire } from 'node:module'\nimport nodePath from 'node:path'\n\n// `__filename` is available in both output formats:\n// - CJS: provided natively by Node\n// - ESM: shimmed from `import.meta.url` via the tsup banner\nconst _require = createRequire(__filename)\n\n/**\n * Resolves the directory of the installed `vuetify` package.\n */\nexport function resolveVuetifyBase (): string {\n return nodePath.dirname(\n _require.resolve('vuetify/package.json', { paths: [process.cwd()] })\n )\n}\n\nexport function loadImportMap () {\n return _require('vuetify/dist/json/importMap.json') as ImportMap\n}\n\nexport function loadImportMapLabs () {\n return _require('vuetify/dist/json/importMap-labs.json') as ImportMap\n}\n\nexport interface ImportMap {\n components: Record<string, { from: string }>\n directives: string[]\n}\n\n/** Forward-slash paths on Windows for Vite/esbuild compatibility. */\nexport function normalizePath (p: string): string {\n p = nodePath.normalize(p).replace(/\\\\/g, '/')\n if (/^[a-z]:\\//i.test(p)) p = '/' + p\n return p\n}\n\nexport function isObject (value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object'\n}\n\nexport function isSubdir (root: string, test: string): boolean {\n const rel = nodePath.relative(root, test)\n return !!rel && !rel.startsWith('..') && !nodePath.isAbsolute(rel)\n}\n","import { parseTemplate } from './parseTemplate'\nimport { loadImportMap, loadImportMapLabs } from '../utils'\nimport type { TemplateMatch } from './parseTemplate'\nimport type { ImportPluginOptions } from '../types'\n\n/**\n * Given compiled Vue template source, returns:\n * - `imports` Map<from-specifier, [\"Name as _symbol\", ...]>\n * - `components` matched component descriptors (for source-rewriting)\n * - `directives` matched directive descriptors (for source-rewriting)\n */\nexport function getImports (source: string, options: ImportPluginOptions) {\n const importMap = loadImportMap()\n const importMapLabs = loadImportMapLabs()\n\n const { components, directives } = parseTemplate(source)\n const resolvedComponents: TemplateMatch[] = []\n const resolvedDirectives: TemplateMatch[] = []\n const imports = new Map<string, string[]>()\n\n const ignore = options.ignore ?? null\n const includeLabs = !!options.labs\n\n // Merge labs into the lookup when requested\n const componentMap: Record<string, { from: string }> = includeLabs\n ? { ...importMap.components, ...importMapLabs.components }\n : { ...importMap.components }\n\n components.forEach(c => {\n if (ignore?.includes(c.name as never)) return\n if (c.name in componentMap) resolvedComponents.push(c)\n })\n\n directives.forEach(d => {\n if (importMap.directives.includes(d.name) && !ignore?.includes(d.name as never)) {\n resolvedDirectives.push(d)\n }\n })\n\n resolvedComponents.forEach(c => {\n const { from } = componentMap[c.name]\n // Vuetify ≥3.7.11 / v4: `from` ends in `.mjs` and is a subpath export.\n // Older builds use a bare lib path.\n const specifier = from.endsWith('.mjs') ? `vuetify/lib/${from}` : `vuetify/${from}`\n addImport(imports, c.name, c.symbol, specifier)\n })\n\n resolvedDirectives.forEach(d => {\n addImport(imports, d.name, d.symbol, 'vuetify/directives')\n })\n\n return { imports, components: resolvedComponents, directives: resolvedDirectives }\n}\n\nfunction addImport (\n imports: Map<string, string[]>,\n name: string,\n as: string,\n from: string\n) {\n if (!imports.has(from)) imports.set(from, [])\n imports.get(from)!.push(`${name} as ${as}`)\n}\n","import { getImports } from './getImports'\nimport type { ImportPluginOptions } from '../types'\n\n/**\n * Core transform: given compiled Vue template `source`, generates static\n * Vuetify import statements and erases the `_resolveComponent(...)` /\n * `_resolveDirective(...)` declarations those imports replace.\n *\n * Returns `{ code, source }` where:\n * - `source` is the (possibly mutated) original code with dynamic-resolve\n * calls blanked out (spaces, preserving source-map columns).\n * - `code` is the new import block to prepend / append.\n */\nexport function generateImports (\n source: string,\n options: ImportPluginOptions\n): { code: string; source: string } {\n const { imports, components, directives } = getImports(source, options)\n\n let code = ''\n\n if (components.length || directives.length) {\n code += '\\n\\n/* Vuetify */\\n'\n\n // Sort import specifiers alphabetically for deterministic output\n Array.from(imports)\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n .forEach(([from, names]) => {\n code += `import { ${names.join(', ')} } from \"${from}\"\\n`\n })\n\n code += '\\n'\n\n // Replace matched substrings with spaces to preserve source-map columns\n source = [...components, ...directives].reduce((acc, v) => {\n return acc.slice(0, v.index) + ' '.repeat(v.length) + acc.slice(v.index + v.length)\n }, source)\n\n // If all resolveComponent / resolveDirective calls are gone, also strip\n // the named imports from the Vue runtime import at the top of the file.\n if (!source.includes('_resolveComponent(')) {\n source = source.replace('resolveComponent as _resolveComponent, ', '')\n }\n if (!source.includes('_resolveDirective(')) {\n source = source.replace('resolveDirective as _resolveDirective, ', '')\n }\n }\n\n return { code, source }\n}\n","import nodePath from 'node:path'\nimport fs from 'node:fs/promises'\nimport { resolveVuetifyBase, normalizePath, isObject, isSubdir } from './utils'\nimport type { Plugin, ResolvedConfig } from 'vite'\nimport type { ResolvedOptions, StylesConfigFile } from './types'\n\nconst VIRTUAL_PREFIX = 'virtual:'\nconst PLUGIN_VIRTUAL_NAME = 'plugin-vuetify4'\nconst VIRTUAL_MODULE_ID = `${VIRTUAL_PREFIX}${PLUGIN_VIRTUAL_NAME}`\n\n/**\n * `vuetify4:styles`\n *\n * Intercepts Vuetify's internal `.css` imports and redirects them according to\n * `options.styles`:\n *\n * - `'none'` → return empty module (suppress all Vuetify CSS)\n * - `'sass'` → resolve to the companion `.sass` / `.scss` source\n * - `{ configFile }` → prefix every component stylesheet with `@use configFile`\n *\n * When `styles: true` (default), this plugin is not added at all — Vite\n * handles the pre-compiled CSS normally.\n */\nexport function stylesPlugin (options: ResolvedOptions): Plugin {\n const vuetifyBase = resolveVuetifyBase()\n\n let configFile = ''\n // Virtual file contents keyed by relative path (configFile strategy)\n const tempFiles = new Map<string, string>()\n // Cache css → sass/scss path resolutions\n const cssToSass = new Map<string, string>()\n\n async function resolveSass (target: string): Promise<string> {\n let cached = cssToSass.get(target)\n if (!cached) {\n cached = target.replace(/\\.css$/, '.sass')\n try {\n await fs.access(cached, fs.constants.R_OK)\n } catch (err) {\n // Fallback to .scss\n if (err instanceof Error && 'code' in err && (err as NodeJS.ErrnoException).code === 'ENOENT') {\n cached = target.replace(/\\.css$/, '.scss')\n } else {\n throw err\n }\n }\n cssToSass.set(target, cached)\n }\n return cached\n }\n\n return {\n name: 'vuetify4:styles',\n enforce: 'pre', // Must run before Vite's default CSS resolution\n\n configResolved (config: ResolvedConfig) {\n if (isObject(options.styles) && 'configFile' in options.styles) {\n const cf = (options.styles as StylesConfigFile).configFile\n configFile = nodePath.isAbsolute(cf)\n ? cf\n : nodePath.join(config.root || process.cwd(), cf)\n }\n },\n\n async resolveId (source, importer, ctx) {\n const isVuetifyStyles =\n source === 'vuetify/styles' ||\n (\n importer &&\n source.endsWith('.css') &&\n isSubdir(\n vuetifyBase,\n nodePath.isAbsolute(source) ? source : importer\n )\n )\n\n if (isVuetifyStyles) {\n // ── Strategy: none ────────────────────────────────────────────────────\n if (options.styles === 'none') {\n return `${VIRTUAL_PREFIX}__void__`\n }\n\n // ── Strategy: sass ────────────────────────────────────────────────────\n if (options.styles === 'sass') {\n const resolution = await this.resolve(source, importer, {\n skipSelf: true,\n custom: ctx.custom,\n })\n if (!resolution) return null\n return resolveSass(resolution.id)\n }\n\n // ── Strategy: { configFile } ──────────────────────────────────────────\n if (isObject(options.styles) && 'configFile' in options.styles) {\n const resolution = await this.resolve(source, importer, {\n skipSelf: true,\n custom: ctx.custom,\n })\n if (!resolution) return null\n\n const sassFile = await resolveSass(resolution.id)\n const relFile = nodePath.relative(nodePath.join(vuetifyBase, 'lib'), sassFile)\n const suffix = sassFile.endsWith('.scss') ? ';\\n' : '\\n'\n const contents =\n `@use \"${normalizePath(configFile)}\"${suffix}` +\n `@use \"${normalizePath(sassFile)}\"${suffix}`\n\n tempFiles.set(relFile, contents)\n return `${VIRTUAL_MODULE_ID}:${relFile}`\n }\n }\n\n // ── Vite SSR virtual re-entry aliases ─────────────────────────────────\n if (source.startsWith(`/${PLUGIN_VIRTUAL_NAME}:`)) {\n return VIRTUAL_PREFIX + source.slice(1)\n }\n if (source.startsWith(`/@id/__x00__${PLUGIN_VIRTUAL_NAME}:`)) {\n return VIRTUAL_PREFIX + source.slice(12)\n }\n if (source.startsWith(`/${VIRTUAL_MODULE_ID}:`)) {\n return source.slice(1)\n }\n\n return null\n },\n\n load (id) {\n // __void__ — suppress CSS (styles: 'none')\n // Vite may append a version hash: `?v=abc123`\n if (new RegExp(`^${VIRTUAL_PREFIX}__void__(\\\\?.*)?$`).test(id)) {\n return ''\n }\n\n // Virtual config-prefixed sass files\n if (id.startsWith(VIRTUAL_MODULE_ID)) {\n const file = new RegExp(`^${VIRTUAL_MODULE_ID}:(.*?)(\\\\?.*)?$`).exec(id)?.[1]\n if (file) return tempFiles.get(file) ?? null\n }\n\n return null\n },\n }\n}\n","import type { Plugin } from 'vite'\nimport { resolveOptions } from './types'\nimport { importPlugin } from './importPlugin'\nimport { stylesPlugin } from './stylesPlugin'\nimport type { Options } from './types'\n\n// ─── transformAssetUrls ───────────────────────────────────────────────────────\n// Tells @vitejs/plugin-vue which Vuetify component props carry asset URLs\n// (images, posters, etc.) so Vite can process them as static assets.\n// Mirrors the official plugin's export exactly.\n\nfunction toKebabCase (str = '') {\n return str\n .replace(/[^a-z]/gi, '-')\n .replace(/\\B([A-Z])/g, '-$1')\n .toLowerCase()\n}\n\nconst _transformAssetUrls: Record<string, string[]> = {\n VAppBar: ['image'],\n VAvatar: ['image'],\n VBanner: ['avatar'],\n VCard: ['image', 'prependAvatar', 'appendAvatar'],\n VCardItem: ['prependAvatar', 'appendAvatar'],\n VCarouselItem: ['src', 'lazySrc', 'srcset'],\n VChip: ['prependAvatar', 'appendAvatar'],\n VImg: ['src', 'lazySrc', 'srcset'],\n VListItem: ['prependAvatar', 'appendAvatar'],\n VNavigationDrawer:['image'],\n VParallax: ['src', 'lazySrc', 'srcset'],\n VToolbar: ['image'],\n}\n\n// Add kebab-case aliases and default HTML tag attrs\nfor (const [tag, attrs] of Object.entries(_transformAssetUrls)) {\n attrs.forEach(attr => {\n if (/[A-Z]/.test(attr)) attrs.push(toKebabCase(attr))\n })\n _transformAssetUrls[toKebabCase(tag)] = attrs\n}\nObject.assign(_transformAssetUrls, {\n video: ['src', 'poster'],\n source: ['src'],\n img: ['src'],\n image: ['xlink:href', 'href'],\n use: ['xlink:href', 'href'],\n})\n\nexport const transformAssetUrls = _transformAssetUrls\n\n// ─── Main plugin factory ──────────────────────────────────────────────────────\n\n/**\n * `vite-plugin-vuetify4`\n *\n * Drop-in Vite plugin for Vuetify 4 with:\n * - Tree-shaking auto-import (no `@vuetify/loader-shared` dependency)\n * - CSS / SASS / configFile style strategies\n * - Lab component support\n * - `transformAssetUrls` for @vitejs/plugin-vue\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { defineConfig } from 'vite'\n * import vue from '@vitejs/plugin-vue'\n * import vuetify from 'vite-plugin-vuetify4'\n *\n * export default defineConfig({\n * plugins: [\n * vue({ template: { transformAssetUrls: vuetify.transformAssetUrls } }),\n * vuetify({ styles: { configFile: 'src/styles/settings.scss' } }),\n * ],\n * })\n * ```\n */\nfunction vuetify (rawOptions: Options = {}): Plugin[] {\n const options = resolveOptions(rawOptions)\n const plugins: Plugin[] = []\n\n if (options.autoImport !== false) {\n plugins.push(importPlugin(options))\n }\n\n // Style plugin is only needed for non-default strategies\n if (\n options.styles === 'none' ||\n options.styles === 'sass' ||\n (typeof options.styles === 'object' && 'configFile' in options.styles)\n ) {\n plugins.push(stylesPlugin(options))\n }\n\n return plugins\n}\n\nvuetify.transformAssetUrls = transformAssetUrls\n\nexport default vuetify\n\n// Named exports for Nuxt module / programmatic usage\nexport type { Options, ImportPluginOptions, StylesOption, StylesConfigFile, ResolvedOptions } from './types'\nexport { importPlugin } from './importPlugin'\nexport { stylesPlugin } from './stylesPlugin'\nexport { generateImports } from './imports/generateImports'\nexport { parseTemplate } from './imports/parseTemplate'\n"],"mappings":"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","names":["nodePath","nodePath"]}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "vuetify-vite-plugin",
3
+ "version": "1.0.0",
4
+ "description": "Vite plugin for Vuetify 4 — tree-shaking auto-import, styles, and labs. No legacy loader-shared dependency.",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "README.md"
24
+ ],
25
+ "scripts": {
26
+ "build": "tsup",
27
+ "dev": "tsup --watch",
28
+ "typecheck": "tsc --noEmit",
29
+ "prepublishOnly": "npm run build"
30
+ },
31
+ "peerDependencies": {
32
+ "vite": ">=5.0.0",
33
+ "vue": "^3.4.0",
34
+ "vuetify": "^4.0.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^25.9.3",
38
+ "tsup": "^8.5.1",
39
+ "typescript": "^5.9.3",
40
+ "vite": "^6.4.3",
41
+ "vue": "^3.5.38",
42
+ "vuetify": "^4.1.1"
43
+ },
44
+ "keywords": [
45
+ "vite",
46
+ "vite-plugin",
47
+ "vuetify",
48
+ "vuetify4",
49
+ "tree-shaking",
50
+ "auto-import"
51
+ ],
52
+ "license": "MIT",
53
+ "engines": {
54
+ "node": "^18.0.0 || >=20.0.0"
55
+ }
56
+ }