Perf
This commit is contained in:
parent
c213bd19df
commit
bf19bbfed7
|
@ -48,31 +48,38 @@ module Middleman::Cli
|
|||
verbose = options['verbose'] ? 0 : 1
|
||||
instrument = options['instrument']
|
||||
|
||||
@app = ::Middleman::Application.new do
|
||||
config[:mode] = :build
|
||||
config[:environment] = env
|
||||
config[:show_exceptions] = false
|
||||
::Middleman::Logger.singleton(verbose, instrument)
|
||||
builder = nil
|
||||
|
||||
::Middleman::Logger.singleton(verbose, instrument)
|
||||
|
||||
::Middleman::Util.instrument "builder_setup" do
|
||||
@app = ::Middleman::Application.new do
|
||||
config[:mode] = :build
|
||||
config[:environment] = env
|
||||
config[:show_exceptions] = false
|
||||
end
|
||||
|
||||
builder = Middleman::Builder.new(@app,
|
||||
glob: options['glob'],
|
||||
clean: options['clean'],
|
||||
parallel: options['parallel'])
|
||||
builder.thor = self
|
||||
builder.on_build_event(&method(:on_event))
|
||||
end
|
||||
|
||||
builder = Middleman::Builder.new(@app,
|
||||
glob: options['glob'],
|
||||
clean: options['clean'],
|
||||
parallel: options['parallel'])
|
||||
builder.thor = self
|
||||
builder.on_build_event(&method(:on_event))
|
||||
::Middleman::Util.instrument "builder_run" do
|
||||
if builder.run!
|
||||
clean_directories! if options['clean']
|
||||
shell.say 'Project built successfully.'
|
||||
else
|
||||
msg = 'There were errors during this build'
|
||||
unless options['verbose']
|
||||
msg << ', re-run with `middleman build --verbose` to see the full exception.'
|
||||
end
|
||||
shell.say msg, :red
|
||||
|
||||
if builder.run!
|
||||
clean_directories! if options['clean']
|
||||
shell.say 'Project built successfully.'
|
||||
else
|
||||
msg = 'There were errors during this build'
|
||||
unless options['verbose']
|
||||
msg << ', re-run with `middleman build --verbose` to see the full exception.'
|
||||
exit(1)
|
||||
end
|
||||
shell.say msg, :red
|
||||
|
||||
exit(1)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -110,22 +110,22 @@ Feature: Assets get file hashes appended to them and references to them are upda
|
|||
Scenario: Enabling an asset host still produces hashed files and references
|
||||
Given the Server is running at "asset-hash-host-app"
|
||||
When I go to "/"
|
||||
Then I should see 'href="http://middlemanapp.com/stylesheets/site-e587b659.css"'
|
||||
Then I should see 'href="http://middlemanapp.com/stylesheets/fragment-7af0b5ab.css"'
|
||||
Then I should see 'href="http://middlemanapp.com/stylesheets/site-4b64a653.css"'
|
||||
Then I should see 'href="http://middlemanapp.com/stylesheets/fragment-a772891f.css"'
|
||||
And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg"'
|
||||
And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg?test"'
|
||||
And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg?#test"'
|
||||
And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg#test"'
|
||||
When I go to "/subdir/"
|
||||
Then I should see 'href="http://middlemanapp.com/stylesheets/site-e587b659.css"'
|
||||
Then I should see 'href="http://middlemanapp.com/stylesheets/site-4b64a653.css"'
|
||||
And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg"'
|
||||
When I go to "/other/"
|
||||
Then I should see 'href="http://middlemanapp.com/stylesheets/site-e587b659.css"'
|
||||
Then I should see 'href="http://middlemanapp.com/stylesheets/site-4b64a653.css"'
|
||||
And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg"'
|
||||
And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg?test"'
|
||||
And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg?#test"'
|
||||
And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg#test"'
|
||||
When I go to "/stylesheets/fragment-7af0b5ab.css"
|
||||
When I go to "/stylesheets/fragment-a772891f.css"
|
||||
And I should see 'url("http://middlemanapp.com/images/100px-5fd6fb90.jpg")'
|
||||
And I should see 'url("http://middlemanapp.com/images/100px-5fd6fb90.jpg?test")'
|
||||
And I should see 'url("http://middlemanapp.com/images/100px-5fd6fb90.jpg?#test")'
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
activate :asset_host, host: "http://assets1.example.com"
|
|
@ -210,46 +210,51 @@ module Middleman
|
|||
# Search the root of the project for required files
|
||||
$LOAD_PATH.unshift(root) unless $LOAD_PATH.include?(root)
|
||||
|
||||
@callbacks = ::Middleman::CallbackManager.new
|
||||
@callbacks.install_methods!(self, [
|
||||
:initialized,
|
||||
:configure,
|
||||
:before_extensions,
|
||||
:before_sitemap,
|
||||
:before_configuration,
|
||||
:after_configuration,
|
||||
:after_configuration_eval,
|
||||
:ready,
|
||||
:before_build,
|
||||
:after_build,
|
||||
:before_shutdown,
|
||||
:before, # Before Rack requests
|
||||
:before_render,
|
||||
:after_render,
|
||||
:before_server
|
||||
])
|
||||
::Middleman::Util.instrument "application.setup" do
|
||||
@callbacks = ::Middleman::CallbackManager.new
|
||||
@callbacks.install_methods!(self, [
|
||||
:initialized,
|
||||
:configure,
|
||||
:before_extensions,
|
||||
:before_instance_block,
|
||||
:before_sitemap,
|
||||
:before_configuration,
|
||||
:after_configuration,
|
||||
:after_configuration_eval,
|
||||
:ready,
|
||||
:before_build,
|
||||
:after_build,
|
||||
:before_shutdown,
|
||||
:before, # Before Rack requests
|
||||
:before_render,
|
||||
:after_render,
|
||||
:before_server
|
||||
])
|
||||
|
||||
@middleware = Set.new
|
||||
@mappings = Set.new
|
||||
@middleware = Set.new
|
||||
@mappings = Set.new
|
||||
|
||||
@template_context_class = Class.new(Middleman::TemplateContext)
|
||||
@generic_template_context = @template_context_class.new(self)
|
||||
@config_context = ConfigContext.new(self, @template_context_class)
|
||||
@template_context_class = Class.new(Middleman::TemplateContext)
|
||||
@generic_template_context = @template_context_class.new(self)
|
||||
@config_context = ConfigContext.new(self, @template_context_class)
|
||||
|
||||
# Setup the default values from calls to set before initialization
|
||||
@config = ::Middleman::Configuration::ConfigurationManager.new
|
||||
@config.load_settings(self.class.config.all_settings)
|
||||
# Setup the default values from calls to set before initialization
|
||||
@config = ::Middleman::Configuration::ConfigurationManager.new
|
||||
@config.load_settings(self.class.config.all_settings)
|
||||
|
||||
config[:source] = ENV['MM_SOURCE'] if ENV['MM_SOURCE']
|
||||
config[:source] = ENV['MM_SOURCE'] if ENV['MM_SOURCE']
|
||||
|
||||
# TODO, make this less global
|
||||
::Middleman::FileRenderer.cache.clear
|
||||
::Middleman::TemplateRenderer.cache.clear
|
||||
# TODO, make this less global
|
||||
::Middleman::FileRenderer.cache.clear
|
||||
::Middleman::TemplateRenderer.cache.clear
|
||||
end
|
||||
|
||||
execute_callbacks(:before_extensions)
|
||||
|
||||
@extensions = ::Middleman::ExtensionManager.new(self)
|
||||
|
||||
execute_callbacks(:before_instance_block)
|
||||
|
||||
# Evaluate a passed block if given
|
||||
config_context.instance_exec(&block) if block_given?
|
||||
|
||||
|
|
|
@ -72,13 +72,17 @@ module Middleman
|
|||
Contract ResourceList
|
||||
def prerender_css
|
||||
logger.debug '== Prerendering CSS'
|
||||
css_files = @app.sitemap.resources.select do |resource|
|
||||
resource.ext == '.css'
|
||||
end.each(&method(:output_resource))
|
||||
logger.debug '== Checking for Compass sprites'
|
||||
|
||||
css_files = @app.sitemap.resources
|
||||
.select { |resource| resource.ext == '.css' }
|
||||
.each(&method(:output_resource))
|
||||
|
||||
# Double-check for compass sprites
|
||||
@app.files.find_new_files!
|
||||
@app.sitemap.ensure_resource_list_updated!
|
||||
if @app.files.find_new_files!.length > 0
|
||||
logger.debug '== Checking for Compass sprites'
|
||||
@app.sitemap.ensure_resource_list_updated!
|
||||
end
|
||||
|
||||
css_files
|
||||
end
|
||||
|
||||
|
@ -131,24 +135,26 @@ module Middleman
|
|||
# @return [void]
|
||||
Contract Pathname, Or[String, Pathname] => Any
|
||||
def export_file!(output_file, source)
|
||||
source = write_tempfile(output_file, source.to_s) if source.is_a? String
|
||||
# ::Middleman::Util.instrument "write_file", output_file: output_file do
|
||||
source = write_tempfile(output_file, source.to_s) if source.is_a? String
|
||||
|
||||
method, source_path = if source.is_a? Tempfile
|
||||
[FileUtils.method(:mv), source.path]
|
||||
else
|
||||
[FileUtils.method(:cp), source.to_s]
|
||||
end
|
||||
method, source_path = if source.is_a? Tempfile
|
||||
[::FileUtils.method(:mv), source.path]
|
||||
else
|
||||
[::FileUtils.method(:cp), source.to_s]
|
||||
end
|
||||
|
||||
mode = which_mode(output_file, source_path)
|
||||
mode = which_mode(output_file, source_path)
|
||||
|
||||
if mode == :created || mode == :updated
|
||||
FileUtils.mkdir_p(output_file.dirname)
|
||||
method.call(source_path, output_file.to_s)
|
||||
end
|
||||
if mode == :created || mode == :updated
|
||||
::FileUtils.mkdir_p(output_file.dirname)
|
||||
method.call(source_path, output_file.to_s)
|
||||
end
|
||||
|
||||
source.unlink if source.is_a? Tempfile
|
||||
source.unlink if source.is_a? Tempfile
|
||||
|
||||
trigger(mode, output_file)
|
||||
trigger(mode, output_file)
|
||||
# end
|
||||
end
|
||||
|
||||
# Try to output a resource and capture errors.
|
||||
|
@ -162,7 +168,7 @@ module Middleman
|
|||
if resource.binary?
|
||||
export_file!(output_file, resource.file_descriptor[:full_path])
|
||||
else
|
||||
response = @rack.get(URI.escape(resource.request_path))
|
||||
response = @rack.get(::URI.escape(resource.request_path))
|
||||
|
||||
# If we get a response, save it to a tempfile.
|
||||
if response.status == 200
|
||||
|
|
|
@ -48,8 +48,15 @@ module Middleman
|
|||
|
||||
Contract Or[Symbol, ArrayOf[Symbol]], Maybe[ArrayOf[Any]], Maybe[RespondTo[:instance_exec]] => Any
|
||||
def execute(keys, args=[], scope=self)
|
||||
callbacks_for(keys).each { |b| scope.instance_exec(*args, &b) }
|
||||
@subscribers.each { |b| scope.instance_exec(keys, args, &b) }
|
||||
callbacks = callbacks_for(keys)
|
||||
callbacks_count = callbacks.length + @subscribers.length
|
||||
|
||||
return if callbacks_count < 1
|
||||
|
||||
# ::Middleman::Util.instrument "callbacks.execute", keys: keys, length: callbacks_count do
|
||||
callbacks.each { |b| scope.instance_exec(*args, &b) }
|
||||
@subscribers.each { |b| scope.instance_exec(keys, args, &b) }
|
||||
# end
|
||||
end
|
||||
|
||||
Contract Or[Symbol, ArrayOf[Symbol]] => ::Hamster::Vector
|
||||
|
|
|
@ -19,6 +19,12 @@ Middleman::Extensions.register :data, auto_activate: :before_sitemap do
|
|||
Middleman::CoreExtensions::Data
|
||||
end
|
||||
|
||||
# Rewrite embedded URLs via Rack
|
||||
Middleman::Extensions.register :inline_url_rewriter, auto_activate: :before_sitemap do
|
||||
require 'middleman-core/core_extensions/inline_url_rewriter'
|
||||
Middleman::CoreExtensions::InlineURLRewriter
|
||||
end
|
||||
|
||||
# Catch and show exceptions at the Rack level
|
||||
Middleman::Extensions.register :show_exceptions, auto_activate: :before_configuration, modes: [:server] do
|
||||
require 'middleman-core/core_extensions/show_exceptions'
|
||||
|
|
|
@ -30,6 +30,7 @@ module Middleman::CoreExtensions
|
|||
resources.each do |resource|
|
||||
next if resource.ignored?
|
||||
next if resource.file_descriptor.nil?
|
||||
next unless resource.template?
|
||||
|
||||
fmdata = data(resource.file_descriptor[:full_path].to_s).first.dup
|
||||
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
require 'rack'
|
||||
require 'rack/response'
|
||||
require 'addressable/uri'
|
||||
require 'middleman-core/util'
|
||||
require 'middleman-core/contracts'
|
||||
|
||||
module Middleman
|
||||
module CoreExtensions
|
||||
|
||||
class InlineURLRewriter < ::Middleman::Extension
|
||||
include Contracts
|
||||
|
||||
expose_to_application rewrite_inline_urls: :add
|
||||
|
||||
IGNORE_DESCRIPTOR = Or[Regexp, RespondTo[:call], String]
|
||||
REWRITER_DESCRIPTOR = {
|
||||
id: Symbol,
|
||||
proc: Or[Proc, Method],
|
||||
url_extensions: ArrayOf[String],
|
||||
source_extensions: ArrayOf[String],
|
||||
ignore: ArrayOf[IGNORE_DESCRIPTOR]
|
||||
}
|
||||
|
||||
def initialize(app, options_hash={}, &block)
|
||||
super
|
||||
|
||||
@rewriters = {}
|
||||
end
|
||||
|
||||
Contract REWRITER_DESCRIPTOR => Any
|
||||
def add(options)
|
||||
@rewriters[options] = options
|
||||
end
|
||||
|
||||
def after_configuration
|
||||
app.use Rack, {
|
||||
rewriters: @rewriters.values,
|
||||
middleman_app: @app
|
||||
}
|
||||
end
|
||||
|
||||
class Rack
|
||||
include Contracts
|
||||
|
||||
Contract RespondTo[:call], ({
|
||||
middleman_app: IsA['Middleman::Application'],
|
||||
rewriters: ArrayOf[REWRITER_DESCRIPTOR]
|
||||
}) => Any
|
||||
def initialize(app, options={})
|
||||
@rack_app = app
|
||||
@middleman_app = options.fetch(:middleman_app)
|
||||
@rewriters = options.fetch(:rewriters)
|
||||
end
|
||||
|
||||
def call(env)
|
||||
status, headers, response = @rack_app.call(env)
|
||||
|
||||
# Allow configuration or upstream request to skip all rewriting
|
||||
return [status, headers, response] if env['bypass_inline_url_rewriter'] == 'true'
|
||||
|
||||
all_source_exts = @rewriters
|
||||
.reduce([]) { |sum, rewriter| sum + rewriter[:source_extensions] }
|
||||
.flatten
|
||||
.uniq
|
||||
source_exts_regex_text = Regexp.union(all_source_exts).to_s
|
||||
|
||||
all_asset_exts = @rewriters
|
||||
.reduce([]) { |sum, rewriter| sum + rewriter[:url_extensions] }
|
||||
.flatten
|
||||
.uniq
|
||||
|
||||
path = ::Middleman::Util.full_path(env['PATH_INFO'], @middleman_app)
|
||||
|
||||
return [status, headers, response] unless path =~ /(^\/$)|(#{source_exts_regex_text}$)/
|
||||
return [status, headers, response] unless body = ::Middleman::Util.extract_response_text(response)
|
||||
|
||||
dirpath = ::Pathname.new(File.dirname(path))
|
||||
|
||||
rewritten = nil
|
||||
|
||||
# ::Middleman::Util.instrument "inline_url_rewriter", path: path do
|
||||
rewritten = ::Middleman::Util.rewrite_paths(body, path, all_asset_exts) do |asset_path|
|
||||
uri = ::Addressable::URI.parse(asset_path)
|
||||
|
||||
relative_path = uri.host.nil?
|
||||
|
||||
full_asset_path = if relative_path
|
||||
dirpath.join(asset_path).to_s
|
||||
else
|
||||
asset_path
|
||||
end
|
||||
|
||||
@rewriters.each do |rewriter|
|
||||
uid = rewriter.fetch(:id)
|
||||
|
||||
# Allow upstream request to skip this specific rewriting
|
||||
next if env["bypass_inline_url_rewriter_#{uid}"] == 'true'
|
||||
|
||||
exts = rewriter.fetch(:url_extensions)
|
||||
next unless exts.include?(::File.extname(asset_path))
|
||||
|
||||
source_exts = rewriter.fetch(:source_extensions)
|
||||
next unless source_exts.include?(::File.extname(path))
|
||||
|
||||
ignore = rewriter.fetch(:ignore)
|
||||
next if ignore.any? { |r| should_ignore?(r, full_asset_path) }
|
||||
|
||||
rewrite_ignore = Array(rewriter.fetch(:rewrite_ignore, []))
|
||||
next if rewrite_ignore.any? { |ignore| ::Middleman::Util.path_match(ignore, path) }
|
||||
|
||||
proc = rewriter.fetch(:proc)
|
||||
|
||||
result = proc.call(asset_path, dirpath, path)
|
||||
asset_path = result if result
|
||||
end
|
||||
|
||||
asset_path
|
||||
# end
|
||||
end
|
||||
|
||||
::Rack::Response.new(
|
||||
rewritten,
|
||||
status,
|
||||
headers
|
||||
).finish
|
||||
end
|
||||
|
||||
Contract IGNORE_DESCRIPTOR, String => Bool
|
||||
def should_ignore?(validator, value)
|
||||
if validator.is_a? Regexp
|
||||
# Treat as Regexp
|
||||
!value.match(validator).nil?
|
||||
elsif validator.respond_to? :call
|
||||
# Treat as proc
|
||||
validator.call(value)
|
||||
elsif validator.is_a? String
|
||||
# Treat as glob
|
||||
File.fnmatch(value, validator)
|
||||
else
|
||||
# If some unknown thing, don't ignore
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,8 +1,8 @@
|
|||
require 'addressable/uri'
|
||||
require 'middleman-core/util'
|
||||
require 'middleman-core/rack'
|
||||
|
||||
class Middleman::Extensions::AssetHash < ::Middleman::Extension
|
||||
option :sources, %w(.htm .html .php .css .js), 'List of extensions that are searched for hashable assets.'
|
||||
option :exts, %w(.jpg .jpeg .png .gif .webp .js .css .otf .woff .woff2 .eot .ttf .svg .svgz), 'List of extensions that get asset hashes appended to them.'
|
||||
option :ignore, [], 'Regexes of filenames to skip adding asset hashes to'
|
||||
option :rewrite_ignore, [], 'Regexes of filenames to skip processing for path rewrites'
|
||||
|
@ -10,23 +10,19 @@ class Middleman::Extensions::AssetHash < ::Middleman::Extension
|
|||
def initialize(app, options_hash={}, &block)
|
||||
super
|
||||
|
||||
require 'addressable/uri'
|
||||
require 'digest/sha1'
|
||||
require 'rack/mock'
|
||||
require 'middleman-core/middleware/inline_url_rewriter'
|
||||
end
|
||||
|
||||
def after_configuration
|
||||
# Allow specifying regexes to ignore, plus always ignore apple touch icons
|
||||
@ignore = Array(options.ignore) + [/^apple-touch-icon/]
|
||||
|
||||
app.use ::Middleman::Middleware::InlineURLRewriter,
|
||||
id: :asset_hash,
|
||||
url_extensions: options.exts.sort.reverse,
|
||||
source_extensions: %w(.htm .html .php .css .js),
|
||||
ignore: @ignore,
|
||||
rewrite_ignore: options.rewrite_ignore,
|
||||
middleman_app: app,
|
||||
proc: method(:rewrite_url)
|
||||
app.rewrite_inline_urls id: :asset_hash,
|
||||
url_extensions: options.exts.sort.reverse,
|
||||
source_extensions: options.sources,
|
||||
ignore: @ignore,
|
||||
rewrite_ignore: options.rewrite_ignore,
|
||||
proc: method(:rewrite_url)
|
||||
end
|
||||
|
||||
Contract String, Or[String, Pathname], Any => Maybe[String]
|
||||
|
@ -77,15 +73,19 @@ class Middleman::Extensions::AssetHash < ::Middleman::Extension
|
|||
return if ignored_resource?(resource)
|
||||
return if resource.ignored?
|
||||
|
||||
# Render through the Rack interface so middleware and mounted apps get a shot
|
||||
response = @rack_client.get(
|
||||
URI.escape(resource.destination_path),
|
||||
'bypass_inline_url_rewriter_asset_hash' => 'true'
|
||||
)
|
||||
digest = if resource.template?
|
||||
# Render through the Rack interface so middleware and mounted apps get a shot
|
||||
response = @rack_client.get(
|
||||
::URI.escape(resource.destination_path),
|
||||
'bypass_inline_url_rewriter_asset_hash' => 'true'
|
||||
)
|
||||
|
||||
raise "#{resource.path} should be in the sitemap!" unless response.status == 200
|
||||
raise "#{resource.path} should be in the sitemap!" unless response.status == 200
|
||||
|
||||
digest = Digest::SHA1.hexdigest(response.body)[0..7]
|
||||
::Digest::SHA1.hexdigest(response.body)[0..7]
|
||||
else
|
||||
::Digest::SHA1.file(resource.source_file).hexdigest[0..7]
|
||||
end
|
||||
|
||||
resource.destination_path = resource.destination_path.sub(/\.(\w+)$/) { |ext| "-#{digest}#{ext}" }
|
||||
resource
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
require 'addressable/uri'
|
||||
require 'middleman-core/middleware/inline_url_rewriter'
|
||||
|
||||
class Middleman::Extensions::AssetHost < ::Middleman::Extension
|
||||
option :host, nil, 'The asset host to use or a Proc to determine asset host', required: true
|
||||
|
@ -8,15 +7,15 @@ class Middleman::Extensions::AssetHost < ::Middleman::Extension
|
|||
option :ignore, [], 'Regexes of filenames to skip adding query strings to'
|
||||
option :rewrite_ignore, [], 'Regexes of filenames to skip processing for host rewrites'
|
||||
|
||||
def ready
|
||||
app.use ::Middleman::Middleware::InlineURLRewriter,
|
||||
id: :asset_host,
|
||||
url_extensions: options.exts,
|
||||
source_extensions: options.sources,
|
||||
ignore: options.ignore,
|
||||
rewrite_ignore: options.rewrite_ignore,
|
||||
middleman_app: app,
|
||||
proc: method(:rewrite_url)
|
||||
def initialize(app, options_hash={}, &block)
|
||||
super
|
||||
|
||||
app.rewrite_inline_urls id: :asset_host,
|
||||
url_extensions: options.exts,
|
||||
source_extensions: options.sources,
|
||||
ignore: options.ignore,
|
||||
rewrite_ignore: options.rewrite_ignore,
|
||||
proc: method(:rewrite_url)
|
||||
end
|
||||
|
||||
Contract String, Or[String, Pathname], Any => String
|
||||
|
|
|
@ -8,18 +8,12 @@ class Middleman::Extensions::CacheBuster < ::Middleman::Extension
|
|||
def initialize(app, options_hash={}, &block)
|
||||
super
|
||||
|
||||
require 'middleman-core/middleware/inline_url_rewriter'
|
||||
end
|
||||
|
||||
def after_configuration
|
||||
app.use ::Middleman::Middleware::InlineURLRewriter,
|
||||
id: :cache_buster,
|
||||
url_extensions: options.exts,
|
||||
source_extensions: options.sources,
|
||||
ignore: options.ignore,
|
||||
rewrite_ignore: options.rewrite_ignore,
|
||||
middleman_app: app,
|
||||
proc: method(:rewrite_url)
|
||||
app.rewrite_inline_urls id: :cache_buster,
|
||||
url_extensions: options.exts,
|
||||
source_extensions: options.sources,
|
||||
ignore: options.ignore,
|
||||
rewrite_ignore: options.rewrite_ignore,
|
||||
proc: method(:rewrite_url)
|
||||
end
|
||||
|
||||
Contract String, Or[String, Pathname], Any => String
|
||||
|
|
|
@ -10,18 +10,12 @@ class Middleman::Extensions::RelativeAssets < ::Middleman::Extension
|
|||
def initialize(app, options_hash={}, &block)
|
||||
super
|
||||
|
||||
require 'middleman-core/middleware/inline_url_rewriter'
|
||||
end
|
||||
|
||||
def ready
|
||||
app.use ::Middleman::Middleware::InlineURLRewriter,
|
||||
id: :asset_hash,
|
||||
url_extensions: options.exts,
|
||||
source_extensions: options.sources,
|
||||
ignore: options.ignore,
|
||||
rewrite_ignore: options.rewrite_ignore,
|
||||
middleman_app: app,
|
||||
proc: method(:rewrite_url)
|
||||
app.rewrite_inline_urls id: :asset_hash,
|
||||
url_extensions: options.exts,
|
||||
source_extensions: options.sources,
|
||||
ignore: options.ignore,
|
||||
rewrite_ignore: options.rewrite_ignore,
|
||||
proc: method(:rewrite_url)
|
||||
end
|
||||
|
||||
helpers do
|
||||
|
|
|
@ -73,9 +73,11 @@ module Middleman
|
|||
# end
|
||||
|
||||
# Render using Tilt
|
||||
content = ::Middleman::Util.instrument 'render.tilt', path: path do
|
||||
template.render(context, locs, &block)
|
||||
end
|
||||
content = nil
|
||||
|
||||
# ::Middleman::Util.instrument 'render.tilt', path: path do
|
||||
content = template.render(context, locs, &block)
|
||||
# end
|
||||
|
||||
# Allow hooks to manipulate the result after render
|
||||
content = @app.callbacks_for(:after_render).reduce(content) do |sum, callback|
|
||||
|
|
|
@ -1,109 +0,0 @@
|
|||
require 'rack'
|
||||
require 'rack/response'
|
||||
require 'addressable/uri'
|
||||
require 'middleman-core/util'
|
||||
require 'middleman-core/contracts'
|
||||
|
||||
module Middleman
|
||||
module Middleware
|
||||
class InlineURLRewriter
|
||||
include Contracts
|
||||
|
||||
IGNORE_DESCRIPTOR = Or[Regexp, RespondTo[:call], String]
|
||||
|
||||
Contract RespondTo[:call], ({
|
||||
middleman_app: IsA['Middleman::Application'],
|
||||
id: Maybe[Symbol],
|
||||
proc: Or[Proc, Method],
|
||||
url_extensions: ArrayOf[String],
|
||||
source_extensions: ArrayOf[String],
|
||||
ignore: ArrayOf[IGNORE_DESCRIPTOR]
|
||||
}) => Any
|
||||
def initialize(app, options={})
|
||||
@rack_app = app
|
||||
@middleman_app = options.fetch(:middleman_app)
|
||||
|
||||
@uid = options.fetch(:id, nil)
|
||||
@proc = options.fetch(:proc)
|
||||
|
||||
raise 'InlineURLRewriter requires a :proc to call with inline URL results' unless @proc
|
||||
|
||||
@exts = options.fetch(:url_extensions)
|
||||
|
||||
@source_exts = options.fetch(:source_extensions)
|
||||
@source_exts_regex_text = Regexp.union(@source_exts).to_s
|
||||
|
||||
@ignore = options.fetch(:ignore)
|
||||
@rewrite_ignore = Array(options.fetch(:rewrite_ignore, []))
|
||||
end
|
||||
|
||||
def call(env)
|
||||
status, headers, response = @rack_app.call(env)
|
||||
|
||||
# Allow configuration or upstream request to skip all rewriting
|
||||
if rewrite_ignore?(env['PATH_INFO']) || env['bypass_inline_url_rewriter'] == 'true'
|
||||
return [status, headers, response]
|
||||
end
|
||||
|
||||
# Allow upstream request to skip this specific rewriting
|
||||
if @uid
|
||||
uid_key = "bypass_inline_url_rewriter_#{@uid}"
|
||||
return [status, headers, response] if env[uid_key] == 'true'
|
||||
end
|
||||
|
||||
path = ::Middleman::Util.full_path(env['PATH_INFO'], @middleman_app)
|
||||
|
||||
if path =~ /(^\/$)|(#{@source_exts_regex_text}$)/
|
||||
if body = ::Middleman::Util.extract_response_text(response)
|
||||
|
||||
dirpath = Pathname.new(File.dirname(path))
|
||||
|
||||
rewritten = ::Middleman::Util.rewrite_paths(body, path, @exts) do |asset_path|
|
||||
uri = ::Addressable::URI.parse(asset_path)
|
||||
|
||||
relative_path = uri.host.nil?
|
||||
|
||||
full_asset_path = if relative_path
|
||||
dirpath.join(asset_path).to_s
|
||||
else
|
||||
asset_path
|
||||
end
|
||||
|
||||
@ignore.none? { |r| should_ignore?(r, full_asset_path) } && @proc.call(asset_path, dirpath, path)
|
||||
end
|
||||
|
||||
status, headers, response = ::Rack::Response.new(
|
||||
rewritten,
|
||||
status,
|
||||
headers
|
||||
).finish
|
||||
end
|
||||
end
|
||||
|
||||
[status, headers, response]
|
||||
end
|
||||
|
||||
Contract IGNORE_DESCRIPTOR, String => Bool
|
||||
def should_ignore?(validator, value)
|
||||
if validator.is_a? Regexp
|
||||
# Treat as Regexp
|
||||
!value.match(validator).nil?
|
||||
elsif validator.respond_to? :call
|
||||
# Treat as proc
|
||||
validator.call(value)
|
||||
elsif validator.is_a? String
|
||||
# Treat as glob
|
||||
File.fnmatch(value, validator)
|
||||
else
|
||||
# If some unknown thing, don't ignore
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
Contract String => Bool
|
||||
def rewrite_ignore?(path)
|
||||
@rewrite_ignore.any? { |ignore| Middleman::Util.path_match(ignore, path) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -127,9 +127,9 @@ module Middleman
|
|||
# @return [String]
|
||||
Contract Hash, Hash => String
|
||||
def render(opts={}, locs={})
|
||||
return ::Middleman::FileRenderer.new(@app, file_descriptor[:full_path].to_s).template_data_for_file unless template?
|
||||
return File.read(file_descriptor[:full_path].to_s) unless template?
|
||||
|
||||
::Middleman::Util.instrument 'render.resource', path: file_descriptor[:full_path].to_s, destination_path: destination_path do
|
||||
# ::Middleman::Util.instrument 'render.resource', path: file_descriptor[:full_path].to_s, destination_path: destination_path do
|
||||
md = metadata
|
||||
opts = md[:options].deep_merge(opts)
|
||||
locs = md[:locals].deep_merge(locs)
|
||||
|
@ -140,7 +140,7 @@ module Middleman
|
|||
|
||||
renderer = ::Middleman::TemplateRenderer.new(@app, file_descriptor[:full_path].to_s)
|
||||
renderer.render(locs, opts)
|
||||
end
|
||||
# end
|
||||
end
|
||||
|
||||
# A path without the directory index - so foo/index.html becomes
|
||||
|
|
|
@ -75,6 +75,7 @@ module Middleman
|
|||
def initialize(app)
|
||||
@app = app
|
||||
@resources = []
|
||||
@rebuild_reasons = [:first_run]
|
||||
@update_count = 0
|
||||
|
||||
@resource_list_manipulators = ::Hamster::Vector.empty
|
||||
|
@ -115,9 +116,10 @@ module Middleman
|
|||
|
||||
# Rebuild the list of resources from scratch, using registed manipulators
|
||||
# @return [void]
|
||||
Contract Maybe[Symbol] => Any
|
||||
def rebuild_resource_list!(name=nil)
|
||||
Contract Symbol => Any
|
||||
def rebuild_resource_list!(name)
|
||||
@lock.synchronize do
|
||||
@rebuild_reasons << name
|
||||
@app.logger.debug "== Requesting resource list rebuilding: #{name}"
|
||||
@needs_sitemap_rebuild = true
|
||||
end
|
||||
|
@ -198,29 +200,36 @@ module Middleman
|
|||
def ensure_resource_list_updated!
|
||||
@lock.synchronize do
|
||||
return unless @needs_sitemap_rebuild
|
||||
@needs_sitemap_rebuild = false
|
||||
|
||||
@app.logger.debug '== Rebuilding resource list'
|
||||
::Middleman::Util.instrument "sitemap.update", reasons: @rebuild_reasons.uniq do
|
||||
@needs_sitemap_rebuild = false
|
||||
|
||||
@resources = []
|
||||
@app.logger.debug '== Rebuilding resource list'
|
||||
|
||||
@resource_list_manipulators.each do |m|
|
||||
@app.logger.debug "== Running manipulator: #{m[:name]}"
|
||||
@resources = m[:manipulator].send(m[:custom_name] || :manipulate_resource_list, @resources)
|
||||
@resources = []
|
||||
|
||||
# Reset lookup cache
|
||||
reset_lookup_cache!
|
||||
@resource_list_manipulators.each do |m|
|
||||
::Middleman::Util.instrument "sitemap.manipulator", name: m[:name] do
|
||||
@app.logger.debug "== Running manipulator: #{m[:name]}"
|
||||
@resources = m[:manipulator].send(m[:custom_name] || :manipulate_resource_list, @resources)
|
||||
|
||||
# Rebuild cache
|
||||
@resources.each do |resource|
|
||||
@_lookup_by_path[resource.path] = resource
|
||||
@_lookup_by_destination_path[resource.destination_path] = resource
|
||||
# Reset lookup cache
|
||||
reset_lookup_cache!
|
||||
|
||||
# Rebuild cache
|
||||
@resources.each do |resource|
|
||||
@_lookup_by_path[resource.path] = resource
|
||||
@_lookup_by_destination_path[resource.destination_path] = resource
|
||||
end
|
||||
|
||||
invalidate_resources_not_ignored_cache!
|
||||
end
|
||||
end
|
||||
|
||||
invalidate_resources_not_ignored_cache!
|
||||
end
|
||||
@update_count += 1
|
||||
|
||||
@update_count += 1
|
||||
@rebuild_reasons = []
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -213,12 +213,12 @@ module Middleman
|
|||
# Manually poll all watchers for new content.
|
||||
#
|
||||
# @return [void]
|
||||
Contract Any
|
||||
Contract ArrayOf[Pathname]
|
||||
def find_new_files!
|
||||
return unless @update_count != @last_update_count
|
||||
return [] unless @update_count != @last_update_count
|
||||
|
||||
@last_update_count = @update_count
|
||||
watchers.each(&:poll_once!)
|
||||
watchers.reduce([]) { |sum, w| sum + w.poll_once! }
|
||||
end
|
||||
|
||||
# Start up all listeners.
|
||||
|
|
|
@ -180,17 +180,19 @@ module Middleman
|
|||
# Manually trigger update events.
|
||||
#
|
||||
# @return [void]
|
||||
Contract Any
|
||||
Contract ArrayOf[Pathname]
|
||||
def poll_once!
|
||||
updated = ::Middleman::Util.all_files_under(@directory.to_s)
|
||||
removed = @files.keys.reject { |p| updated.include?(p) }
|
||||
|
||||
update(updated, removed)
|
||||
|
||||
return unless @waiting_for_existence && @directory.exist?
|
||||
if @waiting_for_existence && @directory.exist?
|
||||
@waiting_for_existence = false
|
||||
listen!
|
||||
end
|
||||
|
||||
@waiting_for_existence = false
|
||||
listen!
|
||||
updated + removed
|
||||
end
|
||||
|
||||
# Work around this bug: http://bugs.ruby-lang.org/issues/4521
|
||||
|
|
|
@ -4,22 +4,23 @@ require 'capybara/cucumber'
|
|||
|
||||
Given /^a clean server$/ do
|
||||
@initialize_commands = []
|
||||
@activation_commands = []
|
||||
end
|
||||
|
||||
Given /^"([^\"]*)" feature is "([^\"]*)"$/ do |feature, state|
|
||||
@initialize_commands ||= []
|
||||
@activation_commands ||= []
|
||||
|
||||
if state == 'enabled'
|
||||
@initialize_commands << lambda { activate(feature.to_sym) }
|
||||
@activation_commands << lambda { activate(feature.to_sym) }
|
||||
end
|
||||
end
|
||||
|
||||
Given /^"([^\"]*)" feature is "enabled" with "([^\"]*)"$/ do |feature, options_str|
|
||||
@initialize_commands ||= []
|
||||
@activation_commands ||= []
|
||||
|
||||
options = eval("{#{options_str}}")
|
||||
|
||||
@initialize_commands << lambda { activate(feature.to_sym, options) }
|
||||
@activation_commands << lambda { activate(feature.to_sym, options) }
|
||||
end
|
||||
|
||||
Given /^"([^\"]*)" is set to "([^\"]*)"$/ do |variable, value|
|
||||
|
@ -41,6 +42,7 @@ Given /^the Server is running$/ do
|
|||
ENV['MM_ROOT'] = root_dir
|
||||
|
||||
initialize_commands = @initialize_commands || []
|
||||
activation_commands = @activation_commands || []
|
||||
|
||||
@server_inst = ::Middleman::Application.new do
|
||||
config[:watcher_disable] = true
|
||||
|
@ -49,6 +51,12 @@ Given /^the Server is running$/ do
|
|||
initialize_commands.each do |p|
|
||||
instance_exec(&p)
|
||||
end
|
||||
|
||||
app.after_configuration_eval do
|
||||
activation_commands.each do |p|
|
||||
config_context.instance_exec(&p)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Capybara.app = ::Middleman::Rack.new(@server_inst).to_app
|
||||
|
|
|
@ -332,7 +332,7 @@ module Middleman
|
|||
end
|
||||
|
||||
Contract String, String, ArrayOf[String], Proc => String
|
||||
def rewrite_paths(body, _path, exts, &_block)
|
||||
def rewrite_paths(body, _path, exts, &block)
|
||||
matcher = /([=\'\"\(,]\s*)([^\s\'\"\)>]+(#{Regexp.union(exts)}))/
|
||||
|
||||
url_fn_prefix = 'url('
|
||||
|
@ -349,7 +349,7 @@ module Middleman
|
|||
begin
|
||||
uri = ::Addressable::URI.parse(asset_path)
|
||||
|
||||
if uri.relative? && uri.host.nil? && (result = yield(asset_path))
|
||||
if uri.relative? && uri.host.nil? && (result = block.call(asset_path))
|
||||
"#{opening_character}#{result}"
|
||||
else
|
||||
match
|
||||
|
|
|
@ -17,7 +17,7 @@ module Middleman
|
|||
# @return [Array<Hash, String>]
|
||||
Contract Pathname, Maybe[Symbol] => [Hash, Maybe[String]]
|
||||
def parse(full_path, frontmatter_delims, known_type=nil)
|
||||
return [{}, nil] if Middleman::Util.binary?(full_path)
|
||||
return [{}, nil] if ::Middleman::Util.binary?(full_path)
|
||||
|
||||
# Avoid weird race condition when a file is renamed
|
||||
begin
|
||||
|
@ -74,8 +74,8 @@ module Middleman
|
|||
# @return [Hash]
|
||||
Contract String, Pathname, Bool => Hash
|
||||
def parse_yaml(content, full_path)
|
||||
symbolize_recursive(YAML.load(content) || {})
|
||||
rescue StandardError, Psych::SyntaxError => error
|
||||
symbolize_recursive(::YAML.load(content) || {})
|
||||
rescue StandardError, ::Psych::SyntaxError => error
|
||||
warn "YAML Exception parsing #{full_path}: #{error.message}"
|
||||
{}
|
||||
end
|
||||
|
@ -85,7 +85,7 @@ module Middleman
|
|||
# @return [Hash]
|
||||
Contract String, Pathname => Hash
|
||||
def parse_json(content, full_path)
|
||||
symbolize_recursive(JSON.parse(content) || {})
|
||||
symbolize_recursive(::JSON.parse(content) || {})
|
||||
rescue StandardError => error
|
||||
warn "JSON Exception parsing #{full_path}: #{error.message}"
|
||||
{}
|
||||
|
|
Loading…
Reference in a new issue