@@ -2110,7 +2110,7 @@ const makeScssWorker = (
21102110 // eslint-disable-next-line no-restricted-globals -- this function runs inside a cjs worker
21112111 const sass : typeof Sass = require ( sassPath )
21122112 // eslint-disable-next-line no-restricted-globals
2113- const path = require ( 'node:path' )
2113+ const path : typeof import ( 'node:path' ) = require ( 'node:path' )
21142114
21152115 // NOTE: `sass` always runs it's own importer first, and only falls back to
21162116 // the `importer` option when it can't resolve a path
@@ -2144,11 +2144,7 @@ const makeScssWorker = (
21442144 }
21452145 : { } ) ,
21462146 }
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 ) => {
21522148 sass . render ( finalOptions , ( err , res ) => {
21532149 if ( err ) {
21542150 reject ( err )
@@ -2179,6 +2175,114 @@ const makeScssWorker = (
21792175 return worker
21802176}
21812177
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+
21822286const scssProcessor = (
21832287 maxWorkers : number | undefined ,
21842288) : SassStylePreprocessor => {
@@ -2196,7 +2300,9 @@ const scssProcessor = (
21962300 if ( ! workerMap . has ( options . alias ) ) {
21972301 workerMap . set (
21982302 options . alias ,
2199- makeScssWorker ( resolvers , options . alias , maxWorkers ) ,
2303+ options . api === 'modern'
2304+ ? makeModernScssWorker ( resolvers , options . alias , maxWorkers )
2305+ : makeScssWorker ( resolvers , options . alias , maxWorkers ) ,
22002306 )
22012307 }
22022308 const worker = workerMap . get ( options . alias ) !
@@ -2251,7 +2357,7 @@ async function rebaseUrls(
22512357 alias : Alias [ ] ,
22522358 variablePrefix : string ,
22532359 resolver : ResolveFn ,
2254- ) : Promise < Sass . LegacyImporterResult > {
2360+ ) : Promise < { file : string ; contents ?: string } > {
22552361 file = path . resolve ( file ) // ensure os-specific flashes
22562362 // in the same dir, no need to rebase
22572363 const fileDir = path . dirname ( file )
@@ -2681,7 +2787,7 @@ const createPreprocessorWorkerController = (maxWorkers: number | undefined) => {
26812787 return scss . process (
26822788 source ,
26832789 root ,
2684- { ...options , indentedSyntax : true } ,
2790+ { ...options , indentedSyntax : true , syntax : 'indented' } ,
26852791 resolvers ,
26862792 )
26872793 }
0 commit comments