@@ -2110,7 +2110,7 @@ const makeScssWorker = (
2110
2110
// eslint-disable-next-line no-restricted-globals -- this function runs inside a cjs worker
2111
2111
const sass : typeof Sass = require ( sassPath )
2112
2112
// eslint-disable-next-line no-restricted-globals
2113
- const path = require ( 'node:path' )
2113
+ const path : typeof import ( 'node:path' ) = require ( 'node:path' )
2114
2114
2115
2115
// NOTE: `sass` always runs it's own importer first, and only falls back to
2116
2116
// the `importer` option when it can't resolve a path
@@ -2144,11 +2144,7 @@ const makeScssWorker = (
2144
2144
}
2145
2145
: { } ) ,
2146
2146
}
2147
- return new Promise < {
2148
- css : string
2149
- map ?: string | undefined
2150
- stats : Sass . LegacyResult [ 'stats' ]
2151
- } > ( ( resolve , reject ) => {
2147
+ return new Promise < ScssWorkerResult > ( ( resolve , reject ) => {
2152
2148
sass . render ( finalOptions , ( err , res ) => {
2153
2149
if ( err ) {
2154
2150
reject ( err )
@@ -2179,6 +2175,114 @@ const makeScssWorker = (
2179
2175
return worker
2180
2176
}
2181
2177
2178
+ const makeModernScssWorker = (
2179
+ resolvers : CSSAtImportResolvers ,
2180
+ alias : Alias [ ] ,
2181
+ maxWorkers : number | undefined ,
2182
+ ) => {
2183
+ const internalCanonicalize = async (
2184
+ url : string ,
2185
+ importer : string ,
2186
+ ) : Promise < string | null > => {
2187
+ importer = cleanScssBugUrl ( importer )
2188
+ const resolved = await resolvers . sass ( url , importer )
2189
+ return resolved ?? null
2190
+ }
2191
+
2192
+ const internalLoad = async ( file : string , rootFile : string ) => {
2193
+ const result = await rebaseUrls ( file , rootFile , alias , '$' , resolvers . sass )
2194
+ if ( result . contents ) {
2195
+ return result . contents
2196
+ }
2197
+ return await fsp . readFile ( result . file , 'utf-8' )
2198
+ }
2199
+
2200
+ const worker = new WorkerWithFallback (
2201
+ ( ) =>
2202
+ async (
2203
+ sassPath : string ,
2204
+ data : string ,
2205
+ // additionalData can a function that is not cloneable but it won't be used
2206
+ options : SassStylePreprocessorOptions & { additionalData : undefined } ,
2207
+ ) => {
2208
+ // eslint-disable-next-line no-restricted-globals -- this function runs inside a cjs worker
2209
+ const sass : typeof Sass = require ( sassPath )
2210
+ // eslint-disable-next-line no-restricted-globals
2211
+ const path : typeof import ( 'node:path' ) = require ( 'node:path' )
2212
+
2213
+ const { fileURLToPath, pathToFileURL } : typeof import ( 'node:url' ) =
2214
+ // eslint-disable-next-line no-restricted-globals
2215
+ require ( 'node:url' )
2216
+
2217
+ const sassOptions = { ...options } as Sass . StringOptions < 'async' >
2218
+ sassOptions . url = pathToFileURL ( options . filename )
2219
+ sassOptions . sourceMap = options . enableSourcemap
2220
+
2221
+ const internalImporter : Sass . Importer < 'async' > = {
2222
+ async canonicalize ( url , context ) {
2223
+ const importer = context . containingUrl
2224
+ ? fileURLToPath ( context . containingUrl )
2225
+ : options . filename
2226
+ const resolved = await internalCanonicalize ( url , importer )
2227
+ return resolved ? pathToFileURL ( resolved ) : null
2228
+ } ,
2229
+ async load ( canonicalUrl ) {
2230
+ const ext = path . extname ( canonicalUrl . pathname )
2231
+ let syntax : Sass . Syntax = 'scss'
2232
+ if ( ext === '.sass' ) {
2233
+ syntax = 'indented'
2234
+ } else if ( ext === '.css' ) {
2235
+ syntax = 'css'
2236
+ }
2237
+ const contents = await internalLoad (
2238
+ fileURLToPath ( canonicalUrl ) ,
2239
+ options . filename ,
2240
+ )
2241
+ return { contents, syntax }
2242
+ } ,
2243
+ }
2244
+ sassOptions . importers = [
2245
+ ...( sassOptions . importers ?? [ ] ) ,
2246
+ internalImporter ,
2247
+ ]
2248
+
2249
+ const result = await sass . compileStringAsync ( data , sassOptions )
2250
+ return {
2251
+ css : result . css ,
2252
+ map : result . sourceMap ? JSON . stringify ( result . sourceMap ) : undefined ,
2253
+ stats : {
2254
+ includedFiles : result . loadedUrls
2255
+ . filter ( ( url ) => url . protocol === 'file:' )
2256
+ . map ( ( url ) => fileURLToPath ( url ) ) ,
2257
+ } ,
2258
+ } satisfies ScssWorkerResult
2259
+ } ,
2260
+ {
2261
+ parentFunctions : {
2262
+ internalCanonicalize,
2263
+ internalLoad,
2264
+ } ,
2265
+ shouldUseFake ( _sassPath , _data , options ) {
2266
+ // functions and importer is a function and is not serializable
2267
+ // in that case, fallback to running in main thread
2268
+ return ! ! (
2269
+ ( options . functions && Object . keys ( options . functions ) . length > 0 ) ||
2270
+ ( options . importers &&
2271
+ ( ! Array . isArray ( options . importers ) || options . importers . length > 0 ) )
2272
+ )
2273
+ } ,
2274
+ max : maxWorkers ,
2275
+ } ,
2276
+ )
2277
+ return worker
2278
+ }
2279
+
2280
+ type ScssWorkerResult = {
2281
+ css : string
2282
+ map ?: string | undefined
2283
+ stats : Pick < Sass . LegacyResult [ 'stats' ] , 'includedFiles' >
2284
+ }
2285
+
2182
2286
const scssProcessor = (
2183
2287
maxWorkers : number | undefined ,
2184
2288
) : SassStylePreprocessor => {
@@ -2196,7 +2300,9 @@ const scssProcessor = (
2196
2300
if ( ! workerMap . has ( options . alias ) ) {
2197
2301
workerMap . set (
2198
2302
options . alias ,
2199
- makeScssWorker ( resolvers , options . alias , maxWorkers ) ,
2303
+ options . api === 'modern'
2304
+ ? makeModernScssWorker ( resolvers , options . alias , maxWorkers )
2305
+ : makeScssWorker ( resolvers , options . alias , maxWorkers ) ,
2200
2306
)
2201
2307
}
2202
2308
const worker = workerMap . get ( options . alias ) !
@@ -2251,7 +2357,7 @@ async function rebaseUrls(
2251
2357
alias : Alias [ ] ,
2252
2358
variablePrefix : string ,
2253
2359
resolver : ResolveFn ,
2254
- ) : Promise < Sass . LegacyImporterResult > {
2360
+ ) : Promise < { file : string ; contents ?: string } > {
2255
2361
file = path . resolve ( file ) // ensure os-specific flashes
2256
2362
// in the same dir, no need to rebase
2257
2363
const fileDir = path . dirname ( file )
@@ -2681,7 +2787,7 @@ const createPreprocessorWorkerController = (maxWorkers: number | undefined) => {
2681
2787
return scss . process (
2682
2788
source ,
2683
2789
root ,
2684
- { ...options , indentedSyntax : true } ,
2790
+ { ...options , indentedSyntax : true , syntax : 'indented' } ,
2685
2791
resolvers ,
2686
2792
)
2687
2793
}
0 commit comments