mirror of
https://github.com/discourse/discourse.git
synced 2026-09-05 04:40:41 -05:00
Previously, lib/pretty_text.rb assembled the mini_racer context by transpiling and loading ~50 JS modules one-by-one at boot. This commit replaces that with a single Rolldown-built bundle, precompiled during assets:precompile and cached on disk under a digest of its inputs. This uses a new `PrecompiledBundle` class, which is extracted from `AssetProcessor`. The whole Ruby -> JS interface now goes through mini_racer's `call`, which is significantly faster & safer than the old `.eval` strategy. The plugin interface is maintained by registering modules in `loader.js`. This is a similar compatibility strategy to the one currently being used for frontend code.
68 lines
1.7 KiB
Ruby
68 lines
1.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# A JS bundle built by an external command and cached on disk, keyed by a digest
|
|
# of its inputs. Precompiled during `assets:precompile`; held by composition.
|
|
class PrecompiledBundle
|
|
attr_reader :dependency_globs
|
|
|
|
def initialize(dir:, filename_prefix:, dependency_globs:, &build)
|
|
@dir = dir
|
|
@filename_prefix = filename_prefix
|
|
@dependency_globs = dependency_globs
|
|
@build = build
|
|
end
|
|
|
|
def path
|
|
Rails.root.join(@dir, "#{@filename_prefix}-#{digest}.js")
|
|
end
|
|
|
|
def precompiled?
|
|
File.exist?(path)
|
|
end
|
|
|
|
def load_or_build
|
|
cache_path = path
|
|
return File.read(cache_path) if File.exist?(cache_path)
|
|
|
|
with_lock do
|
|
return File.read(cache_path) if File.exist?(cache_path)
|
|
source = @build.call
|
|
FileUtils.mkdir_p(File.dirname(cache_path))
|
|
Discourse::Utils.atomic_write_file(cache_path, source)
|
|
cleanup_old(cache_path)
|
|
source
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def digest
|
|
digest = Digest::MD5.new
|
|
@dependency_globs.each do |pattern|
|
|
files = Dir.glob(pattern, base: Rails.root).sort
|
|
raise "No files matched #{pattern}" if files.empty?
|
|
|
|
files.each do |file|
|
|
digest.update(file)
|
|
digest.update(File.read(Rails.root.join(file)))
|
|
end
|
|
end
|
|
digest.hexdigest.to_i(16).to_s(36)
|
|
end
|
|
|
|
def with_lock(&block)
|
|
lock_path = Rails.root.join(@dir, "build.lock")
|
|
FileUtils.mkdir_p(File.dirname(lock_path))
|
|
File.open(lock_path, File::CREAT | File::RDWR) do |lock_file|
|
|
lock_file.flock(File::LOCK_EX)
|
|
yield
|
|
end
|
|
end
|
|
|
|
def cleanup_old(keep)
|
|
Dir
|
|
.glob(Rails.root.join(@dir, "#{@filename_prefix}-*.js"))
|
|
.each { |file| File.delete(file) unless file == keep.to_s }
|
|
end
|
|
end
|