DEV: Remove vendored babel and update config for plugins/themes (#17832)

The new plugin list is based on the ones currently used in our ember-cli pipeline, and are based on our official browser support policy.

This commit includes an update to the raw-handlebars compiler to remove the 'very hacky but lets us use ES6' code. It's  served us well for the last 6 years, but the babel config changes broke it (`const` -> `let`). This commit takes the opportunity to refactor it to take a similar approach to PrettyText, by leaning on `mini-loader.js`.
This commit is contained in:
David Taylor 2022-08-09 11:53:24 +01:00 committed by GitHub
parent 169f2ad443
commit 7f9c2c0bfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 70 additions and 49 deletions

View File

@ -17,6 +17,7 @@
},
"dependencies": {
"@babel/core": "^7.18.5",
"@babel/standalone": "^7.18.12",
"@discourse/itsatrap": "^2.0.10",
"@ember/jquery": "^2.0.0",
"@ember/optional-features": "^2.0.0",

View File

@ -957,6 +957,11 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/standalone@^7.18.12":
version "7.18.12"
resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.18.12.tgz#4c0abdf1b5213394e73a0ba5500dcc287194a20d"
integrity sha512-wDh3K5IUJiSMAY0MLYBFoCaj2RCZwvDz5BHn2uHat9KOsGWEVDFgFQFIOO+81Js2phFKNppLC45iOCsZVfJniw==
"@babel/template@^7.16.7", "@babel/template@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31"

View File

@ -4,6 +4,25 @@ require 'mini_racer'
class DiscourseJsProcessor
DISCOURSE_COMMON_BABEL_PLUGINS = [
'proposal-optional-chaining',
['proposal-decorators', { legacy: true } ],
'transform-template-literals',
'proposal-class-properties',
'proposal-class-static-block',
'proposal-private-property-in-object',
'proposal-private-methods',
'proposal-numeric-separator',
'proposal-logical-assignment-operators',
'proposal-nullish-coalescing-operator',
'proposal-json-strings',
'proposal-optional-catch-binding',
'transform-parameters',
'proposal-async-generator-functions',
'proposal-object-rest-spread',
'proposal-export-namespace-from',
]
def self.plugin_transpile_paths
@@plugin_transpile_paths ||= Set.new
end
@ -94,9 +113,10 @@ class DiscourseJsProcessor
def self.create_new_context
# timeout any eval that takes longer than 15 seconds
ctx = MiniRacer::Context.new(timeout: 15000, ensure_gc_after_idle: 2000)
ctx.eval("var self = this; #{File.read("#{Rails.root}/vendor/assets/javascripts/babel.js")}")
ctx.eval("#{File.read("#{Rails.root}/app/assets/javascripts/node_modules/@babel/standalone/babel.js")}")
ctx.eval(File.read(Ember::Source.bundled_path_for('ember-template-compiler.js')))
ctx.eval("module = {}; exports = {};")
ctx.eval("const DISCOURSE_COMMON_BABEL_PLUGINS = #{DISCOURSE_COMMON_BABEL_PLUGINS.to_json};")
ctx.attach("rails.logger.info", proc { |err| Rails.logger.info(err.to_s) })
ctx.attach("rails.logger.error", proc { |err| Rails.logger.error(err.to_s) })
ctx.eval <<JS
@ -156,9 +176,34 @@ JS
if opts[:module_name] && !@skip_module
filename = opts[:filename] || 'unknown'
"Babel.transform(#{js_source}, { moduleId: '#{opts[:module_name]}', filename: '#{filename}', ast: false, presets: ['es2015'], plugins: [['transform-modules-amd', {noInterop: true}], 'proposal-object-rest-spread', 'proposal-optional-chaining', ['proposal-decorators', {legacy: true} ], 'proposal-class-properties', exports.WidgetHbsCompiler] }).code"
<<~JS
Babel.transform(
#{js_source},
{
moduleId: '#{opts[:module_name]}',
filename: '#{filename}',
ast: false,
plugins: [
exports.WidgetHbsCompiler,
['transform-modules-amd', {noInterop: true}],
...DISCOURSE_COMMON_BABEL_PLUGINS
]
}
).code
JS
else
"Babel.transform(#{js_source}, { ast: false, plugins: ['proposal-json-strings', 'proposal-nullish-coalescing-operator', 'proposal-logical-assignment-operators', 'proposal-numeric-separator', 'proposal-optional-catch-binding', 'transform-dotall-regex', 'proposal-unicode-property-regex', 'transform-named-capturing-groups-regex', 'proposal-object-rest-spread', 'proposal-optional-chaining', 'transform-arrow-functions', 'transform-block-scoped-functions', 'transform-block-scoping', 'transform-computed-properties', 'transform-destructuring', 'transform-duplicate-keys', 'transform-for-of', 'transform-function-name', 'transform-literals', 'transform-object-super', 'transform-parameters', 'transform-shorthand-properties', 'transform-spread', 'transform-sticky-regex', 'transform-template-literals', 'transform-typeof-symbol', 'transform-unicode-regex', ['proposal-decorators', {legacy: true}], 'proposal-class-properties', exports.WidgetHbsCompiler] }).code"
<<~JS
Babel.transform(
#{js_source},
{
ast: false,
plugins: [
exports.WidgetHbsCompiler,
...DISCOURSE_COMMON_BABEL_PLUGINS
]
}
).code
JS
end
end

View File

@ -10,20 +10,20 @@ class Barber::Precompiler
def precompiler
if !@precompiler
loader = File.read("#{Rails.root}/app/assets/javascripts/mini-loader.js")
source = File.read("#{Rails.root}/app/assets/javascripts/discourse-common/addon/lib/raw-handlebars.js")
transpiler = DiscourseJsProcessor::Transpiler.new(skip_module: true)
transpiled = transpiler.perform(source)
# very hacky but lets us use ES6. I'm ashamed of this code -RW
transpiled = transpiled[transpiled.index('var RawHandlebars = ')...transpiled.index('export ')]
transpiled = DiscourseJsProcessor.transpile(source, "#{Rails.root}/app/assets/javascripts/", "discourse-common/lib/raw-handlebars")
@precompiler = StringIO.new <<~JS
var __RawHandlebars;
(function() {
#{transpiled};
__RawHandlebars = RawHandlebars;
})();
let __RawHandlebars;
(function(){
#{loader}
define("handlebars", ["exports"], function(exports){ exports.default = Handlebars; })
#{transpiled}
__RawHandlebars = require("discourse-common/lib/raw-handlebars").default;
})()
Barber = {
precompile: function(string) {
@ -31,6 +31,7 @@ class Barber::Precompiler
}
};
JS
end
@precompiler

View File

@ -197,7 +197,7 @@ HTML
expect(theme.javascript_cache.content).to include('addRawTemplate("discovery"')
expect(theme.javascript_cache.content).to include("define(\"discourse/theme-#{theme.id}/controllers/discovery\"")
expect(theme.javascript_cache.content).to include("define(\"discourse/theme-#{theme.id}/controllers/discovery-2\"")
expect(theme.javascript_cache.content).to include("var settings =")
expect(theme.javascript_cache.content).to include("const settings =")
end
def create_upload_theme_field!(name)

View File

@ -248,22 +248,8 @@ HTML
)
expect(javascript_cache.content).to include("name: \"theme-field-#{field.id}-mobile-html-script-1\",")
expect(javascript_cache.content).to include("after: \"inject-objects\",")
expect(javascript_cache.content).to include("(0, _pluginApi.withPluginApi)(\"0.1\", function (api) {")
expect(javascript_cache.content).to include("var x = 1;")
end
it "replaces const writes with _readOnlyError function call" do
html = <<HTML
<script type='text/discourse-plugin' version='0.1'>
const x = 1;
x = 2;
</script>
HTML
baked, javascript_cache = transpile(html)
expect(baked).to include(javascript_cache.url)
expect(javascript_cache.content).to include('var x = 1;')
expect(javascript_cache.content).to include('2, _readOnlyError("x");')
expect(javascript_cache.content).to include("(0, _pluginApi.withPluginApi)(\"0.1\", api =>")
expect(javascript_cache.content).to include("const x = 1;")
end
end
@ -369,9 +355,9 @@ HTML
)
expect(theme_field.javascript_cache.content).to include("name: \"theme-field-#{theme_field.id}-common-html-script-1\",")
expect(theme_field.javascript_cache.content).to include("after: \"inject-objects\",")
expect(theme_field.javascript_cache.content).to include("(0, _pluginApi.withPluginApi)(\"1.0\", function (api)")
expect(theme_field.javascript_cache.content).to include("(0, _pluginApi.withPluginApi)(\"1.0\", api =>")
expect(theme_field.javascript_cache.content).to include("alert(settings.name)")
expect(theme_field.javascript_cache.content).to include("var a = function a() {}")
expect(theme_field.javascript_cache.content).to include("let a = () => {}")
setting = theme.settings.find { |s| s.name == :name }
setting.value = 'bill'

File diff suppressed because one or more lines are too long