@@ -3,6 +3,7 @@ const sass = require("sass");
33const util = require ( "util" ) ;
44const tmp = require ( "tmp" ) ;
55const path = require ( "path" ) ;
6+ const csstree = require ( "css-tree" ) ;
67
78const sassRender = util . promisify ( sass . render ) ;
89const writeFile = util . promisify ( fs . writeFile ) ;
@@ -16,20 +17,24 @@ module.exports = (options = {}) => ({
1617 build . onResolve (
1718 { filter : / .\. ( s c s s | s a s s ) $ / , namespace : "file" } ,
1819 async ( args ) => {
19- const fullFileName = path . resolve ( args . resolveDir , args . path ) ;
20- const fileExt = path . extname ( fullFileName ) ;
21- const baseFileName = path . basename ( fullFileName , fileExt ) ;
20+ const sourceFullPath = path . resolve ( args . resolveDir , args . path ) ;
21+ const sourceExt = path . extname ( sourceFullPath ) ;
22+ const sourceBaseName = path . basename ( sourceFullPath , sourceExt ) ;
23+ const sourceDir = path . dirname ( sourceFullPath ) ;
24+ const sourceRelDir = path . relative ( path . dirname ( rootDir ) , sourceDir ) ;
2225
23- const sassBuildResult = await sassRender ( { file : fullFileName } ) ;
26+ const tmpDir = path . resolve ( tmpDirPath , sourceRelDir ) ;
27+ const tmpFilePath = path . resolve ( tmpDir , `${ sourceBaseName } .css` ) ;
28+ await ensureDir ( tmpDir ) ;
2429
25- const relativeDir = path . relative (
26- path . dirname ( rootDir ) ,
27- path . dirname ( fullFileName )
28- ) ;
29- const tmpDirFullPath = path . resolve ( tmpDirPath , relativeDir ) ;
30- const tmpFilePath = path . resolve ( tmpDirFullPath , ` ${ baseFileName } .css` ) ;
31- await ensureDir ( tmpDirFullPath ) ;
32- await writeFile ( tmpFilePath , sassBuildResult . css ) ;
30+ // Compile SASS to CSS
31+ let css = ( await sassRender ( { file : sourceFullPath } ) ) . css . toString ( ) ;
32+
33+ // Replace all relative urls
34+ css = await replaceUrls ( css , tmpFilePath , sourceDir , rootDir ) ;
35+
36+ // Write result file
37+ await writeFile ( tmpFilePath , css ) ;
3338
3439 return {
3540 path : tmpFilePath ,
@@ -38,3 +43,76 @@ module.exports = (options = {}) => ({
3843 ) ;
3944 } ,
4045} ) ;
46+
47+ async function replaceUrls ( css , newCssFileName , sourceDir , rootDir ) {
48+ const ast = csstree . parse ( css ) ;
49+
50+ csstree . walk ( ast , {
51+ enter ( node ) {
52+ if ( node . type === "Url" ) {
53+ const value = node . value ;
54+ const stringValue = value . value ;
55+
56+ let normalizedUrl ;
57+ if ( value . type === "String" ) {
58+ const match = stringValue . match ( / ^ [ ' " ] ( .* ) [ " ' ] $ / s) ;
59+ if ( match ) {
60+ normalizedUrl = match [ 1 ] ;
61+ } else {
62+ normalizedUrl = stringValue ;
63+ }
64+ } else {
65+ normalizedUrl = stringValue ;
66+ }
67+
68+ if ( isLocalFileUrl ( normalizedUrl ) ) {
69+ const resolved = resolveUrl ( normalizedUrl , sourceDir , rootDir ) ;
70+ const relativePath = path . relative ( newCssFileName , resolved . file ) ;
71+
72+ node . value = {
73+ ...node . value ,
74+ type : "String" ,
75+ // disable keeping query and hash parts of original url, since esbuild doesn't support it yet
76+ // value: `"${relativePath}${resolved.query}${resolved.hash}"`,
77+ value : `"${ relativePath } "` ,
78+ } ;
79+ }
80+ }
81+ } ,
82+ } ) ;
83+
84+ return csstree . generate ( ast ) ;
85+ }
86+
87+ function isLocalFileUrl ( url ) {
88+ if ( / ^ h t t p s ? : \/ \/ / i. test ( url ) ) {
89+ return false ;
90+ }
91+ if ( / ^ d a t a : / . test ( url ) ) {
92+ return false ;
93+ }
94+ if ( / ^ # / . test ( url ) ) {
95+ return false ;
96+ }
97+
98+ return true ;
99+ }
100+
101+ function resolveUrl ( url , originalFolder , rootDir ) {
102+ const [ _ , pathname , query , hash ] = url . match ( / ^ ( .* ?) ( \? .* ?) ? ( # .* ?) ? $ / ) ;
103+
104+ let file = "" ;
105+ if ( pathname . startsWith ( "/" ) ) {
106+ file = path . resolve ( rootDir , pathname . substring ( 1 ) ) ;
107+ // todo: resolve by root dir
108+ } else {
109+ file = path . resolve ( originalFolder , pathname ) ;
110+ }
111+
112+ return {
113+ file,
114+ pathname,
115+ query : query || "" ,
116+ hash : hash || "" ,
117+ } ;
118+ }
0 commit comments