DEV: Use esbuild to make DiscourseJsProcessor (#23187)

Co-authored-by: David Taylor <david@taylorhq.com>
This commit is contained in:
Jarek Radosz
2023-08-24 12:43:59 +02:00
committed by GitHub
parent bffdfbd11b
commit 4dfe25d062
12 changed files with 242 additions and 319 deletions

View File

@ -6,6 +6,9 @@ class DiscourseJsProcessor
class TranspileError < StandardError
end
JS_PROCESSOR_PATH =
Rails.env.production? ? "tmp/js-processor.js" : "tmp/js-processor/#{Process.pid}.js"
# To generate a list of babel plugins used by ember-cli, set
# babel: { debug: true } in ember-cli-build.js, then run `yarn ember build -prod`
DISCOURSE_COMMON_BABEL_PLUGINS = [
@ -100,19 +103,29 @@ class DiscourseJsProcessor
class Transpiler
@mutex = Mutex.new
@ctx_init = Mutex.new
@processor_mutex = Mutex.new
def self.mutex
@mutex
end
def self.load_file_in_context(ctx, path, wrap_in_module: nil)
contents = File.read("#{Rails.root}/app/assets/javascripts/#{path}")
contents = <<~JS if wrap_in_module
define(#{wrap_in_module.to_json}, ["exports", "require", "module"], function(exports, require, module){
#{contents}
});
JS
ctx.eval(contents, filename: path)
def self.generate_js_processor
@processor_mutex.synchronize do
if Rails.env.development? || Rails.env.test? ||
!File.exist?("#{Rails.root}/#{JS_PROCESSOR_PATH}")
Discourse::Utils.execute_command(
"yarn",
"--silent",
"esbuild",
"--log-level=warning",
"--bundle",
"--external:fs",
"--define:process='{\"env\":{}}'",
"app/assets/javascripts/js-processor.js",
"--outfile=#{JS_PROCESSOR_PATH}",
)
end
end
end
def self.create_new_context
@ -123,120 +136,10 @@ class DiscourseJsProcessor
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) })
ctx.attach("rails.logger.error", proc { |err| Rails.logger.error(err.to_s) })
ctx.eval(<<~JS, filename: "environment-setup.js")
window = {};
console = {
prefix: "[DiscourseJsProcessor] ",
log: function(...args){ rails.logger.info(console.prefix + args.join(" ")); },
warn: function(...args){ rails.logger.warn(console.prefix + args.join(" ")); },
error: function(...args){ rails.logger.error(console.prefix + args.join(" ")); }
};
JS
# define/require support
load_file_in_context(ctx, "node_modules/loader.js/dist/loader/loader.js")
# Babel
load_file_in_context(ctx, "node_modules/@babel/standalone/babel.js")
ctx.eval <<~JS
globalThis.rawBabelTransform = function(){
return Babel.transform(...arguments).code;
}
JS
# Terser
load_file_in_context(ctx, "node_modules/source-map/dist/source-map.js")
load_file_in_context(ctx, "node_modules/terser/dist/bundle.min.js")
# Template Compiler
load_file_in_context(ctx, "node_modules/ember-source/dist/ember-template-compiler.js")
load_file_in_context(
ctx,
"node_modules/babel-plugin-ember-template-compilation/src/plugin.js",
wrap_in_module: "babel-plugin-ember-template-compilation/index",
)
load_file_in_context(
ctx,
"node_modules/babel-plugin-ember-template-compilation/src/expression-parser.js",
wrap_in_module: "babel-plugin-ember-template-compilation/expression-parser",
)
load_file_in_context(
ctx,
"node_modules/babel-plugin-ember-template-compilation/src/js-utils.js",
wrap_in_module: "babel-plugin-ember-template-compilation/js-utils",
)
load_file_in_context(
ctx,
"node_modules/babel-plugin-ember-template-compilation/src/public-types.js",
wrap_in_module: "babel-plugin-ember-template-compilation/public-types",
)
load_file_in_context(
ctx,
"node_modules/babel-import-util/src/index.js",
wrap_in_module: "babel-import-util",
)
load_file_in_context(
ctx,
"node_modules/ember-cli-htmlbars/lib/colocated-babel-plugin.js",
wrap_in_module: "colocated-babel-plugin",
)
# Widget HBS compiler
widget_hbs_compiler_source =
File.read(
"#{Rails.root}/app/assets/javascripts/discourse-widget-hbs/lib/widget-hbs-compiler.js",
)
widget_hbs_compiler_source = <<~JS
define("widget-hbs-compiler", ["exports"], function(exports){
#{widget_hbs_compiler_source}
});
JS
widget_hbs_compiler_transpiled =
ctx.call(
"rawBabelTransform",
widget_hbs_compiler_source,
{ ast: false, moduleId: "widget-hbs-compiler", plugins: DISCOURSE_COMMON_BABEL_PLUGINS },
)
ctx.eval(widget_hbs_compiler_transpiled, filename: "widget-hbs-compiler.js")
# Raw HBS compiler
load_file_in_context(
ctx,
"node_modules/handlebars/dist/handlebars.js",
wrap_in_module: "handlebars",
)
raw_hbs_transpiled =
ctx.call(
"rawBabelTransform",
File.read(
"#{Rails.root}/app/assets/javascripts/discourse-common/addon/lib/raw-handlebars.js",
),
{
ast: false,
moduleId: "raw-handlebars",
plugins: [
["transform-modules-amd", { noInterop: true }],
*DISCOURSE_COMMON_BABEL_PLUGINS,
],
},
)
ctx.eval(raw_hbs_transpiled, filename: "raw-handlebars.js")
# Theme template AST transformation plugins
load_file_in_context(
ctx,
"discourse-js-processor.js",
wrap_in_module: "discourse-js-processor",
)
# Make interfaces available via `v8.call`
ctx.eval <<~JS
globalThis.compileRawTemplate = require('discourse-js-processor').compileRawTemplate;
globalThis.transpile = require('discourse-js-processor').transpile;
globalThis.minify = require('discourse-js-processor').minify;
globalThis.getMinifyResult = require('discourse-js-processor').getMinifyResult;
JS
generate_js_processor
ctx.eval(File.read(JS_PROCESSOR_PATH), filename: "js-processor.js")
ctx
end