Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixe hash Urls #1

Merged
merged 2 commits into from
Mar 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
64 changes: 34 additions & 30 deletions fixUrls.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
//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 url(...)
return "url(" + JSON.stringify(newUrl) + ")";
});

//send back the fixed css
// send back the fixed css
return fixedCss;
};
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -18,9 +22,5 @@
"license": "MIT",
"dependencies": {
"loader-utils": "^1.0.2"
},
"scripts": {
"test": "mocha",
"travis:test": "yarn run test"
}
}
183 changes: 183 additions & 0 deletions test/fixUrlsTest.js
Original file line number Diff line number Diff line change
@@ -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"
);
});
});