Skip to content

Commit

Permalink
fix: order of imported styles (#443)
Browse files Browse the repository at this point in the history
  • Loading branch information
evilebottnawi committed Dec 20, 2019
1 parent a283b30 commit c7d6e3a
Show file tree
Hide file tree
Showing 9 changed files with 301 additions and 104 deletions.
7 changes: 5 additions & 2 deletions src/index.js
Expand Up @@ -159,7 +159,9 @@ if (content.locals) {
exported.use = function() {
if (!(refs++)) {
dispose = api(content, options);
var id = ${loaderUtils.stringifyRequest(this, `!!${request}`)};
dispose = api(id, content, options);
}
return exported;
Expand Down Expand Up @@ -248,7 +250,8 @@ var options = ${JSON.stringify(options)};
options.insert = ${insert};
options.singleton = ${isSingleton};
var update = api(content, options);
var id = ${loaderUtils.stringifyRequest(this, `!!${request}`)};
var update = api(id, content, options);
var exported = content.locals ? content.locals : {};
Expand Down
106 changes: 28 additions & 78 deletions src/runtime/injectStylesIntoStyleTag.js
Expand Up @@ -46,70 +46,51 @@ const getTarget = (function getTarget() {
};
})();

function listToStyles(list, options) {
const styles = [];
const newStyles = {};
function addModulesToDom(id, list, options) {
id = options.base ? id + options.base : id;

if (!stylesInDom[id]) {
stylesInDom[id] = [];
}

for (let i = 0; i < list.length; i++) {
const item = list[i];
const id = options.base ? item[0] + options.base : item[0];
const css = item[1];
const media = item[2];
const sourceMap = item[3];
const part = { css, media, sourceMap };

if (!newStyles[id]) {
styles.push((newStyles[id] = { id, parts: [part] }));
const part = { css: item[1], media: item[2], sourceMap: item[3] };
const styleInDomById = stylesInDom[id];

if (styleInDomById[i]) {
styleInDomById[i].updater(part);
} else {
newStyles[id].parts.push(part);
styleInDomById.push({ updater: addStyle(part, options) });
}
}

return styles;
}

function addStylesToDom(styles, options) {
for (let i = 0; i < styles.length; i++) {
const item = styles[i];
const domStyle = stylesInDom[item.id];
let j = 0;

if (domStyle) {
domStyle.refs++;

for (; j < domStyle.parts.length; j++) {
domStyle.parts[j](item.parts[j]);
}
for (let j = list.length; j < stylesInDom[id].length; j++) {
stylesInDom[id][j].updater();
}

for (; j < item.parts.length; j++) {
domStyle.parts.push(addStyle(item.parts[j], options));
}
} else {
const parts = [];
stylesInDom[id].length = list.length;

for (; j < item.parts.length; j++) {
parts.push(addStyle(item.parts[j], options));
}

stylesInDom[item.id] = { id: item.id, refs: 1, parts };
}
if (stylesInDom[id].length === 0) {
delete stylesInDom[id];
}
}

function insertStyleElement(options) {
const style = document.createElement('style');
const attributes = options.attributes || {};

if (typeof options.attributes.nonce === 'undefined') {
if (typeof attributes.nonce === 'undefined') {
const nonce =
typeof __webpack_nonce__ !== 'undefined' ? __webpack_nonce__ : null;

if (nonce) {
options.attributes.nonce = nonce;
attributes.nonce = nonce;
}
}

Object.keys(options.attributes).forEach((key) => {
style.setAttribute(key, options.attributes[key]);
Object.keys(attributes).forEach((key) => {
style.setAttribute(key, attributes[key]);
});

if (typeof options.insert === 'function') {
Expand Down Expand Up @@ -179,6 +160,8 @@ function applyToTag(style, options, obj) {

if (media) {
style.setAttribute('media', media);
} else {
style.removeAttribute('media');
}

if (sourceMap && btoa) {
Expand Down Expand Up @@ -243,51 +226,18 @@ function addStyle(obj, options) {
};
}

module.exports = (list, options) => {
module.exports = (id, list, options) => {
options = options || {};

options.attributes =
typeof options.attributes === 'object' ? options.attributes : {};

// Force single-tag solution on IE6-9, which has a hard limit on the # of <style>
// tags it will allow on a page
if (!options.singleton && typeof options.singleton !== 'boolean') {
options.singleton = isOldIE();
}

const styles = listToStyles(list, options);

addStylesToDom(styles, options);
addModulesToDom(id, list, options);

return function update(newList) {
const mayRemove = [];

for (let i = 0; i < styles.length; i++) {
const item = styles[i];
const domStyle = stylesInDom[item.id];

if (domStyle) {
domStyle.refs--;
mayRemove.push(domStyle);
}
}

if (newList) {
const newStyles = listToStyles(newList, options);

addStylesToDom(newStyles, options);
}

for (let i = 0; i < mayRemove.length; i++) {
const domStyle = mayRemove[i];

if (domStyle.refs === 0) {
for (let j = 0; j < domStyle.parts.length; j++) {
domStyle.parts[j]();
}

delete stylesInDom[domStyle.id];
}
}
addModulesToDom(id, newList || [], options);
};
};
7 changes: 6 additions & 1 deletion test/manual/index.html
Expand Up @@ -66,7 +66,12 @@ <h3>Use/Unuse</h3>
</section>

<section>
<h3>Custom element</h3>
<h2>Order</h2>
<div class="order">BACKGROUND SHOULD BE RED</div>
</section>

<section>
<h2>Custom element</h2>
<custom-square l="100" c="red"></custom-square>
</section>

Expand Down
1 change: 1 addition & 0 deletions test/manual/src/index.js
Expand Up @@ -8,6 +8,7 @@ import useUnse from './use-unuse.lazy.css';
import otherStyleLazy from './other-style.lazy.scss';
import componentLazy from './component.lazy.module.css';
import './style.link.css';
import './order.css';
import './custom-square';

console.log('___LOCALS___');
Expand Down
3 changes: 3 additions & 0 deletions test/manual/src/order-1.css
@@ -0,0 +1,3 @@
.order {
background: red;
}
3 changes: 3 additions & 0 deletions test/manual/src/order-2.css
@@ -0,0 +1,3 @@
.order {
background: blue;
}
13 changes: 13 additions & 0 deletions test/manual/src/order.css
@@ -0,0 +1,13 @@
@import url('./order-1.css');
@import url('https://fonts.googleapis.com/css?family=Roboto&display=swap');
@import url('./order-2.css');
@import url('https://fonts.googleapis.com/css?family=Roboto&display=swap');
@import url('./order-1.css');
@import url('https://fonts.googleapis.com/css?family=Roboto&display=swap');
@import url('./order-2.css') screen and (min-width: 2000px);
@import url('https://fonts.googleapis.com/css?family=Roboto&display=swap');

.order {
width: 100%;
padding: 10px;
}
32 changes: 32 additions & 0 deletions test/runtime/__snapshots__/injectStylesIntoStyleTag.test.js.snap
Expand Up @@ -91,6 +91,38 @@ exports[`addStyle should work with updates #11 1`] = `"<head><title>Title</title
exports[`addStyle should work with updates #11 2`] = `"<head><title>Title</title><style>.foo { color: black }</style><style>.bar { color: white }</style><script src=\\"https://example.com/script.js\\" id=\\"id\\"></script></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #12 1`] = `"<head><title>Title</title><style>.order { color: red }</style><style>.@import url(\\"https://fonts.googleapis.com/css?family=Roboto&display=swap\\");</style><style>.order { color: blue }</style><style>.@import url(\\"https://fonts.googleapis.com/css?family=Roboto&display=swap\\");</style><style>.order { color: red }</style><style>.@import url(\\"https://fonts.googleapis.com/css?family=Roboto&display=swap\\");</style><style media=\\"screen and (min-width: 2000px)\\">.order { color: blue }</style><style>.@import url(\\"https://fonts.googleapis.com/css?family=Roboto&display=swap\\");</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #12 2`] = `"<head><title>Title</title><style>.order { color: orange }</style><style>.@import url(\\"https://fonts.googleapis.com/css?family=Roboto&display=swap\\");</style><style>.order { color: blue }</style><style>.@import url(\\"https://fonts.googleapis.com/css?family=Roboto&display=swap\\");</style><style>.order { color: orange }</style><style>.@import url(\\"https://fonts.googleapis.com/css?family=Roboto&display=swap\\");</style><style media=\\"screen and (min-width: 2000px)\\">.order { color: blue }</style><style>.@import url(\\"https://fonts.googleapis.com/css?family=Roboto&display=swap\\");</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #12 3`] = `"<head><title>Title</title><style>.foo { color: red }</style><style>.bar { color: blue }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #12 4`] = `"<head><title>Title</title></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #13 1`] = `"<head><title>Title</title><style>.red { color: red }</style><style>.green { color: green }</style><style>.blue { color: blue }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #13 2`] = `"<head><title>Title</title><style>.red { color: black }</style><style>.green { color: green }</style><style>.blue { color: blue }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #13 3`] = `"<head><title>Title</title><style>.red { color: black }</style><style>.green { color: black }</style><style>.blue { color: blue }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #13 4`] = `"<head><title>Title</title><style>.red { color: black }</style><style>.green { color: black }</style><style>.blue { color: black }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #13 5`] = `"<head><title>Title</title><style>.green { color: black }</style><style>.blue { color: black }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #13 6`] = `"<head><title>Title</title><style>.blue { color: black }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #13 7`] = `"<head><title>Title</title></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #14 1`] = `"<head><title>Title</title><style>.red { color: red }</style><style>.green { color: green }</style><style>.blue { color: blue }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #14 2`] = `"<head><title>Title</title><style>.red { color: red }</style><style>.green { color: black }</style><style>.blue { color: blue }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #14 3`] = `"<head><title>Title</title><style>.red { color: red }</style><style>.green { color: black }</style><style>.blue { color: blue }</style><style>.white { color: white }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #14 4`] = `"<head><title>Title</title><style>.green { color: black }</style><style>.blue { color: blue }</style><style>.white { color: white }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #14 5`] = `"<head><title>Title</title><style>.green { color: black }</style><style>.white { color: white }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates 1`] = `"<head><title>Title</title><style>.foo { color: red }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates 2`] = `"<head><title>Title</title><style>.foo { color: blue }</style></head><body><h1>Hello world</h1></body>"`;

0 comments on commit c7d6e3a

Please sign in to comment.