Permalink
Browse files

While in debug mode, urls now have a timestamp appended to the URL. A…

…dditionally, the default "build_number" is set to "current". These combined options should make debug-mode pages reload much faster than before.
  • Loading branch information...
1 parent c7b4d64 commit 7445ecc3fa2ea96954cb67d4f539b0ea77b272b8 Charles Jolley committed Feb 3, 2009
View
@@ -87,13 +87,14 @@ mode :debug do
# In debug mode, we want to simply compute the build number each time
# to ensure the latest version is always loaded.
- :build_number => nil,
-
- # the fast build number method uses file mtimes. It will work correctly
- # on a single machine, but it may produce different build numbers from
- # one machine to the next, so it should not be used in production mode
- # builds.
- :compute_fast_builder_numbers => true,
+ :build_number => :current,
+
+ # Instructs the URL builders to include a timestamp token at the end of
+ # urls. This option is only useful in development mode since browsers
+ # will respect the timestamp token as a way to unique the url. This
+ # should not be used in production as some proxies on the internet do
+ # not respect tokens.
+ :timestamp_urls => true,
:use_packed => false
@@ -56,7 +56,7 @@ def writelines(dst_path, lines)
def replace_static_url(line)
line.gsub(/(sc_static|static_url)\(\s*['"](.+)['"]\s*\)/) do | rsrc |
static_entry = entry.manifest.find_entry($2)
- static_url(static_entry.nil? ? '' : static_entry.url)
+ static_url(static_entry.nil? ? '' : static_entry.cacheable_url)
end
end
@@ -35,9 +35,9 @@ def stylesheets_for_client(target_name = nil, opts = nil)
# include either the entry URL or URL of ordered entries
# depending on setup
if combine_stylesheets
- urls << cur_entry.url
+ urls << cur_entry.cacheable_url
else
- urls += cur_entry.ordered_entries.map { |e| e.url }
+ urls += cur_entry.ordered_entries.map { |e| e.cacheable_url }
end
# add any stylesheet libs from the target
@@ -88,9 +88,9 @@ def javascripts_for_client(target_name = nil, opts = {})
# include either the entry URL or URL of ordered entries
# depending on setup
if combine_javascript
- urls << cur_entry.url
+ urls << cur_entry.cacheable_url
else
- urls += cur_entry.ordered_entries.map { |e| e.url }
+ urls += cur_entry.ordered_entries.map { |e| e.cacheable_url }
end
# add any stylesheet libs from the target
@@ -120,7 +120,7 @@ def sc_static(resource_name, opts = {})
end
entry = m.find_entry(resource_name)
- entry.nil? ? '' : entry.url
+ entry.nil? ? '' : entry.cacheable_url
end
alias_method :static_url, :sc_static
@@ -104,6 +104,15 @@ def timestamp
end
end
+ # Returns a URL with a possible timestamp token appended to the end of
+ # the entry if the target's timestamp_url config is set. Otherwise
+ # returns the URL itself.
+ def cacheable_url
+ ret = self.url
+ ret = [ret, self.timestamp].join('?') if target.config.timestamp_urls
+ return ret
+ end
+
# Scans the source paths (first staging any source entries) for the
# passed regex. Your block will be executed with each line that matched.
# Returns the results of each block
@@ -249,26 +249,14 @@ def compute_build_number(seen=nil)
if build_number.nil?
require 'digest/md5'
- # No predefined build number was found, instead let's compute it!
- if config.compute_fast_build_numbers
- # Note: this method is not good for production builds because it
- # depends on the file mtime, which can change from one machine to
- # the next. It is faster though, which is better for use in
- # development mode when you need to quickly calculate the build
- # number for an asset.
- digests = Dir.glob(File.join(source_root, '**', '*')).map do |path|
- File.mtime(path)
- end
- else
- # This method computes the build number based on the contents of the
- # files. It is not as fast as using an mtime, but it will remain
- # constant from one machine to the next so it can be used when
- # deploying across multiple build machines, etc.
- digests = Dir.glob(File.join(source_root, '**', '*')).map do |path|
- allowed = File.exists?(path) && !File.directory?(path)
- allowed = allowed && !target_directory?(path)
- allowed ? Digest::SHA1.hexdigest(File.read(path)) : nil
- end
+ # Computes the build number based on the contents of the
+ # files. It is not as fast as using an mtime, but it will remain
+ # constant from one machine to the next so it can be used when
+ # deploying across multiple build machines, etc.
+ digests = Dir.glob(File.join(source_root, '**', '*')).map do |path|
+ allowed = File.exists?(path) && !File.directory?(path)
+ allowed = allowed && !target_directory?(path)
+ allowed ? Digest::SHA1.hexdigest(File.read(path)) : nil
end
digests.compact!
@@ -11,6 +11,12 @@
# in production mode
@target.config.load_debug = false
@target.config.theme = nil
+ @target.config.timestamp_urls = false
+
+ # make sure all targets have the same settings...
+ @target.expand_required_targets.each do |t|
+ t.config.timestamp_urls = false
+ end
# run std rules to run manifest. Then verify preconditions to make sure
# no other changes to the build system effect the ability of these tests
@@ -193,6 +199,14 @@
@builder.sc_static('fr.png', :language => :fr).should =~ /french-icons\/fr.png/
end
+ it "respects the timestamp_url option for static_url()" do
+ @target.config.timestamp_urls = false
+ @builder.static_url('icons/image').should_not =~ /\?.+$/
+
+ @target.config.timestamp_urls = true
+ @builder.static_url('icons/image').should =~ /\?.+$/
+ end
+
it "accepts sc_resource(rsrc_name, opts). :layout opt may be used to set layout. otherwise this is scanned for during manifest building" do
@builder.sc_resource('foo', :layout => 'bar')
@builder.instance_variable_get('@layout').should == 'bar'
@@ -295,6 +309,43 @@ def expect_imports(result, urls = [])
result.should =~ /href=\"bar\"/
end
+ describe "timestamp_urls support" do
+
+ def test_timestamps(should_have)
+ result = @builder.stylesheets_for_client
+ matches = 0
+ result.scan(/href=\"([^\"]+)\"/) do |m|
+ m=m.first # look @ match...
+ matches += 1
+ if should_have
+ m.should =~ /\?.+$/
+ else
+ m.should_not =~ /\?.+$/
+ end
+ end
+ matches.should > 0 # should match some urls...
+ end
+
+ it "does NOT timestamp to all urls if timestamp_urls is false" do
+ # simulate having timestamp_urls set true in the root buildfile
+ @target.config.timestamp_urls = false # preconditon
+ @target.expand_required_targets.each do |t|
+ t.config.timestamp_urls = false
+ end
+ test_timestamps false
+ end
+
+ it "does timestamp all urls if timestamp_urls is true" do
+ # simulate having timestamp_urls set true in the root buildfile
+ @target.config.timestamp_urls = true # precondition
+ @target.expand_required_targets.each do |t|
+ t.config.timestamp_urls = true
+ end
+ test_timestamps true
+ end
+ end
+
+
it "adds stylesheet for debug if CONFIG.load_debug" do
# figure expected urls...
t = @project.target_for(:debug)
@@ -400,6 +451,40 @@ def expect_scripts(result, urls = [])
result = @builder.javascripts_for_client
result.should_not =~ url
end
+
+ describe "timestamp_urls support" do
+
+ def test_timestamps(should_have)
+ result = @builder.javascripts_for_client
+ matches = 0
+ result.scan(/src=\"([^\"]+)\"/) do |m|
+ matches += 1
+ m = m.first # look @ match
+ if should_have
+ m.should =~ /\?.+$/
+ else
+ m.should_not =~ /\?.+$/
+ end
+ end
+ matches.should > 0 # should match some urls...
+ end
+
+ it "does NOT timestamp to all urls if timestamp_urls is false" do
+ @target.config.timestamp_urls = false # preconditon
+ @target.expand_required_targets.each do |t|
+ t.config.timestamp_urls = false
+ end
+ test_timestamps false
+ end
+
+ it "does timestamp all urls if timestamp_urls is true" do
+ @target.config.timestamp_urls = true # precondition
+ @target.expand_required_targets.each do |t|
+ t.config.timestamp_urls = true
+ end
+ test_timestamps true
+ end
+ end
end
@@ -9,6 +9,7 @@
# add fake image entry for sc_static tests..
@manifest.add_entry 'icons/image.png'
+ @target.config.timestamp_urls = false
end
@@ -40,6 +41,22 @@ def run_builder(filename, localize=false)
line.should =~ /'.+'/ # important MUST have some url...
end
end
+
+ it "static_url() and sc_static() respect timestamp_urls" do
+ @target.config.timestamp_urls = false
+ lines = run_builder 'sc_static.js'
+ lines.each do |line|
+ next if line.size == 1
+ line.should_not =~ /'.+\?.+'/ # important MUST NOT have some url w/ timestamp...
+ end
+
+ @target.config.timestamp_urls = true
+ lines = run_builder 'sc_static.js'
+ lines.each do |line|
+ next if line.size == 1
+ line.should =~ /'.+\?.+'/ # important MUST have some url w/ timestamp...
+ end
+ end
it "removes server-side keys from localized strings.js files" do
lines = run_builder 'strings.js', true
@@ -9,6 +9,7 @@
# add fake image entry for sc_static tests..
@manifest.add_entry 'icons/image.png'
+ @target.config.timestamp_urls = false
end
@@ -42,5 +43,21 @@ def run_builder(filename)
line.should =~ /url\('.+'\)/ # important MUST have some url...
end
end
+
+ it "static_url() and sc_static() respects config.timestamp_urls" do
+ @target.config.timestamp_urls = false
+ lines = run_builder 'sc_static.css'
+ lines.each do |line|
+ next if line.size == 1
+ line.should_not =~ /url\('.+\?.+'\)/ # important MUST have some url...
+ end
+
+ @target.config.timestamp_urls = true
+ lines = run_builder 'sc_static.css'
+ lines.each do |line|
+ next if line.size == 1
+ line.should =~ /url\('.+\?.+'\)/ # important MUST have some url...
+ end
+ end
end
@@ -0,0 +1,31 @@
+require File.join(File.dirname(__FILE__), %w[.. .. .. spec_helper])
+
+describe SC::ManifestEntry, 'timestamp_url' do
+
+ include SC::SpecHelpers
+
+ before do
+ @project = fixture_project(:real_world)
+ @target = @project.target_for :contacts
+ @manifest = @target.manifest_for(:language => :en)
+
+ # create entry manually to avoid calling prepare
+ @entry = SC::ManifestEntry.new @manifest,
+ :filename => "filename",
+ :url => "foo",
+ :source_path => "imaginary" / "path"
+ end
+
+ it "should return url itself if timestamp_url config is false" do
+ @target.config.timestamp_urls = false # preconditon
+ @entry.cacheable_url.should == 'foo'
+ end
+
+ it "should return url with timestamp token appended as query string if timestamp_url is true" do
+ @target.config.timestamp_urls = true # preconditon
+ @entry.timestamp.should_not be_blank # preconditon
+ @entry.cacheable_url.should == "foo?#{@entry.timestamp}"
+ end
+
+
+end
@@ -53,7 +53,6 @@ def add_dummyfile(project)
@target = @project.target_for(:sproutcore)
@target.config.build_numbers = nil #precondition
@target.config.build_number = nil #precondition
- @target.config.compute_fast_build_numbers = false
end
it "generates a unique build number based on content if nothing is explicitly set" do
@@ -72,44 +71,6 @@ def add_dummyfile(project)
end
end
- describe "fast method to compute build number" do
-
- before do
- @target = @project.target_for(:sproutcore)
- @target.config.build_numbers = nil #precondition
- @target.config.build_number = nil #precondition
- @target.config.compute_fast_build_numbers = true
- end
-
- it "uses faster method to compute build numbers" do
- start = Time.now
- 20.times { @target.compute_build_number }
- fast_time = Time.now - start
-
- @target.config.compute_fast_build_numbers = false
- start = Time.now
- 20.times { @target.compute_build_number }
- accurate_time = Time.now - start
-
- fast_time.should < accurate_time
- end
-
- it "generates a unique build number based on content if nothing is explicitly set" do
- @target.compute_build_number.should_not be_nil
- end
-
- it "changes its generated build number if contents of source files change" do
- old_build_number = @target.compute_build_number
-
- # write an extra file into target for testing
- add_dummyfile(@target)
-
- # get new build number
- new_build_number = @target.compute_build_number
- new_build_number.should_not eql(old_build_number)
- end
- end
-
it "changes generated build number if build number for a required target changes" do
target = @project.target_for(:sproutcore)
target.should_not be_nil

0 comments on commit 7445ecc

Please sign in to comment.