Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Add a data-uri function. #1086

Closed
wants to merge 3 commits into from

4 participants

@jneen

Useful for adding in data uris from files.

Usage:

data-uri(@mimetype, @filepath)

will render

uri(data:some/mimetype,filecontents)

If the mimetype has the ;base64 addition, the file will be base64 encoded.

Enjoy!

@jneen jneen add a data-uri function
as described in a comment on #775
75fb7bc
@jneen

Hm. Is this possibly problematic because it requires node's fs module? I see that less is supposed to be supported browser-side too. One solution would be to require('fs') inside the implementation...? But this function really doesn't make any sense in the browser, does it? In the browser, maybe a reasonable thing to do would be to simply return url(@filepath) and hope that the path checks out?

@lukeapage
Owner

it doesn't make much sense browser-side to me, so returning uel(@filepath) sounds like a good idea.

@jneen

Cool, I'll try that. Do you have some kind of isBrowser() function, or should this function test for it itself? The other option is just to straight-up throw a parse error if require('fs') fails.

@lukeapage
Owner

either that or typeof window are the way it is done at the moment.

@lukeapage
Owner

Possible enhancement... Could it default to trying to work out the mime type? If you only get one argument...

@jneen

Hm, what's the best way to work out the mimetype? File extension, maybe? That could be some pretty complicated logic...

@lukeapage
Owner
jneen added some commits
@jneen jneen throw an error if data-uri is used in the browser
and move require('fs') into the function, so other things
still work in the browser.
d812e24
@jneen jneen guess the mimetype, and properly encode non-base64 uris f7fd632
@jneen

I ended up adding the dependency for mime. The previous PR used image/#{ext}, but this is a bit more general than just images - I have a use case for inlining a font, for example.

@lukeapage
Owner

pulled into 1.4.0

Also fixed the browser to return url and moved tests to url.less - that way it isn't executed in the browser tests.

@lukeapage lukeapage closed this
@jneen

Neat, thanks!

@SomMeri SomMeri referenced this pull request in SomMeri/less4j
Closed

Images embedding #81

@matthew-dean

There were some things missed in this pull request and problems introduced with this code which need to be addressed.

a) Less.js already has properties set up which return whether or not the parser is set to a browser, Node, or Rhino environment. However, this code ignores all of this and attempts to again detect browser support, even though browser support has already been detected in a way that can be overridden. So, this code breaks configurability.

b) Up until this pull request, file operations were restricted to @import statements. The importer in Less.js is designed so that a JavaScript author can adapt the plugin to their environment by overriding the less.Parser.importer function in order to handle file operations. This code breaks that modularity as well by assuming and only supporting Node-based operations, which means that file operations are no longer supported consistently and universally. A JavaScript author can override and support the importer for file operations in unique environments, but not data-uri. (See Issue #1392)

Neither of these things are well-documented, so it's understandable that they were missed, but they should be addressed moving forward (preferably in a bug-fix release).

We're exploring making a more graceful environment plugin model that is more environment-agnostic, with a more clearly-defined API, so that we can write features like this without having to make explicit code paths for Node, Rhino and/or the browser. But for now, data-uri should be adjusted to match the current model for importers.

@matthew-dean

Note, to check browser support, use the less.mode property.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 23, 2012
  1. @jneen

    add a data-uri function

    jneen authored
    as described in a comment on #775
Commits on Dec 28, 2012
  1. @jneen

    throw an error if data-uri is used in the browser

    jneen authored
    and move require('fs') into the function, so other things
    still work in the browser.
  2. @jneen
This page is out of date. Refresh to see the latest.
View
34 lib/less/functions.js
@@ -337,6 +337,40 @@ tree.functions = {
},
shade: function(color, amount) {
return this.mix(this.rgb(0, 0, 0), color, amount);
+ },
+ "data-uri": function(mimetype, path) {
+ if (typeof window !== 'undefined') {
+ throw new Error('data-uri() is not supported in the browser.');
+ }
+
+ mimetype = mimetype.value;
+ path = (path && path.value);
+
+ var fs = require('fs');
+ var useBase64 = false;
+
+ // detect the mimetype if not given
+ if (arguments.length < 2) {
+ var mime = require('mime');
+ path = mimetype;
+ mimetype = mime.lookup(path);
+
+ // use base 64 unless it's an ASCII or UTF-8 format
+ var charset = mime.charsets.lookup(mimetype);
+ useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0;
+ if (useBase64) mimetype += ';base64';
+ }
+ else {
+ useBase64 = /;base64$/.test(mimetype)
+ }
+
+ var buf = fs.readFileSync(path);
+
+ buf = useBase64 ? buf.toString('base64')
+ : encodeURIComponent(buf);
+
+ var uri = "'data:"+mimetype+','+buf+"'";
+ return new(tree.URL)(new(tree.Anonymous)(uri));
}
};
View
2  package.json
@@ -10,7 +10,7 @@
"main" : "./lib/less/index",
"directories" : { "test": "./test" },
"engines" : { "node": ">=0.4.2" },
- "optionalDependencies" : { "ycssmin": ">=1.0.1" },
+ "optionalDependencies" : { "ycssmin": ">=1.0.1", "mime": "1.2.x" },
"devDependencies" : { "diff": "~1.0" },
"scripts": {
"test": "make test"
View
10 test/css/functions.css
@@ -97,3 +97,13 @@
average: #7b007b;
negation: #d73131;
}
+#data-uri {
+ uri: url('data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg==');
+}
+#data-uri-guess {
+ uri: url('data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg==');
+}
+#data-uri-ascii {
+ uri-1: url('data:text/html,%3Ch1%3EThis%20page%20is%20100%25%20Awesome.%3C%2Fh1%3E%0A');
+ uri-2: url('data:text/html,%3Ch1%3EThis%20page%20is%20100%25%20Awesome.%3C%2Fh1%3E%0A');
+}
View
1  test/data/image.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
1  test/data/page.html
@@ -0,0 +1 @@
+<h1>This page is 100% Awesome.</h1>
View
13 test/less/functions.less
@@ -108,3 +108,16 @@
average: average(#f60000, #0000f6);
negation: negation(#f60000, #313131);
}
+
+#data-uri {
+ uri: data-uri('image/jpeg;base64', 'test/data/image.jpg');
+}
+
+#data-uri-guess {
+ uri: data-uri('test/data/image.jpg');
+}
+
+#data-uri-ascii {
+ uri-1: data-uri('text/html', 'test/data/page.html');
+ uri-2: data-uri('test/data/page.html');
+}
Something went wrong with that request. Please try again.