class SvelteOnRails::Lib::ViewHelperSupport
def cache_key
def cache_key @cache_key end
def cache_key_primary
def cache_key_primary @cache_key_primary end
def custom_cache_key
def custom_cache_key if @options[:cache_key] k2 = (@options[:cache_key]) keys = k2.is_a?(Array) ? k2 : [k2] keys.map do |k| if k.is_a?(ActiveRecord::Base) "#{k.class.name}#{k.id}" elsif k == nil 'nil' elsif k.present? k.to_s else "empty-#{k.class}" end end.join('-') end end
def debug?
def debug? @options[:debug] end
def debug_log(message)
def debug_log(message) if debug? Rails.logger.debug(" [svelte_component] #{message} (#{elapsed_milliseconds} ms)") end end
def determine_ssr
def determine_ssr _ssr = if @options.key?(:ssr) if @conf.watch_changes? unless [true, false, :auto].include?(@options[:ssr]) raise "Only true, false, or :auto are allowed for the argument #ssr" end end @options[:ssr] else @conf.ssr end _ssr == :auto ? request.headers[conf.non_ssr_request_header].blank? : _ssr end
def elapsed_milliseconds
def elapsed_milliseconds ((Time.now - @start_time) * 1000).round(1) end
def generate_cache_key
def generate_cache_key filename_part = [ "#{filename.split('/').last}.svelte", Zlib.crc32(filename).to_s(36), custom_cache_key ].compact.join('-') @cache_key_primary = [ conf.redis_cache_store[:namespace] ? conf.redis_cache_store[:namespace] : "svelte-on-rails:#{Rails.env rescue 'unknown'}", filename_part, ].join(':') last_part = [ (@conf.watch_changes? ? Zlib.crc32(File.read(@conf.ssr_dist_folder.join('last_mtime'))).to_s(36) : nil), @args_checksum ].compact.join('-') @cache_key = [@cache_key_primary, last_part].join(':') end
def initialize(file, props, html_options, options, request, caching = false)
def initialize(file, props, html_options, options, request, caching = false) @start_time = Time.now @conf = SvelteOnRails::Configuration.instance utils = SvelteOnRails::Lib::Utils utils.validate_filename(file) if @conf.watch_changes? @filename = (file.match(/\.svelte$/) ? file[0..-8] : file) @args_checksum = [ Zlib.crc32(props.to_json).to_s(36), Zlib.crc32(options.to_json).to_s(36) ].join('-') @svelte_props = props ||= {} @options, @html_options = prepare_options( options, html_options, RENDER_OPTIONS ) @request = request @ssr = determine_ssr # precompile if !Dir.exist?(@conf.ssr_dist_folder) || @conf.watch_changes? SvelteOnRails::Lib::Utils.watch_changes_and_precompile end # caching if caching raise '[svelte-on-rails] Caching required but Redis is not defined' unless defined?(Redis) else raise '[svelte-on-rails] :expires_in is not allowed for this helper' if @options.key?(:expires_in) raise '[svelte-on-rails] :cache_key is not allowed for this helper' if @options.key?(:cache_key) return end generate_cache_key end
def log_rendering(message)
def log_rendering(message) Rails.logger.info " #{message} (#{elapsed_milliseconds}ms)" end
def prepare_options(options, html_options, available_options)
def prepare_options(options, html_options, available_options) # html options ht_opts = html_options.dup.deep_merge( { data: { svelte_component: "/#{conf.components_folder + filename}", controller: 'svelte-on-rails' } } ) ht_opts[:class] = "#{ht_opts[:class]} svelte-component".strip ht_opts[:data][:props] = @svelte_props.to_json ht_opts[:data][:svelte_status] = 'do-not-hydrate-me' if options[:hydrate] == false # render options opts = {} options.each do |k, v| _k = k.to_sym if available_options.include?(_k) opts[_k] = v else raise("Unknown option: #{k}") end end [opts, ht_opts] end
def redis_expiration_seconds
def redis_expiration_seconds (conf.redis_cache_store[:expires_in] || @options[:expires_in] || 1.hour).to_i end
def render(view_context, &block)
def render(view_context, &block) debug_log("Rendering component: #{filename}") r = view_context.instance_eval(&block) log_rendering("Rendered #{filename}.svelte #{'as empty element that will be mounted on the client side' unless ssr?}") r end
def render_cached(view_context, &block)
def render_cached(view_context, &block) cached_content = conf.redis_instance.get(cache_key) # debug if debug? debug_log("Rendering component: «#{filename}», cache_key: «#{custom_cache_key}»") debug_log("Redis configuration: #{conf.redis_cache_store}") ttl = conf.redis_instance.ttl(cache_key) key_stat = if cached_content.present? 'has content' elsif conf.redis_instance.exists(cache_key) 'exists but no content' else 'not exists' end ttl_stat = if conf.redis_instance.exists(cache_key) ", ttl was: #{ttl} seconds, now set to: #{redis_expiration_seconds} seconds" end debug_log("Cache key: «#{cache_key}» (#{key_stat}#{ttl_stat})") end # increase expired time conf.redis_instance.expire(cache_key, redis_expiration_seconds) # render log_message = '?' res = if cached_content log_message = "Returned #{filename}.svelte from cache" cached_content.html_safe else log_message = "Rendered #{filename}.svelte and stored to cache" debug_log("cache recalculating for key: #{cache_key}") r = view_context.instance_eval(&block) debug_log("cache recalculated") conf.redis_instance.set(cache_key, r) r end log_rendering(log_message) res end
def render_ssr
def render_ssr renderer = SvelteOnRails::Renderer.new(filename) res = renderer.render(@svelte_props) if res['html'].is_a?(Array) res['html'] = res['html'].join res else res end end
def ssr?
def ssr? @ssr end