@@ -2,6 +2,12 @@ import path from 'path'
22import pify from 'pify'
33import resolve from 'resolve'
44import importCwd from 'import-cwd'
5+ import PQueue from 'p-queue'
6+
7+ // This queue makes sure node-sass leaves one thread available for executing fs tasks
8+ // See: https://github.com/sass/node-sass/issues/857
9+ const threadPoolSize = process . env . UV_THREADPOOL_SIZE || 4
10+ const workQueue = new PQueue ( { concurrency : threadPoolSize - 1 } )
511
612const moduleRe = / ^ ~ ( [ a - z 0 - 9 ] | @ ) .+ / i
713
@@ -17,54 +23,59 @@ export default {
1723 test : / \. s [ a c ] s s $ / ,
1824 async process ( { code } ) {
1925 const sass = importCwd ( 'node-sass' )
20- const res = await pify ( sass . render . bind ( sass ) ) ( {
21- ...this . options ,
22- file : this . id ,
23- data : code ,
24- indentedSyntax : / \. s a s s $ / . test ( this . id ) ,
25- sourceMap : this . sourceMap ,
26- importer : [
27- ( url , importer , done ) => {
28- if ( ! moduleRe . test ( url ) ) return done ( { file : url } )
2926
30- const moduleUrl = url . slice ( 1 )
31- const partialUrl = getUrlOfPartial ( moduleUrl )
27+ return new Promise ( ( resolve , reject ) => {
28+ workQueue . add ( ( ) =>
29+ pify ( sass . render . bind ( sass ) ) ( {
30+ ...this . options ,
31+ file : this . id ,
32+ data : code ,
33+ indentedSyntax : / \. s a s s $ / . test ( this . id ) ,
34+ sourceMap : this . sourceMap ,
35+ importer : [
36+ ( url , importer , done ) => {
37+ if ( ! moduleRe . test ( url ) ) return done ( { file : url } )
3238
33- const options = {
34- basedir : path . dirname ( importer ) ,
35- extensions : [ '.scss' , '.sass' , '.css' ]
36- }
37- const finishImport = id => {
38- done ( {
39- // Do not add `.css` extension in order to inline the file
40- file : id . endsWith ( '.css' ) ? id . replace ( / \. c s s $ / , '' ) : id
41- } )
42- }
39+ const moduleUrl = url . slice ( 1 )
40+ const partialUrl = getUrlOfPartial ( moduleUrl )
4341
44- const next = ( ) => {
45- // Catch all resolving errors, return the original file and pass responsibility back to other custom importers
46- done ( { file : url } )
47- }
42+ const options = {
43+ basedir : path . dirname ( importer ) ,
44+ extensions : [ '.scss' , '.sass' , '.css' ]
45+ }
46+ const finishImport = id => {
47+ done ( {
48+ // Do not add `.css` extension in order to inline the file
49+ file : id . endsWith ( '.css' ) ? id . replace ( / \. c s s $ / , '' ) : id
50+ } )
51+ }
4852
49- // Give precedence to importing a partial
50- resolvePromise ( partialUrl , options )
51- . then ( finishImport )
52- . catch ( err => {
53- if ( err . code === 'MODULE_NOT_FOUND' || err . code === 'ENOENT' ) {
54- resolvePromise ( moduleUrl , options )
55- . then ( finishImport )
56- . catch ( next )
57- } else {
58- next ( )
53+ const next = ( ) => {
54+ // Catch all resolving errors, return the original file and pass responsibility back to other custom importers
55+ done ( { file : url } )
5956 }
60- } )
61- }
62- ] . concat ( this . options . importer || [ ] )
63- } )
6457
65- return {
66- code : res . css . toString ( ) ,
67- map : res . map && res . map . toString ( )
68- }
58+ // Give precedence to importing a partial
59+ resolvePromise ( partialUrl , options )
60+ . then ( finishImport )
61+ . catch ( err => {
62+ if ( err . code === 'MODULE_NOT_FOUND' || err . code === 'ENOENT' ) {
63+ resolvePromise ( moduleUrl , options )
64+ . then ( finishImport )
65+ . catch ( next )
66+ } else {
67+ next ( )
68+ }
69+ } )
70+ }
71+ ] . concat ( this . options . importer || [ ] )
72+ } ) . then ( res =>
73+ resolve ( {
74+ code : res . css . toString ( ) ,
75+ map : res . map && res . map . toString ( )
76+ } )
77+ ) . catch ( reject )
78+ )
79+ } )
6980 }
7081}
0 commit comments