0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-05 12:50:27 +08:00
discourse/app/controllers/stylesheets_controller.rb
David Taylor 4cee62dbd5
PERF: Only recompile stylesheets when required (#41735)
When precompiling stylesheets, we were forcibly recompiling, even if we
already had the correct stylesheet in the cache. This commit updates the
precompile job so that it tries to pull an already-compiled copy from
the database and cache it on disk, rather than doing a full recompile.
2026-07-16 12:14:28 +01:00

100 lines
2.6 KiB
Ruby
Vendored

# frozen_string_literal: true
class StylesheetsController < ApplicationController
skip_before_action :preload_json,
:redirect_to_login_if_required,
:redirect_to_profile_if_required,
:check_xhr,
:verify_authenticity_token,
only: %i[show show_source_map color_scheme]
before_action :apply_cdn_headers, only: %i[show show_source_map color_scheme]
def show_source_map
show_resource(source_map: true)
end
def show
is_asset_path
show_resource
end
def color_scheme
params.require("id")
params.permit("theme_id")
theme_id = params[:theme_id]&.to_i
theme_id = nil if theme_id && !guardian.allow_themes?([theme_id])
manager = Stylesheet::Manager.new(theme_id: theme_id)
stylesheet = manager.color_scheme_stylesheet_details(params[:id], fallback_to_base: true)
render json: stylesheet
end
protected
def show_resource(source_map: false)
extension = source_map ? ".css.map" : ".css"
no_cookies
target, digest = params[:name].split(/_([a-f0-9]{40})/)
cache_time = request.env["HTTP_IF_MODIFIED_SINCE"]
if cache_time.present?
begin
cache_time = Time.rfc2822(cache_time)
rescue ArgumentError
end
end
query = StylesheetCache.where(target: target)
if digest
query = query.where(digest: digest)
else
query = query.order("id desc")
end
# Security note, safe due to route constraint
underscore_digest = digest ? "_" + digest : ""
cache_path = Stylesheet::Manager.cache_fullpath
location = "#{cache_path}/#{target}#{underscore_digest}#{extension}"
stylesheet_time = query.pick(:created_at)
handle_missing_cache(location, target, digest) if !stylesheet_time
if cache_time.present? && stylesheet_time && stylesheet_time <= cache_time
return head :not_modified
end
raise Discourse::NotFound if !StylesheetCache.write_to_disk(query, location, source_map:)
response.headers["Last-Modified"] = stylesheet_time.httpdate if stylesheet_time
immutable_for(1.year)
send_file(location, disposition: :inline)
end
def handle_missing_cache(location, name, digest)
location = location.sub(".css.map", ".css")
source_map_location = location + ".map"
existing = read_file(location)
if existing && digest
source_map = read_file(source_map_location)
StylesheetCache.add(name, digest, existing, source_map)
end
end
private
def read_file(location)
File.read(location)
rescue Errno::ENOENT
end
end