@@ -37,8 +37,16 @@ function toScssImportPath(filePath) {
3737 return String ( filePath ) . replace ( / \\ / g, '/' ) . replace ( / " / g, '\\"' ) ;
3838}
3939
40+ const resolutionCache = new Map ( ) ;
41+
4042function resolveScssCandidate ( rawPath ) {
4143 const normalizedPath = path . resolve ( rawPath ) ;
44+
45+ const cached = resolutionCache . get ( normalizedPath ) ;
46+ if ( cached !== undefined ) {
47+ return cached ;
48+ }
49+
4250 const extension = path . extname ( normalizedPath ) ;
4351 const hasResolvableExtension = [ '.scss' , '.sass' , '.css' ] . includes ( extension ) ;
4452 const dirname = path . dirname ( normalizedPath ) ;
@@ -64,16 +72,44 @@ function resolveScssCandidate(rawPath) {
6472 for ( const candidate of candidates ) {
6573 try {
6674 if ( fs . statSync ( candidate ) . isFile ( ) ) {
75+ resolutionCache . set ( normalizedPath , candidate ) ;
6776 return candidate ;
6877 }
6978 } catch ( _error ) {
7079 // not found
7180 }
7281 }
7382
83+ resolutionCache . set ( normalizedPath , null ) ;
7484 return null ;
7585}
7686
87+ function invalidateResolutionCacheForChangedFiles ( changedFiles , projectRoot ) {
88+ if ( ! changedFiles || changedFiles . length === 0 ) {
89+ return ;
90+ }
91+
92+ const absolutePaths = new Set ( ) ;
93+ for ( const file of changedFiles ) {
94+ if ( typeof file !== 'string' || file === '' ) {
95+ continue ;
96+ }
97+
98+ const abs = path . isAbsolute ( file ) ? file : path . resolve ( projectRoot , file ) ;
99+ absolutePaths . add ( abs ) ;
100+ }
101+
102+ if ( absolutePaths . size === 0 ) {
103+ return ;
104+ }
105+
106+ for ( const [ key , value ] of resolutionCache ) {
107+ if ( absolutePaths . has ( key ) || ( value && absolutePaths . has ( value ) ) ) {
108+ resolutionCache . delete ( key ) ;
109+ }
110+ }
111+ }
112+
77113function toWatchedFilePath ( item ) {
78114 if ( typeof item === 'string' ) {
79115 return item ;
@@ -131,6 +167,8 @@ function createScssSidecar(projectRoot) {
131167 const scssSourceMapEnabled = asString ( process . env . SHOPWARE_STOREFRONT_SCSS_SOURCE_MAP , '1' ) === '1' ;
132168 const silenceDeprecations = asString ( process . env . SHOPWARE_STOREFRONT_SASS_SILENCE_DEPRECATIONS , '1' ) === '1' ;
133169
170+ const fileContentCache = new Map ( ) ;
171+
134172 const state = {
135173 subscribers : new Set ( ) ,
136174 watchpack : null ,
@@ -173,22 +211,24 @@ function createScssSidecar(projectRoot) {
173211
174212 function resolveSassImplementation ( ) {
175213 try {
176- const embedded = storefrontRequire ( 'sass-embedded' ) ;
177- console . log ( '[SidworksDevTools] SCSS sidecar uses sass-embedded from storefront' ) ;
178- return embedded ;
214+ return storefrontRequire ( 'sass-embedded' ) ;
179215 } catch ( _error ) {
180216 try {
181- const embedded = runtimeRequire ( 'sass-embedded' ) ;
182- console . log ( '[SidworksDevTools] SCSS sidecar uses sass-embedded from runtime' ) ;
183- return embedded ;
217+ return runtimeRequire ( 'sass-embedded' ) ;
184218 } catch ( _runtimeError ) {
185- const sass = storefrontRequire ( 'sass' ) ;
186- console . log ( '[SidworksDevTools] SCSS sidecar fallback: using sass' ) ;
187- return sass ;
219+ return storefrontRequire ( 'sass' ) ;
188220 }
189221 }
190222 }
191223
224+ function describeSassImplementation ( ) {
225+ const info = String ( state . sassImplementation ?. info || '' ) . toLowerCase ( ) ;
226+ if ( info . includes ( 'sass-embedded' ) ) {
227+ return 'sass-embedded' ;
228+ }
229+ return 'sass' ;
230+ }
231+
192232 function findTildeImport ( url ) {
193233 if ( ! url || typeof url !== 'string' || ! url . startsWith ( '~' ) ) {
194234 return null ;
@@ -331,10 +371,7 @@ function createScssSidecar(projectRoot) {
331371 writeGeneratedThemeEntry ( generatedEntryContent ) ;
332372 state . activeEntryPath = generatedThemeEntryPath ;
333373
334- if ( ! state . loggedGeneratedEntryInfo ) {
335- console . log ( '[SidworksDevTools] SCSS sidecar uses generated entry from theme-files.json' ) ;
336- state . loggedGeneratedEntryInfo = true ;
337- }
374+ state . loggedGeneratedEntryInfo = true ;
338375
339376 return generatedThemeEntryPath ;
340377 }
@@ -413,6 +450,9 @@ function createScssSidecar(projectRoot) {
413450 async function compileAndWatch ( reason , changedFiles = [ ] ) {
414451 if ( ! state . sassImplementation ) {
415452 state . sassImplementation = resolveSassImplementation ( ) ;
453+ const engine = describeSassImplementation ( ) ;
454+ const persistent = typeof state . sassImplementation . initAsyncCompiler === 'function' ? ', persistent' : '' ;
455+ log . log ( `${ engine } ${ persistent } ` ) ;
416456 }
417457
418458 const fileSummary = summarizeFiles ( changedFiles ) ;
@@ -431,6 +471,8 @@ function createScssSidecar(projectRoot) {
431471 }
432472
433473 state . compileInFlight = true ;
474+ fileContentCache . clear ( ) ;
475+ invalidateResolutionCacheForChangedFiles ( changedFiles , rootPath ) ;
434476 const startedAt = Date . now ( ) ;
435477 log . status ( 'RUN' , `compiling (${ reasonLabel } )` ) ;
436478
@@ -491,7 +533,6 @@ function createScssSidecar(projectRoot) {
491533 const sass = state . sassImplementation ;
492534 if ( typeof sass . initAsyncCompiler === 'function' ) {
493535 state . persistentCompiler = await sass . initAsyncCompiler ( ) ;
494- console . log ( '[SidworksDevTools] SCSS persistent compiler initialized (Dart VM kept alive)' ) ;
495536 return state . persistentCompiler ;
496537 }
497538
@@ -545,7 +586,11 @@ function createScssSidecar(projectRoot) {
545586 } ,
546587 load ( canonicalUrl ) {
547588 const resolvedPath = fileURLToPath ( canonicalUrl ) ;
548- const contents = fs . readFileSync ( resolvedPath , 'utf8' ) ;
589+ let contents = fileContentCache . get ( resolvedPath ) ;
590+ if ( contents === undefined ) {
591+ contents = fs . readFileSync ( resolvedPath , 'utf8' ) ;
592+ fileContentCache . set ( resolvedPath , contents ) ;
593+ }
549594
550595 if ( resolvedPath . endsWith ( '.sass' ) ) {
551596 return { contents, syntax : 'indented' } ;
0 commit comments