90 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			90 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
 | 
						|
/**
 | 
						|
 * When source maps are enabled, `style-loader` uses a link element with a data-uri to
 | 
						|
 * embed the css on the page. This breaks all relative urls because now they are relative to a
 | 
						|
 * bundle instead of the current page.
 | 
						|
 *
 | 
						|
 * One solution is to only use full urls, but that may be impossible.
 | 
						|
 *
 | 
						|
 * Instead, this function "fixes" the relative urls to be absolute according to the current page location.
 | 
						|
 *
 | 
						|
 * A rudimentary test suite is located at `test/fixUrls.js` and can be run via the `npm test` command.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
module.exports = function (css) {
 | 
						|
  // get current location
 | 
						|
  var location = typeof window !== "undefined" && window.location;
 | 
						|
 | 
						|
  if (!location) {
 | 
						|
    throw new Error("fixUrls requires window.location");
 | 
						|
  }
 | 
						|
 | 
						|
	// blank or null?
 | 
						|
	if (!css || typeof css !== "string") {
 | 
						|
	  return css;
 | 
						|
  }
 | 
						|
 | 
						|
  var baseUrl = location.protocol + "//" + location.host;
 | 
						|
  var currentDir = baseUrl + location.pathname.replace(/\/[^\/]*$/, "/");
 | 
						|
 | 
						|
	// convert each url(...)
 | 
						|
	/*
 | 
						|
	This regular expression is just a way to recursively match brackets within
 | 
						|
	a string.
 | 
						|
 | 
						|
	 /url\s*\(  = Match on the word "url" with any whitespace after it and then a parens
 | 
						|
	   (  = Start a capturing group
 | 
						|
	     (?:  = Start a non-capturing group
 | 
						|
	         [^)(]  = Match anything that isn't a parentheses
 | 
						|
	         |  = OR
 | 
						|
	         \(  = Match a start parentheses
 | 
						|
	             (?:  = Start another non-capturing groups
 | 
						|
	                 [^)(]+  = Match anything that isn't a parentheses
 | 
						|
	                 |  = OR
 | 
						|
	                 \(  = Match a start parentheses
 | 
						|
	                     [^)(]*  = Match anything that isn't a parentheses
 | 
						|
	                 \)  = Match a end parentheses
 | 
						|
	             )  = End Group
 | 
						|
              *\) = Match anything and then a close parens
 | 
						|
          )  = Close non-capturing group
 | 
						|
          *  = Match anything
 | 
						|
       )  = Close capturing group
 | 
						|
	 \)  = Match a close parens
 | 
						|
 | 
						|
	 /gi  = Get all matches, not the first.  Be case insensitive.
 | 
						|
	 */
 | 
						|
	var fixedCss = css.replace(/url\s*\(((?:[^)(]|\((?:[^)(]+|\([^)(]*\))*\))*)\)/gi, function(fullMatch, origUrl) {
 | 
						|
		// strip quotes (if they exist)
 | 
						|
		var unquotedOrigUrl = origUrl
 | 
						|
			.trim()
 | 
						|
			.replace(/^"(.*)"$/, function(o, $1){ return $1; })
 | 
						|
			.replace(/^'(.*)'$/, function(o, $1){ return $1; });
 | 
						|
 | 
						|
		// already a full url? no change
 | 
						|
		if (/^(#|data:|http:\/\/|https:\/\/|file:\/\/\/)/i.test(unquotedOrigUrl)) {
 | 
						|
		  return fullMatch;
 | 
						|
		}
 | 
						|
 | 
						|
		// convert the url to a full url
 | 
						|
		var newUrl;
 | 
						|
 | 
						|
		if (unquotedOrigUrl.indexOf("//") === 0) {
 | 
						|
		  	//TODO: should we add protocol?
 | 
						|
			newUrl = unquotedOrigUrl;
 | 
						|
		} else if (unquotedOrigUrl.indexOf("/") === 0) {
 | 
						|
			// path should be relative to the base url
 | 
						|
			newUrl = baseUrl + unquotedOrigUrl; // already starts with '/'
 | 
						|
		} else {
 | 
						|
			// path should be relative to current directory
 | 
						|
			newUrl = currentDir + unquotedOrigUrl.replace(/^\.\//, ""); // Strip leading './'
 | 
						|
		}
 | 
						|
 | 
						|
		// send back the fixed url(...)
 | 
						|
		return "url(" + JSON.stringify(newUrl) + ")";
 | 
						|
	});
 | 
						|
 | 
						|
	// send back the fixed css
 | 
						|
	return fixedCss;
 | 
						|
};
 |