mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Fix CSS URL rewriting for application deployed under a sub path
Fixes #5837
This commit is contained in:
@@ -81,7 +81,8 @@ CssTools = {
|
||||
// For performance reasons this function acts by side effect by modifying the
|
||||
// given AST without doing a deep copy.
|
||||
rewriteCssUrls: function (ast) {
|
||||
rewriteRules(ast.stylesheet.rules);
|
||||
var mergedCssPath = "/";
|
||||
rewriteRules(ast.stylesheet.rules, mergedCssPath);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -94,7 +95,7 @@ if (typeof Profile !== 'undefined') {
|
||||
});
|
||||
}
|
||||
|
||||
var rewriteRules = function (rules) {
|
||||
var rewriteRules = function (rules, mergedCssPath) {
|
||||
_.each(rules, function(rule, ruleIndex) {
|
||||
|
||||
// Recurse if there are sub-rules. An example:
|
||||
@@ -102,10 +103,10 @@ var rewriteRules = function (rules) {
|
||||
// .rule { url(...); }
|
||||
// }
|
||||
if (_.has(rule, 'rules')) {
|
||||
rewriteRules(rule.rules);
|
||||
rewriteRules(rule.rules, mergedCssPath);
|
||||
}
|
||||
|
||||
var basePath = pathDirname(rule.position.source);
|
||||
var basePath = pathJoin("/", pathDirname(rule.position.source));
|
||||
|
||||
// Set the correct basePath based on how the linked asset will be served.
|
||||
// XXX This is wrong. We are coupling the information about how files will
|
||||
@@ -119,7 +120,7 @@ var rewriteRules = function (rules) {
|
||||
basePath = "/";
|
||||
|
||||
_.each(rule.declarations, function(declaration, declarationIndex) {
|
||||
var parts, resource, absolutePath, quotes, oldCssUrl, newCssUrl;
|
||||
var parts, resource, absolutePath, relativeToMergedCss, quote, oldCssUrl, newCssUrl;
|
||||
var value = declaration.value;
|
||||
|
||||
// Match css values containing some functional calls to `url(URI)` where
|
||||
@@ -130,17 +131,39 @@ var rewriteRules = function (rules) {
|
||||
var cssUrlRegex = /url\s*\(\s*(['"]?)(.+?)\1\s*\)/gi;
|
||||
while (parts = cssUrlRegex.exec(value)) {
|
||||
oldCssUrl = parts[0];
|
||||
quotes = parts[1];
|
||||
quote = parts[1];
|
||||
resource = url.parse(parts[2]);
|
||||
|
||||
// Rewrite relative paths to absolute paths.
|
||||
// We don't rewrite urls starting with a protocol definition such as
|
||||
|
||||
// We don't rewrite URLs starting with a protocol definition such as
|
||||
// http, https, or data.
|
||||
if (isRelative(resource.path) && resource.protocol === null) {
|
||||
absolutePath = pathJoin(basePath, resource.path);
|
||||
newCssUrl = "url(" + quotes + absolutePath + quotes + ")";
|
||||
value = value.replace(oldCssUrl, newCssUrl);
|
||||
if (resource.protocol !== null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Rewrite relative paths (that refers to the internal application tree)
|
||||
// to absolute paths (addressable from the public build).
|
||||
if (isRelative(resource.path)) {
|
||||
absolutePath = pathJoin(basePath, resource.path);
|
||||
} else {
|
||||
absolutePath = resource.path;
|
||||
}
|
||||
|
||||
// We used to finish the rewriting process at the absolute path step
|
||||
// above. But it didn't work in case the Meteor application was deployed
|
||||
// under a sub-path (eg `ROOT_URL=http://localhost:3000/myapp meteor`)
|
||||
// in which case the resources linked in the merged CSS file would miss
|
||||
// the `myapp/` prefix. Since this path prefix is only known at launch
|
||||
// time (rather than build time) we can't use absolute paths to link
|
||||
// resources in the generated CSS.
|
||||
//
|
||||
// Instead we transform absolute paths to make them relative to the
|
||||
// merged CSS, leaving to the browser the responsibility to calculate
|
||||
// the final resource links (by adding the application deployment
|
||||
// prefix, here `myapp/`, if applicable).
|
||||
relativeToMergedCss = path.relative(mergedCssPath, absolutePath);
|
||||
newCssUrl = "url(" + quote + relativeToMergedCss + quote + ")";
|
||||
value = value.replace(oldCssUrl, newCssUrl);
|
||||
}
|
||||
|
||||
declaration.value = value;
|
||||
@@ -154,7 +177,7 @@ var isRelative = function(path) {
|
||||
|
||||
// These are duplicates of functions in tools/files.js, because we don't have
|
||||
// a good way of exporting them into packages.
|
||||
// XXX deduplicate files.js into a package at somepoint so that we can use it
|
||||
// XXX deduplicate files.js into a package at some point so that we can use it
|
||||
// in core
|
||||
var toOSPath = function (p) {
|
||||
if (process.platform === 'win32')
|
||||
@@ -177,3 +200,4 @@ var pathJoin = function (a, b) {
|
||||
var pathDirname = function (p) {
|
||||
return toStandardPath(path.dirname(toOSPath(p)));
|
||||
};
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@ Tinytest.add("minifier-css - url rewriting when merging", function (test) {
|
||||
t('./image.png', 'packages/nameOfPackage/image.png', 'current directory');
|
||||
t('./child/image.png', 'packages/nameOfPackage/child/image.png', 'child directory');
|
||||
t('child/image.png', 'packages/nameOfPackage/child/image.png', 'child directory');
|
||||
t('/image.png', '/image.png', 'absolute url');
|
||||
t('"/image.png"', '"/image.png"', 'double quoted url');
|
||||
t("'/image.png'", "'/image.png'", 'single quoted url');
|
||||
t('/image.png', 'image.png', 'absolute url');
|
||||
t('"/image.png"', '"image.png"', 'double quoted url');
|
||||
t("'/image.png'", "'image.png'", 'single quoted url');
|
||||
t('"./../image.png"', '"packages/image.png"', 'quoted parent directory');
|
||||
t('http://i.imgur.com/fBcdJIh.gif', 'http://i.imgur.com/fBcdJIh.gif', 'complete URL');
|
||||
t('"http://i.imgur.com/fBcdJIh.gif"', '"http://i.imgur.com/fBcdJIh.gif"', 'complete quoted URL');
|
||||
@@ -32,12 +32,12 @@ Tinytest.add("minifier-css - url rewriting when merging", function (test) {
|
||||
t('http://', 'http://', 'malformed URL');
|
||||
|
||||
parseOptions.source = 'application/client/dir/other-style.css';
|
||||
t('./image.png', '/image.png', 'base path is root');
|
||||
t('./child/image.png', '/child/image.png', 'child directory from root');
|
||||
t('child/image.png', '/child/image.png', 'child directory from root');
|
||||
t('/image.png', '/image.png', 'absolute url');
|
||||
t('"/image.png"', '"/image.png"', 'double quoted url');
|
||||
t("'/image.png'", "'/image.png'", 'single quoted url');
|
||||
t('./image.png', 'image.png', 'base path is root');
|
||||
t('./child/image.png', 'child/image.png', 'child directory from root');
|
||||
t('child/image.png', 'child/image.png', 'child directory from root');
|
||||
t('/image.png', 'image.png', 'absolute url');
|
||||
t('"/image.png"', '"image.png"', 'double quoted url');
|
||||
t("'/image.png'", "'image.png'", 'single quoted url');
|
||||
t('http://i.imgur.com/fBcdJIh.gif', 'http://i.imgur.com/fBcdJIh.gif', 'complete URL');
|
||||
t('"http://i.imgur.com/fBcdJIh.gif"', '"http://i.imgur.com/fBcdJIh.gif"', 'complete quoted URL');
|
||||
t('data:image/png;base64,iVBORw0K=', 'data:image/png;base64,iVBORw0K=', 'data URI');
|
||||
@@ -73,9 +73,9 @@ Tinytest.add("minifier-css - url rewriting with media queries (ast rule recursio
|
||||
t('./image.png', 'packages/nameOfPackage/image.png', 'current directory');
|
||||
t('./child/image.png', 'packages/nameOfPackage/child/image.png', 'child directory');
|
||||
t('child/image.png', 'packages/nameOfPackage/child/image.png', 'child directory');
|
||||
t('/image.png', '/image.png', 'absolute url');
|
||||
t('"/image.png"', '"/image.png"', 'double quoted url');
|
||||
t("'/image.png'", "'/image.png'", 'single quoted url');
|
||||
t('/image.png', 'image.png', 'absolute url');
|
||||
t('"/image.png"', '"image.png"', 'double quoted url');
|
||||
t("'/image.png'", "'image.png'", 'single quoted url');
|
||||
t('"./../image.png"', '"packages/image.png"', 'quoted parent directory');
|
||||
t('http://i.imgur.com/fBcdJIh.gif', 'http://i.imgur.com/fBcdJIh.gif', 'complete URL');
|
||||
t('"http://i.imgur.com/fBcdJIh.gif"', '"http://i.imgur.com/fBcdJIh.gif"', 'complete quoted URL');
|
||||
@@ -83,12 +83,12 @@ Tinytest.add("minifier-css - url rewriting with media queries (ast rule recursio
|
||||
t('http://', 'http://', 'malformed URL');
|
||||
|
||||
parseOptions.source = 'application/client/dir/other-style.css';
|
||||
t('./image.png', '/image.png', 'base path is root');
|
||||
t('./child/image.png', '/child/image.png', 'child directory from root');
|
||||
t('child/image.png', '/child/image.png', 'child directory from root');
|
||||
t('/image.png', '/image.png', 'absolute url');
|
||||
t('"/image.png"', '"/image.png"', 'double quoted url');
|
||||
t("'/image.png'", "'/image.png'", 'single quoted url');
|
||||
t('./image.png', 'image.png', 'base path is root');
|
||||
t('./child/image.png', 'child/image.png', 'child directory from root');
|
||||
t('child/image.png', 'child/image.png', 'child directory from root');
|
||||
t('/image.png', 'image.png', 'absolute url');
|
||||
t('"/image.png"', '"image.png"', 'double quoted url');
|
||||
t("'/image.png'", "'image.png'", 'single quoted url');
|
||||
t('http://i.imgur.com/fBcdJIh.gif', 'http://i.imgur.com/fBcdJIh.gif', 'complete URL');
|
||||
t('"http://i.imgur.com/fBcdJIh.gif"', '"http://i.imgur.com/fBcdJIh.gif"', 'complete quoted URL');
|
||||
t('data:image/png;base64,iVBORw0K=', 'data:image/png;base64,iVBORw0K=', 'data URI');
|
||||
|
||||
Reference in New Issue
Block a user