Permalink
Browse files

version 0.2: support url(...) require with loader

  • Loading branch information...
1 parent b7785fb commit 63fcd33e2ae1a0e606b7792fdfb644fac1c1d3e3 @sokra sokra committed May 13, 2012
Showing with 116 additions and 10 deletions.
  1. +2 −0 .npmignore
  2. +12 −1 README.md
  3. +51 −8 index.js
  4. +7 −1 package.json
  5. +44 −0 test/url_test.js
View
@@ -0,0 +1,2 @@
+node_modules
+test
View
@@ -4,9 +4,20 @@
``` javascript
var css = require("css!./file.css");
-// => returns css code from file.css, resolves imports
+// => returns css code from file.css, resolves imports and url(...)
```
+`@import` will be required with this css loader.
+
+`url(...)` will be required with the loader specified in the options.
+If `options.css.requireUrl` is a string it will be prefixed to the required url.
+If it isn't a string `url(...)` will not be replaced.
+`options.css.requireUrl` defaults to `"file/auto!"`.
+
+A alternative to the file-loader is the
+[url-loader](https://github.com/sokra/webpack-url-loader) which can use Data Urls.
+The use it specify `"url/auto!"`.
+
Don't forget to polyfill `require` if you want to use it in node.
See `webpack` documentation.
View
@@ -3,27 +3,43 @@
Author Tobias Koppers @sokra
*/
var csso = require("csso");
+var uriRegExp = /%CSSURL\[%(.*)%\]CSSURL%/g;
module.exports = function(content) {
- var options = this;
+ var isRequireUrl = !this || !this.options || !this.options.css ||
+ typeof this.options.css.requireUrl === "string";
+ var requireUrl = this && this.options && this.options.css &&
+ this.options.css.requireUrl ||
+ "file/auto!";
var result = [];
var tree = csso.parse(content, "stylesheet");
- if(options.minimize)
+ if(this && this.minimize)
tree = csso.compress(tree);
tree = csso.cleanInfo(tree);
-
+
var imports = extractImports(tree);
-
+ if(isRequireUrl)
+ annotateUrls(tree);
+
imports.forEach(function(imp) {
if(imp.media.length > 0) {
- result.push(JSON.stringify("@media " + imp.media.join("") + "{"));
+ result.push(JSON.stringify("@media(" + imp.media.join("") + "){"));
}
- result.push("require(" + JSON.stringify(__filename) + " + \"!\" + " + JSON.stringify(urlToRequire(imp.url)) + ")");
+ result.push("require(" + JSON.stringify(__filename + "!" + urlToRequire(imp.url)) + ")");
if(imp.media.length > 0) {
result.push(JSON.stringify("}"));
}
});
-
- result.push(JSON.stringify(csso.translate(tree)));
+
+ var css = JSON.stringify(csso.translate(tree));
+ if(isRequireUrl) {
+ css = css.replace(uriRegExp, function(match) {
+ match = uriRegExp.exec(match);
+ var url = JSON.parse("\"" + match[1] + "\"");
+ return "\"+require(" + JSON.stringify(requireUrl + urlToRequire(url)) + ")+\"";
+ });
+
+ }
+ result.push(css);
return "module.exports =\n\t" + result.join(" +\n\t") + ";";
}
@@ -71,4 +87,31 @@ function extractImports(tree) {
tree.splice(i, 1);
});
return results;
+}
+function annotateUrls(tree) {
+ function iterateChildren() {
+ for(var i = 1; i < tree.length; i++) {
+ annotateUrls(tree[i]);
+ }
+ }
+ switch(tree[0]) {
+ case "stylesheet": return iterateChildren();
+ case "ruleset": return iterateChildren();
+ case "block": return iterateChildren();
+ case "declaration": return iterateChildren();
+ case "value": return iterateChildren();
+ case "uri":
+ for(var i = 1; i < tree.length; i++) {
+ var item = tree[i];
+ switch(item[0]) {
+ case "ident":
+ case "raw":
+ item[1] = "%CSSURL[%" + item[1] + "%]CSSURL%";
+ return;
+ case "string":
+ item[1] = "%CSSURL[%" + item[1].substring(1, item[1].length-1) + "%]CSSURL%";
+ return;
+ }
+ }
+ }
}
View
@@ -1,11 +1,17 @@
{
"name": "css-loader",
- "version": "0.1.2",
+ "version": "0.2.0",
"author": "Tobias Koppers @sokra",
"description": "css loader module for webpack",
"dependencies": {
"csso": "1.2.x"
},
+ "devDependencies": {
+ "vows": "0.6.2"
+ },
+ "scripts": {
+ "test": "node node_modules/vows/bin/vows"
+ },
"licenses": [
{
"type": "MIT",
View
@@ -0,0 +1,44 @@
+var vows = require("vows");
+var assert = require("assert");
+var path = require("path");
+var cssLoader = require("../index.js");
+
+function test(input, result) {
+ return {
+ topic: function() {
+ var context = {
+ options: {
+ }
+ }
+ return cssLoader.call(context, input);
+ },
+
+ isCorrect: function(output) {
+ if(output instanceof Error)
+ throw output;
+ assert.equal(output, "module.exports =\n\t" + result.join(" +\n\t") + ";");
+ }
+ }
+}
+
+vows.describe("url").addBatch({
+ "simple": test(".class { a: b c d; }",
+ ["\".class { a: b c d; }\""]),
+ "simple2": test(".class { a: b c d; }\n.two {}",
+ ["\".class { a: b c d; }\\n.two {}\""]),
+ "import": test("@import url(test.css);\n.class { a: b c d; }",
+ ["require("+JSON.stringify(path.join(__dirname, "..", "index.js")+"!./test.css")+")",
+ "\"\\n.class { a: b c d; }\""]),
+ "import with media":
+ test("@import url(~test/css) screen and print;\n.class { a: b c d; }",
+ ["\"@media(screen and print){\"",
+ "require("+JSON.stringify(path.join(__dirname, "..", "index.js")+"!test/css")+")",
+ "\"}\"",
+ "\"\\n.class { a: b c d; }\""]),
+ "background img":
+ test(".class { background: green url( \"img.png\" ) xyz }",
+ ["\".class { background: green url( \"+require(\"file/auto!./img.png\")+\" ) xyz }\""]),
+ "background img 2":
+ test(".class { background: green url(~img/png ) xyz }",
+ ["\".class { background: green url(\"+require(\"file/auto!img/png\")+\" ) xyz }\""])
+}).export(module);

0 comments on commit 63fcd33

Please sign in to comment.