lib/roda/plugins/assets.rb in roda-3.41.0 vs lib/roda/plugins/assets.rb in roda-3.42.0

- old
+ new

@@ -374,11 +374,11 @@ s.empty? ? s : (s + '/').freeze end if opts[:precompiled] && !opts[:compiled] && ::File.exist?(opts[:precompiled]) require 'json' - opts[:compiled] = (app.opts[:json_parser] || ::JSON.method(:parse)).call(::File.read(opts[:precompiled])) + opts[:compiled] = app.send(:_precompiled_asset_metadata, opts[:precompiled]) end if opts[:early_hints] app.plugin :early_hints end @@ -453,31 +453,38 @@ # compile assets for the given asset group. def compile_assets(type=nil) require 'fileutils' unless assets_opts[:compiled] - opts[:assets] = assets_opts.merge(:compiled => {}) + opts[:assets] = assets_opts.merge(:compiled => _compiled_assets_initial_hash).freeze end if type == nil _compile_assets(:css) _compile_assets(:js) else _compile_assets(type) end - if assets_opts[:precompiled] + if precompile_file = assets_opts[:precompiled] require 'json' - ::FileUtils.mkdir_p(File.dirname(assets_opts[:precompiled])) - ::File.open(assets_opts[:precompiled], 'wb'){|f| f.write((opts[:json_serializer] || :to_json.to_proc).call(assets_opts[:compiled]))} + ::FileUtils.mkdir_p(File.dirname(precompile_file)) + tmp_file = "#{precompile_file}.tmp" + ::File.open(tmp_file, 'wb'){|f| f.write((opts[:json_serializer] || :to_json.to_proc).call(assets_opts[:compiled]))} + ::File.rename(tmp_file, precompile_file) end assets_opts[:compiled] end private + # The initial hash to use to store compiled asset metadata. + def _compiled_assets_initial_hash + {} + end + # Internals of compile_assets, handling recursive calls for loading # all asset groups under the given type. def _compile_assets(type) type, *dirs = type if type.is_a?(Array) dirs ||= [] @@ -491,10 +498,15 @@ files = Array(files) compile_assets_files(files, type, dirs) unless files.empty? end end + # The precompiled asset metadata stored in the given file + def _precompiled_asset_metadata(file) + (opts[:json_parser] || ::JSON.method(:parse)).call(::File.read(file)) + end + # Compile each array of files for the given type into a single # file. Dirs should be an array of asset group names, if these # are files in an asset group. def compile_assets_files(files, type, dirs) dirs = nil if dirs && dirs.empty? @@ -792,26 +804,35 @@ module RequestClassMethods # An array of asset type strings and regexps for that type, for all asset types # handled. def assets_matchers @assets_matchers ||= [:css, :js].map do |t| - [t, assets_regexp(t)].freeze if roda_class.assets_opts[t] + if regexp = assets_regexp(t) + [t, regexp].freeze + end end.compact.freeze end private + # A string for the asset filename for the asset type, key, and digest. + def _asset_regexp(type, key, digest) + "#{key.sub(/\A#{type}/, '')}.#{digest}.#{type}" + end + # The regexp matcher to use for the given type. This handles any asset groups # for the asset types. def assets_regexp(type) o = roda_class.assets_opts if compiled = o[:compiled] - assets = compiled.select{|k,_| k =~ /\A#{type}/}.map do |k, md| - "#{k.sub(/\A#{type}/, '')}.#{md}.#{type}" - end + assets = compiled. + select{|k,_| k =~ /\A#{type}/}. + map{|k, md| _asset_regexp(type, k, md)} + return if assets.empty? /#{o[:"compiled_#{type}_prefix"]}(#{Regexp.union(assets)})/ else - assets = unnest_assets_hash(o[type]) + return unless assets = o[type] + assets = unnest_assets_hash(assets) ts = o[:timestamp_paths] /#{o[:"#{type}_prefix"]}#{"\\d+#{ts}" if ts}(#{Regexp.union(assets.uniq)})#{o[:"#{type}_suffix"]}/ end end