jekyll-minibundle 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.md +4 -0
- data/Rakefile +45 -0
- data/Readme.md +138 -0
- data/lib/jekyll/minibundle.rb +3 -0
- data/lib/jekyll/minibundle/asset_bundle.rb +48 -0
- data/lib/jekyll/minibundle/asset_file_support.rb +16 -0
- data/lib/jekyll/minibundle/asset_stamp.rb +9 -0
- data/lib/jekyll/minibundle/bundle_file.rb +76 -0
- data/lib/jekyll/minibundle/bundle_markup.rb +18 -0
- data/lib/jekyll/minibundle/mini_bundle_block.rb +33 -0
- data/lib/jekyll/minibundle/mini_stamp_tag.rb +19 -0
- data/lib/jekyll/minibundle/stamp_file.rb +69 -0
- data/lib/jekyll/minibundle/version.rb +5 -0
- data/test/fixture/site/_assets/scripts/app.js +5 -0
- data/test/fixture/site/_assets/scripts/dependency.js +4 -0
- data/test/fixture/site/_assets/styles/common.css +2 -0
- data/test/fixture/site/_assets/styles/reset.css +2 -0
- data/test/fixture/site/_bin/remove_comments +3 -0
- data/test/fixture/site/_plugins/minibundle.rb +1 -0
- data/test/fixture/site/_tmp/site.css +2 -0
- data/test/fixture/site/index.html +31 -0
- data/test/integration/minibundle_test.rb +72 -0
- data/test/integration/ministamp_test.rb +22 -0
- data/test/support/test_case.rb +51 -0
- metadata +141 -0
data/History.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rake/clean'
|
2
|
+
require 'shellwords'
|
3
|
+
|
4
|
+
require_relative 'lib/jekyll/minibundle/version'
|
5
|
+
gem_name = 'jekyll-minibundle'
|
6
|
+
|
7
|
+
namespace :gem do
|
8
|
+
CLEAN.include "#{gem_name}-*.gem"
|
9
|
+
|
10
|
+
desc 'Package the software as a gem'
|
11
|
+
task :build => :test do
|
12
|
+
sh %{gem build #{gem_name}.gemspec}
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Install the software as a gem'
|
16
|
+
task :install => :build do
|
17
|
+
sh %{gem install #{gem_name}-#{Jekyll::Minibundle::VERSION}}
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'Uninstall the gem'
|
21
|
+
task :uninstall => :clean do
|
22
|
+
sh %{gem uninstall #{gem_name}}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
desc 'Run tests'
|
27
|
+
task :test do
|
28
|
+
test_dir = 'test'
|
29
|
+
test_glob = 'integration/**/*_test.rb'
|
30
|
+
includes = ['lib', test_dir].join(':')
|
31
|
+
tests = Dir["#{test_dir}/#{test_glob}"].
|
32
|
+
map { |file| %r{^test/(.+)\.rb$}.match(file)[1] }.
|
33
|
+
shelljoin
|
34
|
+
test_cmd = %{bundle exec ruby -I#{includes} -e 'ARGV.each { |f| require f }' #{tests}}
|
35
|
+
bundle_cmd = File.expand_path(File.join(File.dirname(__FILE__), test_dir, 'fixture/site/_bin/remove_comments'))
|
36
|
+
env = {
|
37
|
+
'JEKYLL_MINIBUNDLE_CMD_JS' => bundle_cmd,
|
38
|
+
'JEKYLL_MINIBUNDLE_CMD_CSS' => bundle_cmd
|
39
|
+
}
|
40
|
+
sh(env, test_cmd)
|
41
|
+
end
|
42
|
+
|
43
|
+
CLEAN.include 'test/fixture/site/_site'
|
44
|
+
|
45
|
+
task :default => :test
|
data/Readme.md
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
# Jekyll Minibundle plugin
|
2
|
+
|
3
|
+
A minimalistic plugin for bundling assets to
|
4
|
+
[Jekyll](https://github.com/mojombo/jekyll)'s site generation
|
5
|
+
directory.
|
6
|
+
|
7
|
+
In addition to the plugin, you need your asset bundling tool of choice
|
8
|
+
only. The plugin needs no other configuration than setting an
|
9
|
+
environment variable.
|
10
|
+
|
11
|
+
Tested with Ruby MRI 1.9.3. Ruby 1.8 is *not* supported.
|
12
|
+
|
13
|
+
# Features
|
14
|
+
|
15
|
+
There are two features: asset stamping with MD5 digest over the
|
16
|
+
contents of the asset, and asset bundling combined with the first
|
17
|
+
feature.
|
18
|
+
|
19
|
+
You still need a separate bundling tool, such as
|
20
|
+
[UglifyJS2](https://github.com/mishoo/UglifyJS2) to do the actual work
|
21
|
+
of bundling (concatenation, minification). There are no other
|
22
|
+
dependencies.
|
23
|
+
|
24
|
+
Why is this good? Well, a unique content specific identifier in asset
|
25
|
+
filename is the best way to handle web caching, because you can allow
|
26
|
+
caching the asset for forever. Calculating MD5 digest over the
|
27
|
+
contents of the asset is fast and the resulting digest is reasonably
|
28
|
+
unique to be generated automatically.
|
29
|
+
|
30
|
+
Asset bundling is good for reducing the number of requests to server
|
31
|
+
upon page load. It also allows minification for stylesheets and
|
32
|
+
JavaScript sources, which makes asset sizes smaller and thus faster to
|
33
|
+
load over network.
|
34
|
+
|
35
|
+
# Usage
|
36
|
+
|
37
|
+
The plugin is shipped as a
|
38
|
+
[RubyGem](https://rubygems.org/gems/jekyll-minibundle):
|
39
|
+
|
40
|
+
gem install jekyll-minibundle
|
41
|
+
|
42
|
+
Add file `_plugins/minibundle.rb` to your Jekyll site project with
|
43
|
+
this line:
|
44
|
+
|
45
|
+
require 'jekyll/minibundle'
|
46
|
+
|
47
|
+
## Asset stamping
|
48
|
+
|
49
|
+
Asset stamping is intended to be used together with
|
50
|
+
[Compass](http://compass-style.org/) and other similar asset
|
51
|
+
generation tools where you do not want to include unprocessed input
|
52
|
+
assets in the generated site.
|
53
|
+
|
54
|
+
Configure Compass to take inputs from `_assets/styles/*.scss` and to
|
55
|
+
put output to `_tmp/site.css`. Use `ministamp` tag to copy the
|
56
|
+
processed style asset to the generated site:
|
57
|
+
|
58
|
+
<link href="{% ministamp _tmp/site.css assets/site.css %}" rel="stylesheet" media="screen, projection">
|
59
|
+
|
60
|
+
Output, containing the MD5 digest in the filename:
|
61
|
+
|
62
|
+
<link href="assets/site-390be921ee0eff063817bb5ef2954300.css" rel="stylesheet" media="screen, projection">
|
63
|
+
|
64
|
+
This feature does not require any external tools.
|
65
|
+
|
66
|
+
## Asset bundling
|
67
|
+
|
68
|
+
A straightforward way to bundle assets with any tool that supports
|
69
|
+
reading input files from STDIN and writing the output to STDOUT. The
|
70
|
+
bundled file has MD5 digest in the filename.
|
71
|
+
|
72
|
+
Place `minibundle` block with configuration to your content file where
|
73
|
+
you want the generated markup to appear. For example, for bundling
|
74
|
+
JavaScript sources:
|
75
|
+
|
76
|
+
{% minibundle js %}
|
77
|
+
source_dir: _assets/scripts
|
78
|
+
destination_path: assets/site
|
79
|
+
assets:
|
80
|
+
- dependency
|
81
|
+
- app
|
82
|
+
attributes:
|
83
|
+
id: my-scripts
|
84
|
+
{% endminibundle %}
|
85
|
+
|
86
|
+
Then, specify the command for launching your favorite bundling tool in
|
87
|
+
`$JEKYLL_MINIBUNDLE_CMD_JS` environment variable. For example, when
|
88
|
+
launching Jekyll:
|
89
|
+
|
90
|
+
$ JEKYLL_MINIBUNDLE_CMD_JS="./node_modules/.bin/uglifyjs --" jekyll
|
91
|
+
|
92
|
+
You can pass custom attributes to the generated markup with
|
93
|
+
`attributes` map in the configuration.
|
94
|
+
|
95
|
+
Output:
|
96
|
+
|
97
|
+
<script type="text/javascript" src="assets/site-8e764372a0dbd296033cb2a416f064b5.js" id="my-scripts"></script>
|
98
|
+
|
99
|
+
For bundling CSS assets, you use `css` as the argument to `minibundle` block:
|
100
|
+
|
101
|
+
{% minibundle css %}
|
102
|
+
source_dir: _assets/styles
|
103
|
+
destination_path: assets/site
|
104
|
+
assets:
|
105
|
+
- reset
|
106
|
+
- common
|
107
|
+
attributes:
|
108
|
+
media: screen
|
109
|
+
{% endminibundle %}
|
110
|
+
|
111
|
+
And then specify the command for launching bundling in
|
112
|
+
`$JEKYLL_MINIBUNDLE_CMD_CSS` environment variable.
|
113
|
+
|
114
|
+
# Example site
|
115
|
+
|
116
|
+
See the contents of `test/fixture/site` directory.
|
117
|
+
|
118
|
+
# License
|
119
|
+
|
120
|
+
Copyright (c) 2012 Tuomas Kareinen
|
121
|
+
|
122
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
123
|
+
of this software and associated documentation files (the "Software"), to deal
|
124
|
+
in the Software without restriction, including without limitation the rights
|
125
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
126
|
+
copies of the Software, and to permit persons to whom the Software is
|
127
|
+
furnished to do so, subject to the following conditions:
|
128
|
+
|
129
|
+
The above copyright notice and this permission notice shall be included in
|
130
|
+
all copies or substantial portions of the Software.
|
131
|
+
|
132
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
133
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
134
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
135
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
136
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
137
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
138
|
+
THE SOFTWARE.
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
module Jekyll::Minibundle
|
4
|
+
class AssetBundle
|
5
|
+
def initialize(type, assets, site_dir)
|
6
|
+
@type, @assets, @site_dir = type, assets, site_dir
|
7
|
+
@temp_file = Tempfile.new "jekyll-minibundle-#{@type}-"
|
8
|
+
at_exit { @temp_file.close! }
|
9
|
+
end
|
10
|
+
|
11
|
+
def path
|
12
|
+
@temp_file.path
|
13
|
+
end
|
14
|
+
|
15
|
+
def make_bundle
|
16
|
+
pipe_bundling_to_temp_file bundling_cmd do |wr|
|
17
|
+
puts "Bundling #{@type} assets:"
|
18
|
+
@assets.each do |asset|
|
19
|
+
puts " #{asset}"
|
20
|
+
IO.foreach(asset) { |line| wr.write line }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def bundling_cmd
|
29
|
+
key = "JEKYLL_MINIBUNDLE_CMD_#{@type.upcase}"
|
30
|
+
cmd = ENV[key]
|
31
|
+
raise "You need to set bundling command in $#{key}" if !cmd
|
32
|
+
cmd
|
33
|
+
end
|
34
|
+
|
35
|
+
def pipe_bundling_to_temp_file(cmd)
|
36
|
+
pid = nil
|
37
|
+
rd, wr = IO.pipe
|
38
|
+
Dir.chdir @site_dir do
|
39
|
+
pid = spawn cmd, out: [@temp_file.path, 'w'], in: rd
|
40
|
+
end
|
41
|
+
yield wr
|
42
|
+
wr.close
|
43
|
+
Process.waitpid2 pid
|
44
|
+
ensure
|
45
|
+
wr.close unless wr.closed?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Jekyll::Minibundle
|
4
|
+
module AssetFileSupport
|
5
|
+
def static_file!(site)
|
6
|
+
static_file_exists = site.static_files.find { |f| f.path == path }
|
7
|
+
site.static_files << self unless static_file_exists
|
8
|
+
end
|
9
|
+
|
10
|
+
def write_destination(gensite_dir)
|
11
|
+
destination_path = destination gensite_dir
|
12
|
+
FileUtils.mkdir_p File.dirname(destination_path)
|
13
|
+
FileUtils.cp path, destination_path
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'jekyll/minibundle/asset_bundle'
|
2
|
+
require 'jekyll/minibundle/asset_file_support'
|
3
|
+
require 'jekyll/minibundle/bundle_markup'
|
4
|
+
|
5
|
+
module Jekyll::Minibundle
|
6
|
+
class BundleFile
|
7
|
+
include AssetFileSupport
|
8
|
+
|
9
|
+
@@mtimes = Hash.new
|
10
|
+
|
11
|
+
def initialize(config)
|
12
|
+
@type = config['type']
|
13
|
+
@site_dir = config['site_dir']
|
14
|
+
source_dir = File.join @site_dir, config['source_dir']
|
15
|
+
@destination_path = config['destination_path']
|
16
|
+
@assets = config['assets'].map { |asset_path| File.join source_dir, "#{asset_path}.#{@type}" }
|
17
|
+
@attributes = config['attributes']
|
18
|
+
update_mtime
|
19
|
+
end
|
20
|
+
|
21
|
+
def path
|
22
|
+
asset_bundle.path
|
23
|
+
end
|
24
|
+
|
25
|
+
def asset_path
|
26
|
+
"#{@destination_path}-#{asset_stamp}.#{@type}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def destination(destination_base_dir)
|
30
|
+
File.join destination_base_dir, asset_path
|
31
|
+
end
|
32
|
+
|
33
|
+
def mtime
|
34
|
+
@assets.max { |f| File.stat(f).mtime.to_i }
|
35
|
+
end
|
36
|
+
|
37
|
+
def modified?
|
38
|
+
@@mtimes[path] != mtime
|
39
|
+
end
|
40
|
+
|
41
|
+
def write(gensite_dir)
|
42
|
+
rebundle_assets if modified?
|
43
|
+
destination_path = destination gensite_dir
|
44
|
+
|
45
|
+
return false if File.exist?(destination_path) and !modified?
|
46
|
+
|
47
|
+
update_mtime
|
48
|
+
write_destination gensite_dir
|
49
|
+
|
50
|
+
true
|
51
|
+
end
|
52
|
+
|
53
|
+
def markup
|
54
|
+
BundleMarkup.make_markup @type, asset_path, @attributes
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def asset_stamp
|
60
|
+
@asset_stamp ||= AssetStamp.from_file(path)
|
61
|
+
end
|
62
|
+
|
63
|
+
def asset_bundle
|
64
|
+
@asset_bundle ||= AssetBundle.new(@type, @assets, @site_dir).make_bundle
|
65
|
+
end
|
66
|
+
|
67
|
+
def rebundle_assets
|
68
|
+
@asset_stamp = nil
|
69
|
+
asset_bundle.make_bundle
|
70
|
+
end
|
71
|
+
|
72
|
+
def update_mtime
|
73
|
+
@@mtimes[path] = mtime
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Jekyll::Minibundle
|
2
|
+
module BundleMarkup
|
3
|
+
def self.make_markup(type, path, attributes)
|
4
|
+
case type
|
5
|
+
when :js
|
6
|
+
%{<script type="text/javascript" src="#{path}"#{make_attributes(attributes)}></script>}
|
7
|
+
when :css
|
8
|
+
%{<link rel="stylesheet" href="#{path}"#{make_attributes(attributes)}>}
|
9
|
+
else
|
10
|
+
raise "Unknown type for generating bundle markup: #{type}, #{path}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.make_attributes(attributes)
|
15
|
+
attributes.map { |name, value| %{ #{name}="#{value}"} }.join('')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'jekyll/minibundle/bundle_file'
|
3
|
+
|
4
|
+
module Jekyll::Minibundle
|
5
|
+
class MiniBundleBlock < Liquid::Block
|
6
|
+
def initialize(tag_name, type, _tokens)
|
7
|
+
super
|
8
|
+
@type = type.strip.to_sym
|
9
|
+
end
|
10
|
+
|
11
|
+
def render(context)
|
12
|
+
current_config = YAML.load super
|
13
|
+
site = context.registers[:site]
|
14
|
+
config = default_config.
|
15
|
+
merge(current_config).
|
16
|
+
merge({ 'type' => @type, 'site_dir' => site.source})
|
17
|
+
file = BundleFile.new config
|
18
|
+
file.static_file! site
|
19
|
+
file.markup
|
20
|
+
end
|
21
|
+
|
22
|
+
def default_config
|
23
|
+
{
|
24
|
+
'source_dir' => '_assets',
|
25
|
+
'destination_path' => 'assets/site',
|
26
|
+
'assets' => [],
|
27
|
+
'attributes' => {}
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Liquid::Template.register_tag('minibundle', Jekyll::Minibundle::MiniBundleBlock)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'jekyll/minibundle/stamp_file'
|
2
|
+
|
3
|
+
module Jekyll::Minibundle
|
4
|
+
class MiniStampTag < Liquid::Tag
|
5
|
+
def initialize(tag_name, text, _tokens)
|
6
|
+
super
|
7
|
+
@source, @destination = text.split(/\s+/, 3)[0, 2]
|
8
|
+
end
|
9
|
+
|
10
|
+
def render(context)
|
11
|
+
site = context.registers[:site]
|
12
|
+
file = StampFile.new File.join(site.source, @source), @destination
|
13
|
+
file.static_file! site
|
14
|
+
file.asset_path
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Liquid::Template.register_tag('ministamp', Jekyll::Minibundle::MiniStampTag)
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'jekyll/minibundle/asset_file_support'
|
2
|
+
require 'jekyll/minibundle/asset_stamp'
|
3
|
+
|
4
|
+
module Jekyll::Minibundle
|
5
|
+
class StampFile
|
6
|
+
include AssetFileSupport
|
7
|
+
|
8
|
+
@@mtimes = Hash.new
|
9
|
+
|
10
|
+
def initialize(source_path, destination_path)
|
11
|
+
@source_path = source_path
|
12
|
+
@destination_dir = File.dirname destination_path
|
13
|
+
@destination_extension = File.extname destination_path
|
14
|
+
base = File.basename destination_path
|
15
|
+
@destination_base_prefix = base[0 .. -(@destination_extension.size + 1)]
|
16
|
+
update_mtime
|
17
|
+
end
|
18
|
+
|
19
|
+
def path
|
20
|
+
@source_path
|
21
|
+
end
|
22
|
+
|
23
|
+
def asset_path
|
24
|
+
File.join @destination_dir, destination_basename
|
25
|
+
end
|
26
|
+
|
27
|
+
def destination(gensite_dir)
|
28
|
+
File.join gensite_dir, @destination_dir, destination_basename
|
29
|
+
end
|
30
|
+
|
31
|
+
def mtime
|
32
|
+
File.stat(path).mtime.to_i
|
33
|
+
end
|
34
|
+
|
35
|
+
def modified?
|
36
|
+
@@mtimes[path] != mtime
|
37
|
+
end
|
38
|
+
|
39
|
+
def write(gensite_dir)
|
40
|
+
clear_asset_stamp if modified?
|
41
|
+
destination_path = destination gensite_dir
|
42
|
+
|
43
|
+
return false if File.exist?(destination_path) and !modified?
|
44
|
+
|
45
|
+
update_mtime
|
46
|
+
write_destination gensite_dir
|
47
|
+
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def destination_basename
|
54
|
+
"#{@destination_base_prefix}-#{asset_stamp}#{@destination_extension}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def asset_stamp
|
58
|
+
@asset_stamp ||= AssetStamp.from_file(path)
|
59
|
+
end
|
60
|
+
|
61
|
+
def clear_asset_stamp
|
62
|
+
@asset_stamp = nil
|
63
|
+
end
|
64
|
+
|
65
|
+
def update_mtime
|
66
|
+
@@mtimes[path] = mtime
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'jekyll/minibundle'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
---
|
2
|
+
layout: nil
|
3
|
+
---
|
4
|
+
|
5
|
+
<!DOCTYPE html>
|
6
|
+
<html>
|
7
|
+
<head>
|
8
|
+
<link rel="stylesheet" href="{% ministamp _tmp/site.css assets/screen.css %}" media="screen">
|
9
|
+
{% minibundle css %}
|
10
|
+
source_dir: _assets/styles
|
11
|
+
destination_path: assets/site
|
12
|
+
assets:
|
13
|
+
- reset
|
14
|
+
- common
|
15
|
+
attributes:
|
16
|
+
id: my-styles
|
17
|
+
media: projection
|
18
|
+
{% endminibundle %}
|
19
|
+
</head>
|
20
|
+
<body>
|
21
|
+
{% minibundle js %}
|
22
|
+
source_dir: _assets/scripts
|
23
|
+
destination_path: assets/site
|
24
|
+
assets:
|
25
|
+
- dependency
|
26
|
+
- app
|
27
|
+
attributes:
|
28
|
+
id: my-scripts
|
29
|
+
{% endminibundle %}
|
30
|
+
</body>
|
31
|
+
</html>
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'support/test_case'
|
2
|
+
|
3
|
+
module Jekyll::Minibundle::Test
|
4
|
+
class MiniBundleTest < TestCase
|
5
|
+
EXPECTED_CSS_ASSET_PATH = 'assets/site-b2e0ecc1c100effc2c7353caad20c327.css'
|
6
|
+
EXPECTED_JS_ASSET_PATH = 'assets/site-f78e0c4497343c33e9282df5d684540e.js'
|
7
|
+
|
8
|
+
def test_css_asset_bundle_has_configured_attributes
|
9
|
+
element = find_html_element_from_index(%{head link[href="#{EXPECTED_CSS_ASSET_PATH}"]}).first
|
10
|
+
assert_equal 'my-styles', element['id']
|
11
|
+
assert_equal 'projection', element['media']
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_js_asset_bundle_has_configured_attributes
|
15
|
+
element = find_html_element_from_index(%{body script[src="#{EXPECTED_JS_ASSET_PATH}"]}).first
|
16
|
+
assert_equal 'my-scripts', element['id']
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_css_asset_bundle_has_stamp
|
20
|
+
actual = find_html_element_from_index('head link[media="projection"]').first['href']
|
21
|
+
assert_equal EXPECTED_CSS_ASSET_PATH, actual
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_js_asset_bundle_has_stamp
|
25
|
+
actual = find_html_element_from_index('body script').first['src']
|
26
|
+
assert_equal EXPECTED_JS_ASSET_PATH, actual
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_css_asset_bundle_is_copied_to_destination_dir
|
30
|
+
assert File.exists?(gensite_path(EXPECTED_CSS_ASSET_PATH))
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_js_asset_bundle_is_copied_to_destination_dir
|
34
|
+
assert File.exists?(gensite_path(EXPECTED_JS_ASSET_PATH))
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_css_asset_bundle_is_concatenated_in_configured_order
|
38
|
+
bundle = File.read(gensite_path(EXPECTED_CSS_ASSET_PATH))
|
39
|
+
assert bundle.index('html { margin: 0; }') < bundle.index('p { margin: 0; }')
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_js_asset_bundle_is_concatenated_in_configured_order
|
43
|
+
bundle = File.read(gensite_path(EXPECTED_JS_ASSET_PATH))
|
44
|
+
assert bundle.index('root.dependency = {};') < bundle.index('root.app = {};')
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_css_asset_bundle_is_minified
|
48
|
+
source_contents_size = source_assets_size('_assets/styles', %w{reset common}, 'css')
|
49
|
+
destination_contents_size = File.read(gensite_path(EXPECTED_CSS_ASSET_PATH)).size
|
50
|
+
assert destination_contents_size < source_contents_size
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_js_asset_bundle_is_minified
|
54
|
+
source_contents_size = source_assets_size('_assets/scripts', %w{dependency app}, 'js')
|
55
|
+
destination_contents_size = File.read(gensite_path(EXPECTED_JS_ASSET_PATH)).size
|
56
|
+
assert destination_contents_size < source_contents_size
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def find_html_element_from_index(css)
|
62
|
+
find_html_element(read_from_gensite('index.html'), css)
|
63
|
+
end
|
64
|
+
|
65
|
+
def source_assets_size(fixture_subdir, assets, type)
|
66
|
+
assets.
|
67
|
+
map { |f| File.read fixture_path(fixture_subdir, "#{f}.#{type}") }.
|
68
|
+
join('').
|
69
|
+
size
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'support/test_case'
|
2
|
+
|
3
|
+
module Jekyll::Minibundle::Test
|
4
|
+
class MiniStampTest < TestCase
|
5
|
+
EXPECTED_ASSET_PATH = 'assets/screen-390be921ee0eff063817bb5ef2954300.css'
|
6
|
+
|
7
|
+
def test_asset_path_has_stamp
|
8
|
+
actual = find_html_element(read_from_gensite('index.html'), 'head link').first['href']
|
9
|
+
assert_equal EXPECTED_ASSET_PATH, actual
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_asset_file_is_copied_to_destination_dir
|
13
|
+
assert File.exists?(gensite_path(EXPECTED_ASSET_PATH))
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_asset_file_is_equal_to_source_file
|
17
|
+
source_contents = File.read fixture_path('_tmp/site.css')
|
18
|
+
destination_contents = File.read gensite_path(EXPECTED_ASSET_PATH)
|
19
|
+
assert_equal source_contents, destination_contents
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'tempfile'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'nokogiri'
|
5
|
+
require 'jekyll'
|
6
|
+
require 'jekyll/minibundle'
|
7
|
+
|
8
|
+
module Jekyll::Minibundle::Test
|
9
|
+
class TestCase < ::MiniTest::Unit::TestCase
|
10
|
+
FIXTURE_DIR = File.expand_path(File.join(File.dirname(__FILE__), '../fixture/site'))
|
11
|
+
|
12
|
+
def fixture_path(*args)
|
13
|
+
File.join(FIXTURE_DIR, *args)
|
14
|
+
end
|
15
|
+
|
16
|
+
def gensite_path(*args)
|
17
|
+
File.join(_gensite_dir, *args)
|
18
|
+
end
|
19
|
+
|
20
|
+
def read_from_gensite(*args)
|
21
|
+
File.read gensite_path(*args)
|
22
|
+
end
|
23
|
+
|
24
|
+
def find_html_element(file, css)
|
25
|
+
Nokogiri::HTML(file).css(css)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def _gensite_dir(&block)
|
31
|
+
@@_gensite_dir ||= begin
|
32
|
+
dir = Dir.mktmpdir('jekyll-minibundle-test-')
|
33
|
+
at_exit do
|
34
|
+
FileUtils.rm_rf dir
|
35
|
+
puts "Cleaned generated site for tests: #{dir}"
|
36
|
+
end
|
37
|
+
Dir.chdir(dir) { _generate_site dir }
|
38
|
+
puts "Generated site for tests: #{dir}"
|
39
|
+
dir
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def _generate_site(destination)
|
44
|
+
options = {
|
45
|
+
'source' => fixture_path,
|
46
|
+
'destination' => destination
|
47
|
+
}
|
48
|
+
Jekyll::Site.new(Jekyll.configuration(options)).process
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
metadata
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jekyll-minibundle
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Tuomas Kareinen
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-07 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: jekyll
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.11.2
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.11.2
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: minitest
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 4.3.3
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 4.3.3
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: nokogiri
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.5.5
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.5.5
|
62
|
+
description: ! 'Provides ''minibundle'' block for bundling multiple assets, ''ministamp''
|
63
|
+
|
64
|
+
tag for stamping a single asset.
|
65
|
+
|
66
|
+
|
67
|
+
No other dependencies than the asset bundler of your choice.
|
68
|
+
|
69
|
+
'
|
70
|
+
email: tkareine@gmail.com
|
71
|
+
executables: []
|
72
|
+
extensions: []
|
73
|
+
extra_rdoc_files: []
|
74
|
+
files:
|
75
|
+
- History.md
|
76
|
+
- Rakefile
|
77
|
+
- Readme.md
|
78
|
+
- lib/jekyll/minibundle.rb
|
79
|
+
- lib/jekyll/minibundle/asset_bundle.rb
|
80
|
+
- lib/jekyll/minibundle/asset_file_support.rb
|
81
|
+
- lib/jekyll/minibundle/asset_stamp.rb
|
82
|
+
- lib/jekyll/minibundle/bundle_file.rb
|
83
|
+
- lib/jekyll/minibundle/bundle_markup.rb
|
84
|
+
- lib/jekyll/minibundle/mini_bundle_block.rb
|
85
|
+
- lib/jekyll/minibundle/mini_stamp_tag.rb
|
86
|
+
- lib/jekyll/minibundle/stamp_file.rb
|
87
|
+
- lib/jekyll/minibundle/version.rb
|
88
|
+
- test/fixture/site/_assets/scripts/app.js
|
89
|
+
- test/fixture/site/_assets/scripts/dependency.js
|
90
|
+
- test/fixture/site/_assets/styles/common.css
|
91
|
+
- test/fixture/site/_assets/styles/reset.css
|
92
|
+
- test/fixture/site/_bin/remove_comments
|
93
|
+
- test/fixture/site/_plugins/minibundle.rb
|
94
|
+
- test/fixture/site/_tmp/site.css
|
95
|
+
- test/fixture/site/index.html
|
96
|
+
- test/integration/minibundle_test.rb
|
97
|
+
- test/integration/ministamp_test.rb
|
98
|
+
- test/support/test_case.rb
|
99
|
+
homepage: https://github.com/tkareine/jekyll-minibundle
|
100
|
+
licenses:
|
101
|
+
- MIT
|
102
|
+
post_install_message:
|
103
|
+
rdoc_options:
|
104
|
+
- --line-numbers
|
105
|
+
- --title
|
106
|
+
- jekyll-minibundle
|
107
|
+
- --exclude
|
108
|
+
- test
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
none: false
|
113
|
+
requirements:
|
114
|
+
- - ! '>='
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ! '>='
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 1.8.24
|
126
|
+
signing_key:
|
127
|
+
specification_version: 3
|
128
|
+
summary: Straightforward asset bundling plugin for Jekyll
|
129
|
+
test_files:
|
130
|
+
- test/fixture/site/_assets/scripts/app.js
|
131
|
+
- test/fixture/site/_assets/scripts/dependency.js
|
132
|
+
- test/fixture/site/_assets/styles/common.css
|
133
|
+
- test/fixture/site/_assets/styles/reset.css
|
134
|
+
- test/fixture/site/_bin/remove_comments
|
135
|
+
- test/fixture/site/_plugins/minibundle.rb
|
136
|
+
- test/fixture/site/_tmp/site.css
|
137
|
+
- test/fixture/site/index.html
|
138
|
+
- test/integration/minibundle_test.rb
|
139
|
+
- test/integration/ministamp_test.rb
|
140
|
+
- test/support/test_case.rb
|
141
|
+
has_rdoc:
|