From e7c0d722b13ab47a445e7b448cf90334e761a78f Mon Sep 17 00:00:00 2001 From: John Anderson Date: Thu, 9 Mar 2017 11:52:13 -0600 Subject: [PATCH 1/2] Fixe hash Urls --- README.md | 2 +- fixUrls.js | 66 ++++++++++++++++++++++++++++------------------------ package.json | 8 +++---- 3 files changed, 40 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index e0eda40b..d6cc3b40 100644 --- a/README.md +++ b/README.md @@ -155,4 +155,4 @@ MIT [deps-url]: https://david-dm.org/webpack/file-loader [chat]: https://badges.gitter.im/webpack/webpack.svg -[chat-url]: https://gitter.im/webpack/webpack +[chat-url]: https://gitter.im/webpack/webpack \ No newline at end of file diff --git a/fixUrls.js b/fixUrls.js index 91e2d9d1..c60ef6cb 100644 --- a/fixUrls.js +++ b/fixUrls.js @@ -11,48 +11,52 @@ * 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; -module.exports = function (css, currentUrl) { + if (!location) { + throw new Error("fixUrls requires window.location"); + } - // get current url - currentUrl = currentUrl || (typeof window !== "undefined" && window.location && window.location.href) || null; - if (typeof currentUrl != "string") { - throw new Error("fixUrls requires a current url"); - } - - //blank or null? - if (!css || typeof css !== "string") + // blank or null? + if (!css || typeof css !== "string") { return css; + } - //base url - var baseUrl = currentUrl.match(/^([a-z]+:)?(\/\/)?[^\/]+/)[0]; - var currentUrlPath = baseUrl + (currentUrl.replace(baseUrl, "")).replace(/\/[^\/]+$/, "") + "/"; + var baseUrl = location.protocol + location.host; + var currentDir = baseUrl + location.pathname.replace(/\/[^\/]*$/, "/"); - //convert each url(...) - var fixedCss = css.replace(/url *\( *(.+?) *\)/g, function(fullMatch, origUrl){ - //strip quotes (if they exist) + // convert each url(...) + var fixedCss = css.replace(/url *\( *(.+?) *\)/g, function(fullMatch, origUrl) { + // strip quotes (if they exist) var unquotedOrigUrl = origUrl - .replace(/^"(.*)"$/, function(o,$1){ return $1; }) - .replace(/^'(.*)'$/, function(o,$1){ return $1; }); + .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)) + // 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 = unquotedOrigUrl; - if (newUrl.indexOf("/") === 0){ - //path should be relative to the base url - newUrl = baseUrl + newUrl; - }else{ - //path should be relative to the current directory - newUrl = currentUrlPath + newUrl.replace(/^\.\//, ""); + } + + // convert the url to a full url + var newUrl; + + if (unquotedOrigUrl.indexOf("//") === 0) { + // add protocol + newUrl = location.protocol + 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 url(...) + return "url(" + JSON.stringify(newUrl) + ")"; }); - //send back the fixed css + // send back the fixed css return fixedCss; }; diff --git a/package.json b/package.json index ff7979f4..242c3a74 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,10 @@ "version": "0.13.2", "author": "Tobias Koppers @sokra", "description": "style loader module for webpack", + "scripts": { + "test": "mocha", + "travis:test": "yarn run test" + }, "devDependencies": { "css-loader": "~0.8.0", "file-loader": "^0.10.1", @@ -18,9 +22,5 @@ "license": "MIT", "dependencies": { "loader-utils": "^1.0.2" - }, - "scripts": { - "test": "mocha", - "travis:test": "yarn run test" } } From d29da2f2b9b04e5a998116fcd4de0faf266c4e62 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Thu, 9 Mar 2017 12:49:35 -0600 Subject: [PATCH 2/2] Fix the hash code --- fixUrls.js | 12 +-- test/fixUrlsTest.js | 183 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+), 6 deletions(-) create mode 100644 test/fixUrlsTest.js diff --git a/fixUrls.js b/fixUrls.js index c60ef6cb..7ba65dea 100644 --- a/fixUrls.js +++ b/fixUrls.js @@ -24,7 +24,7 @@ module.exports = function (css) { return css; } - var baseUrl = location.protocol + location.host; + var baseUrl = location.protocol + "//" + location.host; var currentDir = baseUrl + location.pathname.replace(/\/[^\/]*$/, "/"); // convert each url(...) @@ -37,20 +37,20 @@ module.exports = function (css) { // 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) { - // add protocol - newUrl = location.protocol + unquotedOrigUrl; + //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 './' + // path should be relative to current directory + newUrl = currentDir + unquotedOrigUrl.replace(/^\.\//, ""); // Strip leading './' } // send back the fixed url(...) diff --git a/test/fixUrlsTest.js b/test/fixUrlsTest.js new file mode 100644 index 00000000..d41da4cd --- /dev/null +++ b/test/fixUrlsTest.js @@ -0,0 +1,183 @@ +// Node v4 requires "use strict" to allow block scoped let & const +"use strict"; +var assert = require("assert"); +var url = require('url'); + +describe("fix urls tests", function() { + var fixUrls = require("../fixUrls"); + var defaultUrl = "https://x.y.z/a/b.html"; + + beforeEach(function() { + global.window = { + location: url.parse(defaultUrl) + }; + }); + + var assertUrl = function (origCss, expectedCss, specialUrl) { + if (specialUrl) { + global.window = { + location: url.parse(specialUrl) + }; + } + var resultCss = fixUrls(origCss, specialUrl || defaultUrl); + expectedCss = expectedCss || origCss; + + assert.equal(resultCss, expectedCss); + }; + + // no change + it("Null css is not modified", function() { + assertUrl(null) + }); + + it("Blank css is not modified", function() { assertUrl("") }); + + it("No url is not modified", function () { assertUrl("body { }") }); + + it("Full url isn't changed (no quotes)", function() { + assertUrl("body { background-image:url(http://example.com/bg.jpg); }") + }); + + it("Full url isn't changed (no quotes, spaces)", function() { + assertUrl("body { background-image:url ( http://example.com/bg.jpg ); }"); + }); + + it("Full url isn't changed (double quotes)", function() { + assertUrl("body { background-image:url(\"http://example.com/bg.jpg\"); }") + }); + + it("Full url isn't changed (double quotes, spaces)", function() { + assertUrl("body { background-image:url ( \"http://example.com/bg.jpg\" ); }") + }); + + it("Full url isn't changed (single quotes)", function() { + assertUrl("body { background-image:url('http://example.com/bg.jpg'); }") + }); + + it("Full url isn't changed (single quotes, spaces)", function() { + assertUrl("body { background-image:url ( 'http://example.com/bg.jpg' ); }") + }); + + it("Multiple full urls are not changed", function() { + assertUrl( + "body { background-image:url(http://example.com/bg.jpg); }\ndiv.main { background-image:url ( 'https://www.anothersite.com/another.png' ); }" + ); + }); + + it("Http url isn't changed", function() { + assertUrl("body { background-image:url(http://example.com/bg.jpg); }"); + }); + + it("Https url isn't changed", function() { + assertUrl("body { background-image:url(https://example.com/bg.jpg); }"); + }); + + it("HTTPS url isn't changed", function() { + assertUrl("body { background-image:url(HTTPS://example.com/bg.jpg); }") + }); + + it("File url isn't changed", function() { + assertUrl("body { background-image:url(file:///example.com/bg.jpg); }") + }); + + it("Double slash url isn't changed", function() { + assertUrl( + "body { background-image:url(//example.com/bg.jpg); }", + "body { background-image:url(\"//example.com/bg.jpg\"); }" + ) + }); + + it("Image data uri url isn't changed", function() { + assertUrl("body { background-image:url(data:image/png;base64,qsrwABYuwNkimqm3gAAAABJRU5ErkJggg==); }") + }); + + it("Font data uri url isn't changed", function() { + assertUrl( + "body { background-image:url(data:application/x-font-woff;charset=utf-8;base64,qsrwABYuwNkimqm3gAAAABJRU5ErkJggg); }" + ); + }); + + // relative urls + it("Relative url", function() { + assertUrl( + "body { background-image:url(bg.jpg); }", + "body { background-image:url(\"https://x.y.z/a/bg.jpg\"); }" + ); + }); + + it("Relative url with path", function() { + assertUrl( + "body { background-image:url(c/d/bg.jpg); }", + "body { background-image:url(\"https://x.y.z/a/c/d/bg.jpg\"); }" + ); + }); + it("Relative url with dot slash", function() { + assertUrl( + "body { background-image:url(./c/d/bg.jpg); }", + "body { background-image:url(\"https://x.y.z/a/c/d/bg.jpg\"); }" + ); + }); + + it("Multiple relative urls", function() { + assertUrl( + "body { background-image:url(bg.jpg); }\ndiv.main { background-image:url(./c/d/bg.jpg); }", + "body { background-image:url(\"https://x.y.z/a/bg.jpg\"); }\ndiv.main { background-image:url(\"https://x.y.z/a/c/d/bg.jpg\"); }" + ); + }); + it("Relative url that looks like data-uri", function() { + assertUrl( + "body { background-image:url(data/image/png.base64); }", + "body { background-image:url(\"https://x.y.z/a/data/image/png.base64\"); }" + ); + }); + + // urls with hashes + it("Relative url with hash are not changed", function() { + assertUrl("body { background-image:url(#bg.jpg); }"); + }); + + // rooted urls + it("Rooted url", function() { + assertUrl( + "body { background-image:url(/bg.jpg); }", + "body { background-image:url(\"https://x.y.z/bg.jpg\"); }" + ); + }); + it("Rooted url with path", function() { + assertUrl( + "body { background-image:url(/a/b/bg.jpg); }", + "body { background-image:url(\"https://x.y.z/a/b/bg.jpg\"); }" + ); + }); + + //special locations + it("Location with no path, filename only", function() { + assertUrl( + "body { background-image:url(bg.jpg); }", + "body { background-image:url(\"http://x.y.z/bg.jpg\"); }", + "http://x.y.z" + ); + }); + + it("Location with no path, path with filename", function() { + assertUrl( + "body { background-image:url(a/bg.jpg); }", + "body { background-image:url(\"http://x.y.z/a/bg.jpg\"); }", + "http://x.y.z" + ); + }); + it("Location with no path, rel path with filename", function() { + assertUrl( + "body { background-image:url(./a/bg.jpg); }", + "body { background-image:url(\"http://x.y.z/a/bg.jpg\"); }", + "http://x.y.z" + ); + }); + it("Location with no path, root filename", function() { + assertUrl( + "body { background-image:url(/a/bg.jpg); }", + "body { background-image:url(\"http://x.y.z/a/bg.jpg\"); }", + "http://x.y.z" + ); + }); +});