juicer 0.2.6 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +28 -0
- data/Rakefile +84 -36
- data/Readme.rdoc +192 -23
- data/VERSION +1 -0
- data/bin/juicer +2 -4
- data/lib/juicer.rb +9 -10
- data/lib/juicer/asset/path.rb +275 -0
- data/lib/juicer/asset/path_resolver.rb +79 -0
- data/lib/juicer/binary.rb +3 -5
- data/lib/juicer/cache_buster.rb +112 -27
- data/lib/juicer/command/install.rb +4 -2
- data/lib/juicer/command/list.rb +16 -9
- data/lib/juicer/command/merge.rb +30 -14
- data/lib/juicer/command/verify.rb +1 -1
- data/lib/juicer/css_cache_buster.rb +31 -47
- data/lib/juicer/datafy/datafy.rb +20 -0
- data/lib/juicer/dependency_resolver/css_dependency_resolver.rb +29 -0
- data/lib/juicer/dependency_resolver/dependency_resolver.rb +101 -0
- data/lib/juicer/dependency_resolver/javascript_dependency_resolver.rb +23 -0
- data/lib/juicer/ext/logger.rb +5 -0
- data/lib/juicer/ext/string.rb +47 -0
- data/lib/juicer/ext/symbol.rb +15 -0
- data/lib/juicer/image_embed.rb +129 -0
- data/lib/juicer/install/base.rb +2 -2
- data/lib/juicer/install/closure_compiler_installer.rb +69 -0
- data/lib/juicer/install/jslint_installer.rb +3 -3
- data/lib/juicer/install/rhino_installer.rb +3 -2
- data/lib/juicer/install/yui_compressor_installer.rb +3 -2
- data/lib/juicer/jslint.rb +1 -1
- data/lib/juicer/merger/base.rb +1 -1
- data/lib/juicer/merger/javascript_merger.rb +3 -4
- data/lib/juicer/merger/stylesheet_merger.rb +13 -15
- data/lib/juicer/minifyer/closure_compiler.rb +90 -0
- data/lib/juicer/minifyer/java_base.rb +77 -0
- data/lib/juicer/minifyer/yui_compressor.rb +15 -48
- data/test/bin/jslint-1.0.js +523 -0
- data/test/bin/jslint.js +523 -0
- data/test/bin/rhino1_7R1.zip +0 -0
- data/test/bin/rhino1_7R2-RC1.jar +0 -0
- data/test/bin/rhino1_7R2-RC1.zip +0 -0
- data/test/bin/yuicompressor +0 -0
- data/test/bin/yuicompressor-2.3.5.zip +0 -0
- data/test/bin/yuicompressor-2.4.2.jar +0 -0
- data/test/bin/yuicompressor-2.4.2.zip +0 -0
- data/test/data/Changelog.txt +10 -0
- data/test/data/a.css +3 -0
- data/test/data/a.js +5 -0
- data/test/data/a1.css +5 -0
- data/test/data/b.css +1 -0
- data/test/data/b.js +5 -0
- data/test/data/b1.css +5 -0
- data/test/data/c1.css +3 -0
- data/test/data/css/2.gif +1 -0
- data/test/data/css/test.css +11 -0
- data/test/data/css/test2.css +1 -0
- data/test/data/d1.css +3 -0
- data/test/data/images/1.png +1 -0
- data/test/data/my_app.js +2 -0
- data/test/data/not-ok.js +2 -0
- data/test/data/ok.js +3 -0
- data/test/data/path_test.css +5 -0
- data/test/data/path_test2.css +14 -0
- data/test/data/pkg/module/moda.js +2 -0
- data/test/data/pkg/module/modb.js +3 -0
- data/test/data/pkg/pkg.js +1 -0
- data/test/fixtures/yui-download.html +425 -0
- data/test/test_helper.rb +36 -7
- data/test/unit/juicer/asset/path_resolver_test.rb +76 -0
- data/test/unit/juicer/asset/path_test.rb +370 -0
- data/test/unit/juicer/cache_buster_test.rb +104 -0
- data/test/{juicer/test_chainable.rb → unit/juicer/chainable_test.rb} +1 -1
- data/test/unit/juicer/command/install_test.rb +58 -0
- data/test/{juicer/command/test_list.rb → unit/juicer/command/list_test.rb} +26 -14
- data/test/unit/juicer/command/merge_test.rb +162 -0
- data/test/{juicer/command/test_util.rb → unit/juicer/command/util_test.rb} +10 -6
- data/test/unit/juicer/command/verify_test.rb +48 -0
- data/test/{juicer/test_css_cache_buster.rb → unit/juicer/css_cache_buster_test.rb} +10 -30
- data/test/unit/juicer/datafy_test.rb +37 -0
- data/test/{juicer/merger/test_css_dependency_resolver.rb → unit/juicer/dependency_resolver/css_dependency_resolver_test.rb} +2 -2
- data/test/{juicer/merger/test_javascript_dependency_resolver.rb → unit/juicer/dependency_resolver/javascript_dependency_resolver_test.rb} +13 -2
- data/test/unit/juicer/ext/{#string_test.rb# → string_test.rb} +0 -7
- data/test/unit/juicer/ext/symbol_test.rb +27 -0
- data/test/unit/juicer/image_embed_test.rb +271 -0
- data/test/unit/juicer/install/installer_base_test.rb +214 -0
- data/test/{juicer/install/test_jslint_installer.rb → unit/juicer/install/jslint_installer_test.rb} +1 -1
- data/test/{juicer/install/test_rhino_installer.rb → unit/juicer/install/rhino_installer_test.rb} +1 -1
- data/test/{juicer/install/test_yui_compressor_installer.rb → unit/juicer/install/yui_compressor_test.rb} +16 -16
- data/test/unit/juicer/jslint_test.rb +60 -0
- data/test/{juicer/merger/test_base.rb → unit/juicer/merger/base_test.rb} +1 -1
- data/test/{juicer/merger/test_javascript_merger.rb → unit/juicer/merger/javascript_merger_test.rb} +2 -2
- data/test/{juicer/merger/test_stylesheet_merger.rb → unit/juicer/merger/stylesheet_merger_test.rb} +15 -13
- data/test/unit/juicer/minifyer/closure_compressor_test.rb +107 -0
- data/test/{integration → unit}/juicer/minifyer/yui_compressor_test.rb +30 -47
- data/test/unit/juicer_test.rb +1 -0
- metadata +207 -113
- data/lib/juicer/core.rb +0 -61
- data/lib/juicer/merger/css_dependency_resolver.rb +0 -25
- data/lib/juicer/merger/dependency_resolver.rb +0 -82
- data/lib/juicer/merger/javascript_dependency_resolver.rb +0 -21
- data/tasks/ann.rake +0 -80
- data/tasks/bones.rake +0 -20
- data/tasks/gem.rake +0 -201
- data/tasks/git.rake +0 -40
- data/tasks/notes.rake +0 -27
- data/tasks/post_load.rake +0 -34
- data/tasks/rdoc.rake +0 -51
- data/tasks/rubyforge.rake +0 -55
- data/tasks/setup.rb +0 -292
- data/tasks/spec.rake +0 -54
- data/tasks/svn.rake +0 -47
- data/tasks/test.rake +0 -40
- data/tasks/test/setup.rake +0 -35
- data/tasks/zentest.rake +0 -36
- data/test/juicer/command/test_install.rb +0 -53
- data/test/juicer/command/test_merge.rb +0 -160
- data/test/juicer/command/test_verify.rb +0 -33
- data/test/juicer/install/test_installer_base.rb +0 -195
- data/test/juicer/minifyer/test_yui_compressor.rb +0 -159
- data/test/juicer/test_cache_buster.rb +0 -58
- data/test/juicer/test_core.rb +0 -47
- data/test/juicer/test_jslint.rb +0 -33
- data/test/test_juicer.rb +0 -4
data/History.txt
CHANGED
@@ -1,3 +1,31 @@
|
|
1
|
+
== 1.0.0 / 2010-02-24
|
2
|
+
* Make sure @import rules with url is removed when files are merged
|
3
|
+
* Dependency resolver supports depending on directories
|
4
|
+
* Constant refefined warnings fixed in installer module (Aaron Suggs)
|
5
|
+
* Ruby 1.9 compatibility
|
6
|
+
* Google Closure Compiler support for `juicer merge` (Pavel Valodzka)
|
7
|
+
* Fix bug in `juicer list` for files with no dependencies (Daniel Stockman)
|
8
|
+
* Image embedder to embed images using data uris (Morgan Roderick)
|
9
|
+
* YUI Compressor --arguments now works (Daniel Stockman)
|
10
|
+
* Download Rhino over HTTP rather than FTP to avoid certain corporate
|
11
|
+
firewall restraints
|
12
|
+
* Development improvements:
|
13
|
+
Use Jeweler to package gem
|
14
|
+
Less obtrusive Ruby core extensions (Pavel Valodzka)
|
15
|
+
Switched from Hpricot to Nokogiri
|
16
|
+
New AssetPath interface for resolving URLs in CSS files
|
17
|
+
Refactor web_root -> document_root
|
18
|
+
Tests are considerably sped up
|
19
|
+
Reorganized tests in unit/ directory
|
20
|
+
Use shoulda for tests
|
21
|
+
Use mocha in tests
|
22
|
+
Use FakeFS for certain file operations in tests
|
23
|
+
Bundling binaries needed to run tests
|
24
|
+
* Refactored/moved dependency resolver classes. They now live in
|
25
|
+
Juicer::CssDependencyResolver and
|
26
|
+
Juicer::JavaScriptDependencyResolver
|
27
|
+
Dependency resolvers include Enumerable
|
28
|
+
|
1
29
|
== 0.2.6 / 2009-07-20
|
2
30
|
* New installation paths for YUI Compressor
|
3
31
|
Patch by http://github.com/craveytrain
|
data/Rakefile
CHANGED
@@ -1,48 +1,96 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
4
5
|
|
5
6
|
begin
|
6
|
-
require '
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
require 'jeweler'
|
8
|
+
Jeweler::Tasks.new do |gem|
|
9
|
+
gem.name = "juicer"
|
10
|
+
gem.summary = "Command line tool for CSS and JavaScript developers"
|
11
|
+
gem.description = "Resolve dependencies, merge and minify CSS and JavaScript files with Juicer - the command line tool for frontend engineers"
|
12
|
+
gem.email = "christian@cjohansen.no"
|
13
|
+
gem.homepage = "http://github.com/cjohansen/juicer"
|
14
|
+
gem.authors = ["Christian Johansen"]
|
15
|
+
gem.rubyforge_project = "juicer"
|
16
|
+
gem.add_development_dependency "shoulda", ">= 2.10.2"
|
17
|
+
gem.add_development_dependency "mocha", ">= 0.9.8"
|
18
|
+
gem.add_development_dependency "fakefs", ">= 0.2.1"
|
19
|
+
gem.add_development_dependency "jeweler", ">= 0.2.1"
|
20
|
+
gem.add_development_dependency "redgreen", ">= 1.2.2" if RUBY_VERSION < "1.9"
|
21
|
+
gem.add_dependency "cmdparse"
|
22
|
+
gem.add_dependency "nokogiri"
|
23
|
+
gem.add_dependency "rubyzip"
|
24
|
+
gem.executables = ["juicer"]
|
25
|
+
gem.post_install_message = <<-MSG
|
26
|
+
Juicer does not ship with third party libraries. You probably want to install
|
27
|
+
Yui Compressor and JsLint now:
|
28
|
+
|
29
|
+
juicer install yui_compressor
|
30
|
+
juicer install jslint
|
31
|
+
|
32
|
+
Happy juicing!
|
33
|
+
MSG
|
34
|
+
gem.files = FileList["[A-Z]*", "{bin,generators,lib,test}/**/*"]
|
13
35
|
end
|
14
|
-
end
|
15
36
|
|
16
|
-
|
17
|
-
|
18
|
-
|
37
|
+
Jeweler::GemcutterTasks.new
|
38
|
+
Jeweler::RubyforgeTasks.new do |rubyforge|
|
39
|
+
rubyforge.doc_task = "rdoc"
|
40
|
+
end
|
41
|
+
rescue LoadError => err
|
42
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
43
|
+
puts err.message
|
44
|
+
end
|
19
45
|
|
20
|
-
|
46
|
+
Rake::TestTask.new("test:units") do |test|
|
47
|
+
test.libs << 'test'
|
48
|
+
test.pattern = 'test/unit/**/*_test.rb'
|
49
|
+
test.verbose = true
|
50
|
+
end
|
21
51
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
PROJ.rubyforge.name = 'juicer'
|
28
|
-
PROJ.readme_file = 'Readme.rdoc'
|
29
|
-
PROJ.exclude = %w(tmp$ bak$ ~$ CVS \.svn ^pkg ^doc \.git ^rcov ^test\/data gemspec ^test\/bin)
|
30
|
-
PROJ.rdoc.remote_dir = 'juicer'
|
52
|
+
Rake::TestTask.new("test:integration") do |test|
|
53
|
+
test.libs << 'test'
|
54
|
+
test.pattern = 'test/integration/**/*_test.rb'
|
55
|
+
test.verbose = true
|
56
|
+
end
|
31
57
|
|
32
|
-
|
58
|
+
task :test => ["check_dependencies:development", "test:units", "test:integration"]
|
33
59
|
|
34
|
-
|
35
|
-
Juicer does not ship with third party libraries. You probably want to install
|
36
|
-
Yui Compressor and JsLint now:
|
60
|
+
task :default => "test:units"
|
37
61
|
|
38
|
-
|
39
|
-
|
62
|
+
# lib/tasks/cruise.rake
|
63
|
+
desc 'Continuous build target'
|
64
|
+
task :cruise do
|
65
|
+
out = ENV['CC_BUILD_ARTIFACTS']
|
66
|
+
mkdir_p out unless File.directory? out if out
|
67
|
+
|
68
|
+
Rake::Task["rcov"].invoke
|
69
|
+
mv 'coverage/', "#{out}/" if out
|
70
|
+
end
|
40
71
|
|
41
|
-
|
42
|
-
|
72
|
+
begin
|
73
|
+
require 'rcov/rcovtask'
|
74
|
+
Rcov::RcovTask.new do |test|
|
75
|
+
test.libs << 'test'
|
76
|
+
test.pattern = 'test/**/*_test.rb'
|
77
|
+
test.verbose = true
|
78
|
+
end
|
79
|
+
rescue LoadError
|
80
|
+
task :rcov do
|
81
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
82
|
+
end
|
83
|
+
end
|
43
84
|
|
44
|
-
|
85
|
+
Rake::RDocTask.new do |rdoc|
|
86
|
+
if File.exist?('VERSION')
|
87
|
+
version = File.read('VERSION')
|
88
|
+
else
|
89
|
+
version = ""
|
90
|
+
end
|
45
91
|
|
46
|
-
|
47
|
-
|
48
|
-
|
92
|
+
rdoc.rdoc_dir = 'rdoc'
|
93
|
+
rdoc.title = "jstdutil #{version}"
|
94
|
+
rdoc.rdoc_files.include('README*')
|
95
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
96
|
+
end
|
data/Readme.rdoc
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
= Juicer
|
2
2
|
Official URL: http://github.com/cjohansen/juicer/tree/master
|
3
|
-
|
3
|
+
|
4
|
+
Christian Johansen (http://www.cjohansen.no) and contributors:
|
5
|
+
|
6
|
+
* Morgan Roderick (http://roderick.dk)
|
7
|
+
* Pavel Valodzka (http://github.com/valodzka)
|
8
|
+
* Daniel Stockman (http://evocateur.org/)
|
9
|
+
* Aaron Suggs (http://ktheory.com)
|
4
10
|
|
5
11
|
== DESCRIPTION:
|
6
12
|
|
@@ -10,12 +16,13 @@ High level overview; Juicer can
|
|
10
16
|
|
11
17
|
* figure out which files depend on each other and merge them together, reducing
|
12
18
|
the number of http requests per page view, thus improving performance
|
13
|
-
* use YUI Compressor to compress code, thus improving performance
|
19
|
+
* use YUI Compressor or Google Closure Compiler to compress code, thus improving performance
|
14
20
|
* verify that your JavaScript is safe to minify/compress by running JsLint on it
|
15
21
|
* cycle asset hosts in CSS files
|
16
22
|
* add "cache busters" to URLs in CSS files
|
17
23
|
* recalculate relative URLs in CSS files, as well as convert them to absolute
|
18
24
|
(or convert absolute URLs to relative URLs)
|
25
|
+
* embed images into stylesheets using data-uris
|
19
26
|
|
20
27
|
== FEATURES:
|
21
28
|
|
@@ -23,7 +30,7 @@ High level overview; Juicer can
|
|
23
30
|
|
24
31
|
Juicer can read @import statements in CSS files and use them to combine all your
|
25
32
|
stylesheets into a single file. This file may be minified using the YUI
|
26
|
-
Compressor. Eventually it will support other minifying tools too.
|
33
|
+
Compressor or Google Closure Compiler. Eventually it will support other minifying tools too.
|
27
34
|
|
28
35
|
Juicer can treat your JavaScript files much the same way too, parsing a comment
|
29
36
|
switch @depend, as this example shows:
|
@@ -31,14 +38,14 @@ switch @depend, as this example shows:
|
|
31
38
|
/**
|
32
39
|
* My script file
|
33
40
|
*
|
34
|
-
* @depend jquery-1.
|
41
|
+
* @depend jquery-1.4.1.js
|
35
42
|
*/
|
36
43
|
var myNS = {
|
37
44
|
myObject = {}
|
38
45
|
};
|
39
46
|
|
40
47
|
Running <tt>juicer merge</tt> on this file will result in a minified file
|
41
|
-
<tt>filename.min.js</tt> containing the file jquery-1.
|
48
|
+
<tt>filename.min.js</tt> containing the file jquery-1.4.1.js (located in the
|
42
49
|
same directory) and the code above.
|
43
50
|
|
44
51
|
You can use @import (CSS files) and @depend (JavaScript) recursively, effectively
|
@@ -50,10 +57,10 @@ When merging CSS files, you may want to merge CSS files in different directories
|
|
50
57
|
You may also want the resulting CSS file to end up in another directory as well.
|
51
58
|
Juicer automatically recalculates referenced URLs to reflect this change.
|
52
59
|
|
53
|
-
Absolute URLs are not changed by default, but if you provide juicer merge
|
54
|
-
|
55
|
-
URLs relative to output directory. You can also
|
56
|
-
all URLs to absolute ones.
|
60
|
+
Absolute URLs are not changed by default, but if you provide juicer merge
|
61
|
+
with <code>--document-root [DIR]</code> and <code>--relative-urls</code> then
|
62
|
+
absolute URLs are converted to URLs relative to output directory. You can also
|
63
|
+
use <code>--absolute-urls</code> to convert all URLs to absolute ones.
|
57
64
|
|
58
65
|
=== Cache busters
|
59
66
|
|
@@ -69,20 +76,170 @@ Unfortunately, the popular web proxy Squid shipped for some time with a default
|
|
69
76
|
configuration which would not treat a URL as a "new" URL if the only thing changed
|
70
77
|
was the GET parameters. For this reason Juicer provides hard cache busters.
|
71
78
|
|
72
|
-
Hard cache busters result in URLs such as http://assets/images/1-cb1234567890.png,
|
79
|
+
Hard cache busters result in URLs such as: http://assets/images/1-cb1234567890.png,
|
73
80
|
ie URLs that require either renaming of files, or (more conveniently) a web
|
74
81
|
server configuration that will forward URLs to the right files anyway.
|
75
82
|
|
76
|
-
|
83
|
+
=== Embed images in stylesheets
|
84
|
+
|
85
|
+
Juicer supports embedding images into stylesheets using data uri's.
|
86
|
+
|
87
|
+
In order to be as unobtrusive as possible, you must indicate for each image that it
|
88
|
+
can be embedded in the stylesheet by using the embed url suffix.
|
89
|
+
|
90
|
+
Example:
|
91
|
+
|
92
|
+
h1 { background: url(/somepath/someimage.png?embed=true); }
|
93
|
+
|
94
|
+
When merging the stylesheets, you must specify which type of embedding you want,
|
95
|
+
currently only 'none' and 'data_uri' are supported.
|
96
|
+
|
97
|
+
$ juicer merge my-stylesheet.css -o my-stylesheet.merged.css --embed-images data_uri
|
98
|
+
|
99
|
+
The result will look similar to this:
|
100
|
+
|
101
|
+
h1 { background: url(data:image/png;base64,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); }
|
102
|
+
|
103
|
+
Embedding images in stylesheets should be used very carefully, as they will bloat
|
104
|
+
your css files considerably, and you will loose some of the fine grained control
|
105
|
+
over caching of images.
|
106
|
+
|
107
|
+
Before using Juicer to embed images into your stylesheets, you should have control
|
108
|
+
over cache expiration of stylesheets.
|
109
|
+
|
110
|
+
You should also have gzip enabled, as base64 encoded images take up about 30% more
|
111
|
+
space than serving them normally. With gzip enabled this is reduced to about 5-10% bloat.
|
112
|
+
|
113
|
+
==== Usage scenario: Modern browsers and IE7, IE6 support
|
114
|
+
|
115
|
+
As all of the major browsers in their later incarnations support the data uri scheme,
|
116
|
+
it is possible to just create two merged stylesheets, although you can create as many
|
117
|
+
as you want really.
|
118
|
+
|
119
|
+
Let's assume you have the following files:
|
120
|
+
|
121
|
+
* reset.css
|
122
|
+
* layout.css
|
123
|
+
* typography.css
|
124
|
+
|
125
|
+
/* layout.css */
|
126
|
+
body { background: url( /images/my-body-background.png?embed=true); }
|
127
|
+
|
128
|
+
And let's assume that you want to merge these, and embed the flagged images in
|
129
|
+
layout.css into the stylesheet.
|
130
|
+
|
131
|
+
To do this, you would have a master stylesheet that imports the other stylesheets using
|
132
|
+
the @import statemet. It could look like this:
|
133
|
+
|
134
|
+
/* master.css */
|
135
|
+
@import url(reset.css)
|
136
|
+
@import url(layout.css)
|
137
|
+
@import url(typography.css)
|
138
|
+
|
139
|
+
Now, in order to create the two versions of the stylesheet, you would simply run
|
140
|
+
Juicer with and without the option to embed images
|
141
|
+
|
142
|
+
$ juicer merge master.css -o master.embedded.css --embed-images data_uri
|
143
|
+
$ juicer merge master.css -o master.normal.css
|
144
|
+
|
145
|
+
In order to only load the relevant stylesheet to supporting browsers, and preventing
|
146
|
+
doubling the effective payload of the background images, you would reference the
|
147
|
+
stylesheets like this:
|
148
|
+
|
149
|
+
<head>
|
150
|
+
...
|
151
|
+
<!--[if !IE]>-->
|
152
|
+
<link rel="stylesheet" type="text/css" href="master.embedded.css" />
|
153
|
+
<!--<![endif]-->
|
154
|
+
<!--[if gte IE 8]>
|
155
|
+
<link rel="stylesheet" type="text/css" href="master.embedded.css" />
|
156
|
+
<![endif]-->
|
157
|
+
<!--[if lte IE 7]>
|
158
|
+
<link rel="stylesheet" type="text/css" href="master.normal.css" />
|
159
|
+
<![endif]-->
|
160
|
+
...
|
161
|
+
</head>
|
162
|
+
|
163
|
+
The first conditional comemnt allows only non-IE browsers to fetch the
|
164
|
+
<code>master.embedded.css</code> stylesheet.
|
165
|
+
|
166
|
+
The second conditional comment allows only IE8+ browsers to fetch the
|
167
|
+
<code>master.embedded.css</code> stylesheet.
|
77
168
|
|
78
|
-
|
79
|
-
|
169
|
+
The last conditional comment allows only IE7 and lower to fetch the
|
170
|
+
<code>master.normal.css</code> stylesheet.
|
171
|
+
|
172
|
+
Unfortunately, you will need to use three conditional comments, or you will end
|
173
|
+
up with an unsightly "-->" displayed at the top of your pages in IE.
|
174
|
+
|
175
|
+
==== Browser support
|
176
|
+
Windows Vista, Windows 2003, Windows 7
|
177
|
+
Tests needed
|
178
|
+
|
179
|
+
Windows XP
|
180
|
+
* IE8 - up to 32kb IS supported
|
181
|
+
* Firefox 3.5.2 - OK
|
182
|
+
* Opera 9.64 - OK
|
183
|
+
* Chrome 3 - OK
|
184
|
+
* Safari 4 - OK
|
185
|
+
|
186
|
+
OS X 10.6.1
|
187
|
+
* Firefox 3.5 - OK
|
188
|
+
* Firefox 2.0.20 - OK
|
189
|
+
* Safari 4 - OK
|
190
|
+
* Opera 10 - OK
|
191
|
+
* Opera 9.27 - OK
|
192
|
+
* Opera 8.0 - OK
|
193
|
+
* Camino 1.6.10 - OK
|
194
|
+
|
195
|
+
Debian
|
196
|
+
* Opera 10 - OK
|
197
|
+
|
198
|
+
Android
|
199
|
+
* WebKit - OK
|
200
|
+
|
201
|
+
iPhone
|
202
|
+
* Safari - OK
|
203
|
+
|
204
|
+
The test used is located at http://roderick.dk/experiments/data-uri-limits/
|
205
|
+
|
206
|
+
The test used tests loading of styles using the href attribute, it is ASSUMED
|
207
|
+
that loading images from data-uri in css has similar support.
|
208
|
+
Soon[tm] there will be a testpage with images as well.
|
209
|
+
|
210
|
+
If you have funky browser / OS combinations not listed above, please visit the
|
211
|
+
test and send a screenshot and details about browser and OS to morgan@roderick.dk
|
212
|
+
|
213
|
+
|
214
|
+
==== Support for really old user-agents
|
215
|
+
If you plan to support user-agents that do understand conditional comments and
|
216
|
+
does not support the data uri scheme, you will have to do some kind of detection
|
217
|
+
of support. These user-agents would be very rare, as our browser testing shows,
|
218
|
+
most modern user agents support data-uris.
|
219
|
+
|
220
|
+
* http://weston.ruter.net/2009/05/07/detecting-support-for-data-uris/
|
221
|
+
|
222
|
+
Please note that image embedding is NOT a silver bullet, but can help reduce
|
223
|
+
the amount of HTTP connections needed for a page.
|
224
|
+
|
225
|
+
|
226
|
+
==== MHTML Support
|
227
|
+
|
228
|
+
Due to MHTML being very awkward in it's implementation (having the absolute url
|
229
|
+
including protocol inside the stylesheet itself), it was decided to be of very
|
230
|
+
little real value and attempts at supporting it has been dropped.
|
231
|
+
|
232
|
+
|
233
|
+
==== Further reading
|
234
|
+
|
235
|
+
* http://www.websiteoptimization.com/speed/tweak/inline-images/
|
236
|
+
* http://en.wikipedia.org/wiki/Data_URI_scheme
|
237
|
+
|
238
|
+
|
239
|
+
== PLANNED FEATURES:
|
80
240
|
|
81
241
|
* Support more minifiers, JsMin (Ruby port), Packer and possibly others
|
82
242
|
* Add support for CssTidy to compress CSS files
|
83
|
-
* juicer build, a command that can build several files in one swoop using a
|
84
|
-
configuration file
|
85
|
-
* juicer doc, a command that produces documentation using YUI Doc or JsDoc
|
86
243
|
|
87
244
|
If you have any ideas, feature requests, want to contribute or whatever, fork
|
88
245
|
the project on github, or get in touch through christian (at) cjohansen.no.
|
@@ -99,30 +256,42 @@ the project on github, or get in touch through christian (at) cjohansen.no.
|
|
99
256
|
|
100
257
|
== REQUIREMENTS:
|
101
258
|
|
102
|
-
In order to use YUI Compressor
|
259
|
+
In order to use YUI Compressor, Closure Compiler or JsMin (requires Rhino) you need Java
|
103
260
|
installed and the java executable available on your path.
|
104
261
|
|
105
262
|
== INSTALL:
|
106
263
|
|
107
264
|
$ gem install juicer
|
108
265
|
$ juicer install yui_compressor
|
266
|
+
$ juicer install closure_compiler
|
109
267
|
$ juicer install jslint
|
110
268
|
|
111
269
|
You need Java installed and available on your PATH. During gem installation,
|
112
|
-
Juicer will download and install YUI Compressor, JsLint and Rhino for you.
|
270
|
+
Juicer will download and install YUI Compressor, Closure Compiler, JsLint and Rhino for you.
|
271
|
+
|
272
|
+
rake check_dependencies:development
|
273
|
+
|
274
|
+
Will tell you about other dependencies that might be missing on your system.
|
113
275
|
|
114
|
-
== For developers
|
115
276
|
|
116
|
-
|
117
|
-
rake test:setup
|
277
|
+
== Contributors
|
118
278
|
|
119
|
-
|
279
|
+
* Morgan Roderick (http://roderick.dk)
|
280
|
+
Added support for embedding graphics using data-uri
|
281
|
+
Several small fixes and optimizations
|
282
|
+
* Pavel Valodzka (http://github.com/valodzka)
|
283
|
+
Added Google Closure Compiler support
|
284
|
+
* Daniel Stockman (http://evocateur.org/)
|
285
|
+
Fixed `juicer list` when running it against files with no dependencies
|
286
|
+
* Aaron Suggs (http://ktheory.com)
|
287
|
+
Added support for depending on directories
|
288
|
+
Fixed installers on 1.0 branch
|
120
289
|
|
121
290
|
== LICENSE:
|
122
291
|
|
123
292
|
(The MIT License)
|
124
293
|
|
125
|
-
Copyright (c) 2008-
|
294
|
+
Copyright (c) 2008-2010 Christian Johansen
|
126
295
|
|
127
296
|
Permission is hereby granted, free of charge, to any person obtaining
|
128
297
|
a copy of this software and associated documentation files (the
|