1- import { utimes } from 'fs/promises'
21import * as path from 'upath'
3- import _debug from 'debug'
4- import { normalizePath as normalizeVitePath } from 'vite'
5- import { cacheDir , writeStyles , resolveVuetifyBase , normalizePath } from '@vuetify/loader-shared'
2+ import { resolveVuetifyBase , normalizePath } from '@vuetify/loader-shared'
63
7- import type { Plugin , ViteDevServer } from 'vite'
4+ import type { Plugin } from 'vite'
85import type { Options } from '@vuetify/loader-shared'
9- import type { PluginContext } from 'rollup'
10-
11- const debug = _debug ( 'vuetify:styles' )
126
137function isSubdir ( root : string , test : string ) {
148 const relative = path . relative ( root , test )
159 return relative && ! relative . startsWith ( '..' ) && ! path . isAbsolute ( relative )
1610}
1711
18- const styleImportRegexp = / ( @ u s e | m e t a \. l o a d - c s s \( ) [ ' " ] ( v u e t i f y (?: \/ l i b ) ? (?: \/ s t y l e s (?: \/ m a i n (?: \. s a s s ) ? ) ? ) ? ) [ ' " ] /
19-
2012export function stylesPlugin ( options : Options ) : Plugin {
2113 const vuetifyBase = resolveVuetifyBase ( )
22- const files = new Set < string > ( )
23-
24- let server : ViteDevServer
25- let context : PluginContext
26- let resolve : ( v : boolean ) => void
27- let promise : Promise < boolean > | null
28- let needsTouch = false
29- const blockingModules = new Set < string > ( )
30-
31- let pendingModules : string [ ]
32- async function getPendingModules ( ) {
33- if ( ! server ) {
34- await new Promise ( resolve => setTimeout ( resolve , 0 ) )
35- const modules = Array . from ( context . getModuleIds ( ) )
36- . filter ( id => {
37- return ! blockingModules . has ( id ) && // Ignore the current file
38- ! / \w \. ( s [ a c ] | c ) s s / . test ( id ) // Ignore stylesheets
39- } )
40- . map ( id => context . getModuleInfo ( id ) ! )
41- . filter ( module => module . code == null ) // Ignore already loaded modules
42-
43- pendingModules = modules . map ( module => module . id )
44- if ( ! pendingModules . length ) return 0
45-
46- const promises = modules . map ( module => context . load ( module ) )
47- await Promise . race ( promises )
48-
49- return promises . length
50- } else {
51- const modules = Array . from ( server . moduleGraph . urlToModuleMap . entries ( ) )
52- . filter ( ( [ k , v ] ) => (
53- v . transformResult == null && // Ignore already loaded modules
54- ! k . startsWith ( '/@id/' ) &&
55- ! / \w \. ( s [ a c ] | c ) s s / . test ( k ) && // Ignore stylesheets
56- ! blockingModules . has ( v . id ! ) && // Ignore the current file
57- ! / \/ n o d e _ m o d u l e s \/ \. v i t e \/ d e p s \/ (? ! v u e t i f y [ . _ ] ) / . test ( k ) // Ignore dependencies
58- ) )
59-
60- pendingModules = modules . map ( ( [ , v ] ) => v . id ! )
61- if ( ! pendingModules . length ) return 0
62-
63- const promises = modules . map ( ( [ k , v ] ) => server . transformRequest ( k ) . then ( ( ) => v ) )
64- await Promise . race ( promises )
65-
66- return promises . length
67- }
68- }
69-
70- let timeout : NodeJS . Timeout
71- async function awaitBlocking ( ) {
72- let pending
73- do {
74- clearTimeout ( timeout )
75- timeout = setTimeout ( ( ) => {
76- console . error ( 'vuetify:styles fallback timeout hit' , {
77- blockingModules : Array . from ( blockingModules . values ( ) ) ,
78- pendingModules,
79- pendingRequests : server ?. _pendingRequests . keys ( )
80- } )
81- resolve ( false )
82- } , options . stylesTimeout )
83-
84- pending = await Promise . any < boolean | number | null > ( [
85- promise ,
86- getPendingModules ( )
87- ] )
88- debug ( pending , 'pending modules' , pendingModules )
89- } while ( pending )
90-
91- resolve ( false )
92- }
93-
94- async function awaitResolve ( id ?: string ) {
95- if ( id ) {
96- blockingModules . add ( id )
97- }
98-
99- if ( ! promise ) {
100- promise = new Promise ( ( _resolve ) => resolve = _resolve )
101-
102- awaitBlocking ( )
103- await promise
104- clearTimeout ( timeout )
105- blockingModules . clear ( )
106-
107- debug ( 'writing styles' )
108- await writeStyles ( files )
109-
110- if ( server && needsTouch ) {
111- const cacheFile = normalizeVitePath ( cacheDir ( 'styles.scss' ) )
112- server . moduleGraph . getModulesByFile ( cacheFile ) ?. forEach ( module => {
113- module . importers . forEach ( module => {
114- if ( module . file ) {
115- const now = new Date ( )
116- debug ( `touching ${ module . file } ` )
117- utimes ( module . file , now , now )
118- }
119- } )
120- } )
121- needsTouch = false
122- }
123- promise = null
124- }
125-
126- return promise
127- }
12814
12915 let configFile : string
13016 const tempFiles = new Map < string , string > ( )
13117
13218 return {
13319 name : 'vuetify:styles' ,
13420 enforce : 'pre' ,
135- configureServer ( _server ) {
136- server = _server
137- } ,
138- buildStart ( ) {
139- if ( ! server ) {
140- context = this
141- }
142- } ,
14321 configResolved ( config ) {
14422 if ( typeof options . styles === 'object' ) {
14523 if ( path . isAbsolute ( options . styles . configFile ) ) {
@@ -162,23 +40,6 @@ export function stylesPlugin (options: Options): Plugin {
16240 } else if ( options . styles === 'sass' ) {
16341 const target = source . replace ( / \. c s s $ / , '.sass' )
16442 return this . resolve ( target , importer , { skipSelf : true , custom } )
165- } else if ( options . styles === 'expose' ) {
166- awaitResolve ( )
167-
168- const resolution = await this . resolve (
169- source . replace ( / \. c s s $ / , '.sass' ) ,
170- importer ,
171- { skipSelf : true , custom }
172- )
173-
174- if ( resolution ) {
175- if ( ! files . has ( resolution . id ) ) {
176- needsTouch = true
177- files . add ( resolution . id )
178- }
179-
180- return '\0__void__'
181- }
18243 } else if ( typeof options . styles === 'object' ) {
18344 const resolution = await this . resolve ( source , importer , { skipSelf : true , custom } )
18445
@@ -200,22 +61,6 @@ export function stylesPlugin (options: Options): Plugin {
20061
20162 return null
20263 } ,
203- async transform ( code , id ) {
204- if (
205- options . styles === 'expose' &&
206- [ '.scss' , '.sass' ] . some ( v => id . endsWith ( v ) ) &&
207- styleImportRegexp . test ( code )
208- ) {
209- debug ( `awaiting ${ id } ` )
210- await awaitResolve ( id )
211- debug ( `returning ${ id } ` )
212-
213- return {
214- code : code . replace ( styleImportRegexp , '$1".cache/vuetify/styles.scss"' ) ,
215- map : null ,
216- }
217- }
218- } ,
21964 load ( id ) {
22065 // When Vite is configured with `optimizeDeps.exclude: ['vuetify']`, the
22166 // received id contains a version hash (e.g. \0__void__?v=893fa859).
0 commit comments