Skip to content

Commit de52177

Browse files
committed
feat(vite): enable vuetify styles plugin for custom styles configuration
1 parent 723cc40 commit de52177

File tree

2 files changed

+129
-3
lines changed

2 files changed

+129
-3
lines changed

packages/vuetify-nuxt-module/src/utils/configure-vite.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { vuetifyDateConfigurationPlugin } from '../vite/vuetify-date-configurati
99
import { vuetifyIconsPlugin } from '../vite/vuetify-icons-configuration-plugin'
1010
import { vuetifyImportPlugin } from '../vite/vuetify-import-plugin'
1111
import { vuetifySSRClientHintsPlugin } from '../vite/vuetify-ssr-client-hints-plugin'
12+
import { vuetifyStylesPlugin } from '../vite/vuetify-styles-plugin'
1213
import { createTransformAssetUrls } from './index'
1314
import { checkVuetifyPlugins } from './module'
1415

@@ -80,9 +81,9 @@ export function configureVite (configKey: string, nuxt: Nuxt, ctx: VuetifyNuxtCo
8081

8182
viteInlineConfig.plugins.push(vuetifyImportPlugin({ autoImport }))
8283
// exclude styles plugin
83-
// if (typeof ctx.moduleOptions.styles !== 'boolean') {
84-
// viteInlineConfig.plugins.push(vuetifyStylesPlugin({ styles: ctx.moduleOptions.styles }, ctx.viteVersion, ctx.logger))
85-
// }
84+
if (typeof ctx.moduleOptions.styles !== 'boolean') {
85+
viteInlineConfig.plugins.push(vuetifyStylesPlugin({ styles: ctx.moduleOptions.styles }, ctx.viteVersion, ctx.logger))
86+
}
8687
viteInlineConfig.plugins.push(vuetifyConfigurationPlugin(ctx), vuetifyIconsPlugin(ctx), vuetifyDateConfigurationPlugin(ctx))
8788
if (ctx.ssrClientHints.enabled) {
8889
viteInlineConfig.plugins.push(vuetifySSRClientHintsPlugin(ctx))
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import type { Options } from '@vuetify/loader-shared'
2+
import type { Plugin } from 'vite'
3+
import type { VuetifyNuxtContext } from '../utils/config'
4+
import fs from 'node:fs'
5+
import fsp from 'node:fs/promises'
6+
import { pathToFileURL } from 'node:url'
7+
import { resolvePath } from '@nuxt/kit'
8+
import { isObject, normalizePath, resolveVuetifyBase } from '@vuetify/loader-shared'
9+
import { isAbsolute, relative as relativePath } from 'pathe'
10+
import semver from 'semver'
11+
import path from 'upath'
12+
13+
export function vuetifyStylesPlugin (
14+
options: Options,
15+
viteVersion: VuetifyNuxtContext['viteVersion'],
16+
_logger: ReturnType<typeof import('@nuxt/kit')['useLogger']>,
17+
) {
18+
let configFile: string | undefined
19+
// let cacheDir: string | undefined
20+
const vuetifyBase = resolveVuetifyBase()
21+
const noneFiles = new Set<string>()
22+
let isNone = false
23+
let sassVariables = false
24+
let fileImport = false
25+
const PREFIX = 'vuetify-styles/'
26+
const SSR_PREFIX = `/@${PREFIX}`
27+
const resolveCss = resolveCssFactory()
28+
29+
return <Plugin>{
30+
name: 'vuetify:styles:nuxt',
31+
enforce: 'pre',
32+
async configResolved (config) {
33+
if (config.plugins.some(plugin => plugin.name === 'vuetify:styles')) {
34+
throw new Error('Remove vite-plugin-vuetify from your Nuxt config file, this module registers a modified version.')
35+
}
36+
37+
if (isObject(options.styles)) {
38+
sassVariables = true
39+
// use file import when vite version > 5.4.2
40+
// check https://github.com/vitejs/vite/pull/17909
41+
fileImport = semver.gt(viteVersion, '5.4.2')
42+
43+
configFile = await resolvePath(options.styles.configFile)
44+
} else {
45+
isNone = options.styles === 'none'
46+
}
47+
},
48+
async resolveId (source, importer, { custom, ssr }) {
49+
if (source.startsWith(PREFIX) || source.startsWith(SSR_PREFIX)) {
50+
if (/\.s[ca]ss$/.test(source)) {
51+
return source
52+
}
53+
54+
const idx = source.indexOf('?')
55+
return idx === -1 ? source : source.slice(0, idx)
56+
}
57+
58+
if (
59+
importer
60+
&& source.endsWith('.css')
61+
&& isSubdir(vuetifyBase, path.isAbsolute(source) ? source : importer)
62+
) {
63+
const resolution = await this.resolve(source, importer, { skipSelf: true, custom })
64+
if (!resolution) {
65+
return undefined
66+
}
67+
68+
const target = await resolveCss(resolution.id)
69+
if (isNone) {
70+
noneFiles.add(target)
71+
return target
72+
}
73+
74+
return `${ssr ? SSR_PREFIX : PREFIX}${path.relative(vuetifyBase, target)}`
75+
}
76+
77+
return undefined
78+
},
79+
load (id) {
80+
if (sassVariables) {
81+
const target = id.startsWith(PREFIX)
82+
? path.resolve(vuetifyBase, id.slice(PREFIX.length))
83+
: (id.startsWith(SSR_PREFIX)
84+
? path.resolve(vuetifyBase, id.slice(SSR_PREFIX.length))
85+
: undefined)
86+
87+
if (target) {
88+
const suffix = /\.scss/.test(target) ? ';\n' : '\n'
89+
return {
90+
code: `@use "${configFile}"${suffix}@use "${fileImport ? pathToFileURL(target).href : normalizePath(target)}"${suffix}`,
91+
map: {
92+
mappings: '',
93+
},
94+
}
95+
}
96+
}
97+
return isNone && noneFiles.has(id) ? '' : undefined
98+
},
99+
}
100+
}
101+
102+
function resolveCssFactory () {
103+
const mappings = new Map<string, string>()
104+
return async (source: string) => {
105+
let mapping = mappings.get(source)
106+
if (!mapping) {
107+
try {
108+
mapping = source.replace(/\.css$/, '.sass')
109+
await fsp.access(mapping, fs.constants.R_OK)
110+
} catch (error) {
111+
if (!(error instanceof Error && 'code' in error && error.code === 'ENOENT')) {
112+
throw error
113+
}
114+
mapping = source.replace(/\.css$/, '.scss')
115+
}
116+
mappings.set(source, mapping)
117+
}
118+
return mapping
119+
}
120+
}
121+
122+
function isSubdir (root: string, test: string) {
123+
const relative = relativePath(root, test)
124+
return relative && !relative.startsWith('..') && !isAbsolute(relative)
125+
}

0 commit comments

Comments
 (0)