Skip to content

Commit 289e62f

Browse files
committed
support an array of items with id
This ensures that items with the same id are only added once. i. e. multiple css file and `@import` the same base css file and it's only added once to the DOM. webpack-contrib/css-loader#17
1 parent fd51db8 commit 289e62f

11 files changed

+157
-46
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/node_modules

addStyle.js

-38
This file was deleted.

addStyles.js

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
MIT License http://www.opensource.org/licenses/mit-license.php
3+
Author Tobias Koppers @sokra
4+
*/
5+
var stylesInDom = {};
6+
7+
module.exports = function(list) {
8+
if(typeof DEBUG !== "undefined" && DEBUG) {
9+
if(typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment");
10+
}
11+
var styles = listToStyles(list);
12+
addStylesToDom(styles);
13+
return function update(newList) {
14+
var mayRemove = [];
15+
for(var i = 0; i < styles.length; i++) {
16+
var item = styles[i];
17+
var domStyle = stylesInDom[item.id];
18+
domStyle.refs--;
19+
mayRemove.push(domStyle);
20+
}
21+
if(newList) {
22+
var newStyles = listToStyles(newList);
23+
addStylesToDom(newStyles);
24+
}
25+
for(var i = 0; i < mayRemove.length; i++) {
26+
var domStyle = mayRemove[i];
27+
if(domStyle.refs === 0) {
28+
for(var j = 0; j < domStyle.parts.length; j++)
29+
domStyle.parts[j]();
30+
delete stylesInDom[domStyle.id];
31+
}
32+
}
33+
};
34+
}
35+
36+
function addStylesToDom(styles) {
37+
for(var i = 0; i < styles.length; i++) {
38+
var item = styles[i];
39+
var domStyle = stylesInDom[item.id];
40+
if(domStyle) {
41+
domStyle.refs++;
42+
for(var j = 0; j < domStyle.parts.length; j++) {
43+
domStyle.parts[j](item.parts[j]);
44+
}
45+
for(; j < item.parts.length; j++) {
46+
domStyle.parts.push(addStyle(item.parts[j]));
47+
}
48+
} else {
49+
var parts = [];
50+
for(var j = 0; j < item.parts.length; j++) {
51+
parts.push(addStyle(item.parts[j]));
52+
}
53+
stylesInDom[item.id] = {id: item.id, refs: 1, parts: parts};
54+
}
55+
}
56+
}
57+
58+
function listToStyles(list) {
59+
var styles = [];
60+
var newStyles = {};
61+
for(var i = 0; i < list.length; i++) {
62+
var item = list[i];
63+
var id = item[0];
64+
var css = item[1];
65+
var media = item[2];
66+
// var sourceMap = item[3];
67+
var part = {css: css, media: media/*, sourceMap: sourceMap*/};
68+
if(!newStyles[id])
69+
styles.push(newStyles[id] = {id: id, parts: [part]});
70+
else
71+
newStyles[id].parts.push(part);
72+
}
73+
return styles;
74+
}
75+
76+
function addStyle(obj) {
77+
var styleElement = document.createElement("style");
78+
var head = document.head || document.getElementsByTagName("head")[0];
79+
styleElement.type = "text/css";
80+
head.appendChild(styleElement);
81+
applyToTag(styleElement, obj);
82+
return function(newObj) {
83+
if(newObj) {
84+
if(newObj.css === obj.css && newObj.media === obj.media /*&& newObj.sourceMap === obj.sourceMap*/)
85+
return;
86+
applyToTag(styleElement, obj = newObj);
87+
} else {
88+
head.removeChild(styleElement);
89+
}
90+
};
91+
};
92+
93+
function applyToTag(styleElement, obj) {
94+
var css = obj.css;
95+
var media = obj.media;
96+
// var sourceMap = obj.sourceMap;
97+
98+
// No browser support
99+
// if(sourceMap && typeof btoa === "function") {
100+
// try {
101+
// css += "\n/*# sourceMappingURL=data:application/json;base64," + btoa(JSON.stringify(sourceMap)) + " */";
102+
// } catch(e) {}
103+
// }
104+
if(media) {
105+
styleElement.setAttribute("media", media)
106+
}
107+
if (styleElement.styleSheet) {
108+
styleElement.styleSheet.cssText = css;
109+
} else {
110+
while(styleElement.firstChild) {
111+
styleElement.removeChild(styleElement.firstChild);
112+
}
113+
styleElement.appendChild(document.createTextNode(css));
114+
}
115+
116+
}

fixtures/a.css

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@import "base.css";
2+
body {
3+
border: 1px solid black;
4+
}

fixtures/b.css

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@import "base.css";
2+
.a {
3+
background: blue;
4+
}

fixtures/base.css

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
body {
2+
background: green;
3+
}

fixtures/entry.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
require("./b.css");
2+
require("./a.css");

fixtures/webpack.config.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module.exports = {
2+
module: {
3+
loaders: [
4+
{ test: /\.css$/, loader: "style!css?sourceMap" }
5+
]
6+
}
7+
}

index.js

+14-7
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,22 @@ module.exports.pitch = function(remainingRequest) {
88
this.cacheable && this.cacheable();
99
return [
1010
"// style-loader: Adds some css to the DOM by adding a <style> tag",
11-
"var update = require(" + JSON.stringify("!" + path.join(__dirname, "addStyle.js")) + ")(",
12-
"\trequire(" + JSON.stringify("!!" + remainingRequest) + ")",
13-
");",
11+
"",
12+
"// load the styles",
13+
"var content = require(" + JSON.stringify("!!" + remainingRequest) + ");",
14+
"if(typeof content === 'string') content = [module.id, content, ''];",
15+
"// add the styles to the DOM",
16+
"var update = require(" + JSON.stringify("!" + path.join(__dirname, "addStyles.js")) + ")(content);",
1417
"// Hot Module Replacement",
1518
"if(module.hot) {",
16-
"\tmodule.hot.accept(" + JSON.stringify("!!" + remainingRequest) + ", function() {",
17-
"\t\tupdate(require(" + JSON.stringify("!!" + remainingRequest) + "));",
18-
"\t});",
19-
"\tmodule.hot.dispose(function() { update(); });",
19+
" // When the styles change, update the <style> tags",
20+
" module.hot.accept(" + JSON.stringify("!!" + remainingRequest) + ", function() {",
21+
" var newContent = require(" + JSON.stringify("!!" + remainingRequest) + ");",
22+
" if(typeof newContent === 'string') newContent = [module.id, newContent, ''];",
23+
" update(newContent);",
24+
" });",
25+
" // When the module is disposed, remove the <style> tags",
26+
" module.hot.dispose(function() { update(); });",
2027
"}"
2128
].join("\n");
2229
};

package.json

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
"version": "0.7.1",
44
"author": "Tobias Koppers @sokra",
55
"description": "style loader module for webpack",
6+
"devDependencies": {
7+
"css-loader": "~0.8.0"
8+
},
69
"repository": {
710
"type": "git",
811
"url": "[email protected]:webpack/style-loader.git"

useable.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ module.exports.pitch = function(remainingRequest) {
1111
"var dispose;",
1212
"exports.use = exports.ref = function() {",
1313
" if(!(refs++)) {",
14-
" dispose = require(" + JSON.stringify("!" + path.join(__dirname, "addStyle.js")) + ")(require(" + JSON.stringify("!!" + remainingRequest) + "));",
14+
" var content = require(" + JSON.stringify("!!" + remainingRequest) + ")",
15+
" if(typeof content === 'string') content = [module.id, content, ''];",
16+
" dispose = require(" + JSON.stringify("!" + path.join(__dirname, "addStyles.js")) + ")(content);",
1517
" }",
1618
" return exports",
1719
"};",

0 commit comments

Comments
 (0)