mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
DEV: remove markdown-it-bundle and custom build code (#23859)
With Embroider, we can rely on async `import()` to do the splitting for us. This commit extracts from `pretty-text` all the parts that are meant to be loaded async into a new `discourse-markdown-it` package that is also a V2 addon (meaning that all files are presumed unused until they are imported, aka "static"). Mostly I tried to keep the very discourse specific stuff (accessing site settings and loading plugin features) inside discourse proper, while the new package aims to have some resembalance of a general purpose library, a MarkdownIt++ if you will. It is far from perfect because of how all the "options" stuff work but I think it's a good start for more refactorings (clearing up the interfaces) to happen later. With this, pretty-text and app/lib/text are mostly a kitchen sink of loosely related text processing utilities. After the refactor, a lot more code related to setting up the engine are now loaded lazily, which should be a pretty nice win. I also noticed that we are currently pulling in the `xss` library at initial load to power the "sanitize" stuff, but I suspect with a similar refactoring effort those usages can be removed too. (See also #23790). This PR does not attempt to fix the sanitize issue, but I think it sets things up on the right trajectory for that to happen later. Co-authored-by: David Taylor <david@taylorhq.com>
This commit is contained in:
@@ -28,50 +28,24 @@ module PrettyText
|
||||
Rails.root
|
||||
end
|
||||
|
||||
def self.find_file(root, filename)
|
||||
return filename if File.file?("#{root}#{filename}")
|
||||
|
||||
es6_name = "#{filename}.js.es6"
|
||||
return es6_name if File.file?("#{root}#{es6_name}")
|
||||
|
||||
js_name = "#{filename}.js"
|
||||
return js_name if File.file?("#{root}#{js_name}")
|
||||
|
||||
erb_name = "#{filename}.js.es6.erb"
|
||||
return erb_name if File.file?("#{root}#{erb_name}")
|
||||
|
||||
erb_name = "#{filename}.js.erb"
|
||||
erb_name if File.file?("#{root}#{erb_name}")
|
||||
def self.apply_es6_file(ctx:, path:, module_name:)
|
||||
source = File.read(path)
|
||||
transpiler = DiscourseJsProcessor::Transpiler.new
|
||||
transpiled = transpiler.perform(source, nil, module_name)
|
||||
ctx.eval(transpiled, filename: module_name)
|
||||
end
|
||||
|
||||
def self.apply_es6_file(ctx, root_path, part_name)
|
||||
filename = find_file(root_path, part_name)
|
||||
if filename
|
||||
source = File.read("#{root_path}#{filename}")
|
||||
source = ERB.new(source).result(binding) if filename =~ /\.erb\z/
|
||||
|
||||
transpiler = DiscourseJsProcessor::Transpiler.new
|
||||
transpiled = transpiler.perform(source, "#{Rails.root}/app/assets/javascripts/", part_name)
|
||||
ctx.eval(transpiled)
|
||||
else
|
||||
# Look for vendored stuff
|
||||
vendor_root = "#{Rails.root}/vendor/assets/javascripts/"
|
||||
filename = find_file(vendor_root, part_name)
|
||||
ctx.eval(File.read("#{vendor_root}#{filename}")) if filename
|
||||
end
|
||||
end
|
||||
|
||||
def self.ctx_load_directory(ctx, path)
|
||||
root_path = "#{Rails.root}/app/assets/javascripts/"
|
||||
Dir["#{root_path}#{path}/**/*"].sort.each do |f|
|
||||
apply_es6_file(ctx, root_path, f.sub(root_path, "").sub(/\.js(.es6)?\z/, ""))
|
||||
def self.ctx_load_directory(ctx:, base_path:, module_prefix:)
|
||||
Dir["**/*.js", base: base_path].sort.each do |f|
|
||||
module_name = "#{module_prefix}#{f.delete_suffix(".js")}"
|
||||
apply_es6_file(ctx: ctx, path: File.join(base_path, f), module_name: module_name)
|
||||
end
|
||||
end
|
||||
|
||||
def self.create_es6_context
|
||||
ctx = MiniRacer::Context.new(timeout: 25_000, ensure_gc_after_idle: 2000)
|
||||
|
||||
ctx.eval("window = {}; window.devicePixelRatio = 2;") # hack to make code think stuff is retina
|
||||
ctx.eval("window = globalThis; window.devicePixelRatio = 2;") # hack to make code think stuff is retina
|
||||
|
||||
ctx.attach("rails.logger.info", proc { |err| Rails.logger.info(err.to_s) })
|
||||
ctx.attach("rails.logger.warn", proc { |err| Rails.logger.warn(err.to_s) })
|
||||
@@ -91,22 +65,40 @@ module PrettyText
|
||||
ctx.attach("__helpers.#{method}", PrettyText::Helpers.method(method))
|
||||
end
|
||||
|
||||
root_path = "#{Rails.root}/app/assets/javascripts/"
|
||||
ctx_load(ctx, "#{root_path}/node_modules/loader.js/dist/loader/loader.js")
|
||||
ctx_load(ctx, "#{root_path}/handlebars-shim.js")
|
||||
ctx_load(ctx, "#{root_path}/node_modules/xss/dist/xss.js")
|
||||
root_path = "#{Rails.root}/app/assets/javascripts"
|
||||
ctx.load("#{root_path}/node_modules/loader.js/dist/loader/loader.js")
|
||||
ctx.load("#{root_path}/node_modules/markdown-it/dist/markdown-it.js")
|
||||
ctx.load("#{root_path}/handlebars-shim.js")
|
||||
ctx.load("#{root_path}/node_modules/xss/dist/xss.js")
|
||||
ctx.load("#{Rails.root}/lib/pretty_text/vendor-shims.js")
|
||||
ctx_load_directory(ctx, "pretty-text/addon")
|
||||
ctx_load_directory(ctx, "pretty-text/engines/discourse-markdown")
|
||||
ctx_load(ctx, "#{root_path}/node_modules/markdown-it/dist/markdown-it.js")
|
||||
|
||||
apply_es6_file(ctx, root_path, "discourse-common/addon/lib/get-url")
|
||||
apply_es6_file(ctx, root_path, "discourse-common/addon/lib/object")
|
||||
apply_es6_file(ctx, root_path, "discourse-common/addon/lib/deprecated")
|
||||
apply_es6_file(ctx, root_path, "discourse-common/addon/lib/escape")
|
||||
apply_es6_file(ctx, root_path, "discourse-common/addon/lib/avatar-utils")
|
||||
apply_es6_file(ctx, root_path, "discourse-common/addon/utils/watched-words")
|
||||
apply_es6_file(ctx, root_path, "discourse/app/lib/to-markdown")
|
||||
ctx_load_directory(
|
||||
ctx: ctx,
|
||||
base_path: "#{root_path}/pretty-text/addon",
|
||||
module_prefix: "pretty-text/",
|
||||
)
|
||||
ctx_load_directory(
|
||||
ctx: ctx,
|
||||
base_path: "#{root_path}/discourse-markdown-it/src",
|
||||
module_prefix: "discourse-markdown-it/",
|
||||
)
|
||||
|
||||
%w[
|
||||
discourse-common/addon/lib/get-url
|
||||
discourse-common/addon/lib/object
|
||||
discourse-common/addon/lib/deprecated
|
||||
discourse-common/addon/lib/escape
|
||||
discourse-common/addon/lib/avatar-utils
|
||||
discourse-common/addon/utils/watched-words
|
||||
discourse/app/lib/to-markdown
|
||||
discourse/app/static/markdown-it/features
|
||||
].each do |f|
|
||||
apply_es6_file(
|
||||
ctx: ctx,
|
||||
path: "#{root_path}/#{f}.js",
|
||||
module_name: f.sub("/addon/", "/").sub("/app/", "/"),
|
||||
)
|
||||
end
|
||||
|
||||
ctx.load("#{Rails.root}/lib/pretty_text/shims.js")
|
||||
ctx.eval("__setUnicode(#{Emoji.unicode_replacements_json})")
|
||||
@@ -116,10 +108,13 @@ module PrettyText
|
||||
to_load << a if File.file?(a) && a =~ /discourse-markdown/
|
||||
end
|
||||
to_load.uniq.each do |f|
|
||||
if f =~ %r{\A.+assets/javascripts/}
|
||||
root = Regexp.last_match[0]
|
||||
apply_es6_file(ctx, root, f.sub(root, "").sub(/\.js(\.es6)?\z/, ""))
|
||||
end
|
||||
plugin_name = f[%r{/plugins/([^/]+)/}, 1]
|
||||
module_name = f[%r{/assets/javascripts/(.+)\.}, 1]
|
||||
apply_es6_file(
|
||||
ctx: ctx,
|
||||
path: f,
|
||||
module_name: "discourse/plugins/#{plugin_name}/#{module_name}",
|
||||
)
|
||||
end
|
||||
|
||||
DiscoursePluginRegistry.vendored_core_pretty_text.each { |vpt| ctx.eval(File.read(vpt)) }
|
||||
@@ -227,8 +222,8 @@ module PrettyText
|
||||
buffer << "__optInput.hashtagTypesInPriorityOrder = [#{hashtag_types_as_js}];\n"
|
||||
buffer << "__optInput.hashtagIcons = #{HashtagAutocompleteService.data_source_icon_map.to_json};\n"
|
||||
|
||||
buffer << "__textOptions = __buildOptions(__optInput);\n"
|
||||
buffer << ("__pt = new __PrettyText(__textOptions);")
|
||||
buffer << "__pluginFeatures = __loadPluginFeatures();"
|
||||
buffer << "__pt = __DiscourseMarkdownIt.withCustomFeatures(__pluginFeatures).withOptions(__optInput);"
|
||||
|
||||
# Be careful disabling sanitization. We allow for custom emails
|
||||
buffer << ("__pt.disableSanitizer();") if opts[:sanitize] == false
|
||||
@@ -666,10 +661,6 @@ module PrettyText
|
||||
rval
|
||||
end
|
||||
|
||||
def self.ctx_load(ctx, *files)
|
||||
files.each { |file| ctx.load(app_root + file) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
USER_TYPE ||= "user"
|
||||
|
||||
Reference in New Issue
Block a user