discourse/lib/ember_cli.rb
David Taylor 2dff6d24af
FIX: Ensure ember version in cache key is coupled to compiler (#34694)
During in-container updates, the old version of the application
continues running while an update is applied. That means that it's
possible for the `node_modules/ember-source` version to be different to
the version currently loaded in the transpiler. That means it's
theoretically possible for theme assets to be built with the old
compiler, and then stored against the new version.

This commit removes that race condition by adding an `ember_version`
method to the JS transpiler. This is guaranteed to give us an accurate
version number for the template-compiler currently being used for
themes.

This commit also bumps the BASE_COMPILER_VERSION to force a recompile on
any sites affected by this race condition.
2025-09-02 22:29:02 +01:00

57 lines
1.5 KiB
Ruby

# frozen_string_literal: true
class EmberCli < ActiveSupport::CurrentAttributes
# Cache which persists for the duration of a request
attribute :request_cache
def self.dist_dir
"#{Rails.root}/app/assets/javascripts/discourse/dist"
end
def self.assets
cache[:assets] ||= Dir.glob("**/*.{js,map,txt,css}", base: "#{dist_dir}/assets")
end
def self.script_chunks
return cache[:script_chunks] if cache[:script_chunks]
chunk_infos = JSON.parse(File.read("#{dist_dir}/assets.json"))
chunk_infos.transform_keys! { |key| key.delete_prefix("assets/").delete_suffix(".js") }
chunk_infos.transform_values! do |value|
value["assets"].map { |chunk| chunk.delete_prefix("assets/").delete_suffix(".js") }
end
# Special case - vendor.js is fingerprinted by Embroider in production, but not run through Webpack
if !assets.include?("vendor.js") &&
fingerprinted = assets.find { |a| a.match?(/^vendor\..*\.js$/) }
chunk_infos["vendor"] = [fingerprinted.delete_suffix(".js")]
end
cache[:script_chunks] = chunk_infos
rescue Errno::ENOENT
{}
end
def self.is_ember_cli_asset?(name)
assets.include?(name) || script_chunks.values.flatten.include?(name.delete_suffix(".js"))
end
def self.has_tests?
File.exist?("#{dist_dir}/tests/index.html")
end
def self.cache
if Rails.env.development?
self.request_cache ||= {}
else
@production_cache ||= {}
end
end
def self.clear_cache!
self.request_cache = nil
@production_cache = nil
end
end