DEV: Use WebPack stats plugin to map entrypoints to chunks (#24239)

Previously, we were parsing webpack JS chunk filenames from the HTML files which ember-cli generates. This worked ok for simple entrypoints, but falls apart once we start using async imports(), which are not included in the HTML.

This commit uses the stats plugin to generate an assets.json file, and updates Rails to parse it instead of the HTML. Caching on the Rails side is also improved to avoid reading from the filesystem multiple times per request in develoment.

Co-authored-by: Godfrey Chan <godfreykfc@gmail.com>
This commit is contained in:
David Taylor
2023-11-07 10:24:49 +00:00
committed by GitHub
parent 9dd4d97289
commit a0b94dca16
8 changed files with 70 additions and 91 deletions

View File

@ -1,6 +1,9 @@
# frozen_string_literal: true
module EmberCli
class EmberCli < ActiveSupport::CurrentAttributes
# Cache which persists for the duration of a request
attribute :request_cached_script_chunks
def self.dist_dir
"#{Rails.root}/app/assets/javascripts/discourse/dist"
end
@ -10,30 +13,23 @@ module EmberCli
end
def self.script_chunks
return @chunk_infos if @chunk_infos
return @production_chunk_infos if @production_chunk_infos
return self.request_cached_script_chunks if self.request_cached_script_chunks
chunk_infos = {}
chunk_infos = JSON.parse(File.read("#{dist_dir}/assets.json"))
begin
test_html = File.read("#{dist_dir}/tests/index.html")
chunk_infos.merge! parse_chunks_from_html(test_html)
rescue Errno::ENOENT
# production build
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
index_html = File.read("#{dist_dir}/index.html")
chunk_infos.merge! parse_chunks_from_html(index_html)
@chunk_infos = chunk_infos if Rails.env.production?
chunk_infos
@production_chunk_infos = chunk_infos if Rails.env.production?
self.request_cached_script_chunks = chunk_infos
rescue Errno::ENOENT
{}
end
def self.parse_source_map_path(file)
File.read("#{dist_dir}/assets/#{file}")[%r{//# sourceMappingURL=(.*)$}, 1]
end
def self.is_ember_cli_asset?(name)
assets.include?(name) || script_chunks.values.flatten.include?(name.delete_suffix(".js"))
end
@ -56,31 +52,13 @@ module EmberCli
end
end
def self.parse_chunks_from_html(html)
doc = Nokogiri::HTML5.parse(html)
chunk_infos = {}
doc
.css("discourse-chunked-script")
.each do |discourse_script|
entrypoint = discourse_script.attr("entrypoint")
chunk_infos[entrypoint] = discourse_script
.css("script[src]")
.map do |script|
script.attr("src").delete_prefix("#{Discourse.base_path}/assets/").delete_suffix(".js")
end
end
chunk_infos
end
def self.has_tests?
File.exist?("#{dist_dir}/tests/index.html")
end
def self.clear_cache!
@chunk_infos = nil
@prod_chunk_infos = nil
@assets = nil
self.request_cached_script_chunks = nil
end
end