From f66757554f7a8c746c9aa4c70751ada174deb3f5 Mon Sep 17 00:00:00 2001 From: Christian Hammond Date: Mon, 27 Apr 2015 23:12:12 -0700 Subject: [PATCH] Fix synchronously loading/applying stylesheets on page load. Starting in 2.0, stylesheet loading became asynchronous, through the usage of promises for both calculating the list of stylesheets and the initial call to less.refresh(). This resulted in visual issues while loading on some browsers (noticed in Firefox and Safari), along with breakages of any custom JavaScript that depended on the computed style of elements on the page, due to race conditions. This change preserves the promise for initial page loading, in order to retain support for less.pageLoadFinished, but immediately executes the stylesheet scan (through a new less.registerStylesheetsImmediately function) and the less.refresh() call. That resulting behavior matches versions of less prior to 2.0. This unveiled a regression in registering functions, both in the browser and in unit tests, that was not previously noticed due to the asynchronous load. Registered functions would have a 'less' variable set to the less options, and not less itself, when not going through the asynchronous loading mode. This meant that both unit tests and real-world function registration would break when the sync page loading was fixed. Overriding window.less to point to the actual less module and not less.options during bootstrap fixes this. This fixes #2317. --- lib/less-browser/bootstrap.js | 11 +++++------ lib/less-browser/index.js | 30 +++++++++++++++++++----------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/lib/less-browser/bootstrap.js b/lib/less-browser/bootstrap.js index 706f98bf..30193b5c 100644 --- a/lib/less-browser/bootstrap.js +++ b/lib/less-browser/bootstrap.js @@ -13,14 +13,13 @@ require("./add-default-options")(window, options); var less = module.exports = require("./index")(window, options); +window.less = less; + if (options.onReady) { if (/!watch/.test(window.location.hash)) { less.watch(); } - less.pageLoadFinished = less.registerStylesheets().then( - function () { - return less.refresh(less.env === 'development'); - } - ); -} \ No newline at end of file + less.registerStylesheetsImmediately(); + less.pageLoadFinished = less.refresh(less.env === 'development'); +} diff --git a/lib/less-browser/index.js b/lib/less-browser/index.js index c6dc4502..376bba54 100644 --- a/lib/less-browser/index.js +++ b/lib/less-browser/index.js @@ -187,20 +187,28 @@ module.exports = function(window, options) { less.unwatch = function () {clearInterval(less.watchTimer); this.watchMode = false; return false; }; // - // Get all tags with the 'rel' attribute set to "stylesheet/less" + // Synchronously get all tags with the 'rel' attribute set to + // "stylesheet/less". + // + less.registerStylesheetsImmediately = function() { + var links = document.getElementsByTagName('link'); + less.sheets = []; + + for (var i = 0; i < links.length; i++) { + if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && + (links[i].type.match(typePattern)))) { + less.sheets.push(links[i]); + } + } + }; + + // + // Asynchronously get all tags with the 'rel' attribute set to + // "stylesheet/less", returning a Promise. // less.registerStylesheets = function() { return new Promise(function(resolve, reject) { - var links = document.getElementsByTagName('link'); - less.sheets = []; - - for (var i = 0; i < links.length; i++) { - if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && - (links[i].type.match(typePattern)))) { - less.sheets.push(links[i]); - } - } - + less.registerStylesheetsImmediately(); resolve(); }); };