DEV: Enable parallel babel processing in ember-cli (#20215)

Ember CLI will automatically run babel transformations in parallel when the config is 'serializable', and can therefore be applied in multiple processes automatically. If any plugin is defined in an unserializable way, parallelisation will be disabled.

Our discourse-widget-hbs transformer was causing parallelisation to be disabled. This commit fixes that, and also enables the throwUnlessParallelizable flag so that we catch this kind of issue more easily in future.

This commit also refactors our deprecation silencing system into its own file, and uses a fake babel plugin to ensure deprecations are silenced in babel worker processes.

In our GitHub CI jobs, this doubles the speed of ember builds (1m30s -> 45s). It should also improve production deploy times, and cold-start dev builds.
This commit is contained in:
David Taylor 2023-02-09 16:24:24 +00:00 committed by GitHub
parent db42917563
commit 25fabccd59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 81 additions and 32 deletions

View File

@ -1,9 +1,6 @@
"use strict";
const WidgetHbsCompiler =
require("../../../../lib/javascripts/widget-hbs-compiler").WidgetHbsCompiler;
const glimmer = require("@glimmer/syntax");
const widgetHbsCompilerPath = require.resolve("./lib/widget-hbs-compiler");
module.exports = {
name: require("./package").name,
@ -15,9 +12,12 @@ module.exports = {
addonOptions.babel.plugins = addonOptions.babel.plugins || [];
let babelPlugins = addonOptions.babel.plugins;
WidgetHbsCompiler.cacheKey = () => "discourse-widget-hbs";
WidgetHbsCompiler.glimmer = glimmer;
babelPlugins.push(WidgetHbsCompiler);
babelPlugins.push({
_parallelBabel: {
requireFile: widgetHbsCompilerPath,
useMethod: "WidgetHbsCompiler",
},
});
},
_getAddonOptions() {

View File

@ -373,4 +373,6 @@ const WidgetHbsCompiler = function (babel) {
};
};
WidgetHbsCompiler.cacheKey = () => "discourse-widget-hbs";
exports.WidgetHbsCompiler = WidgetHbsCompiler;

View File

@ -10,36 +10,16 @@ const { parsePluginClientSettings } = require("./lib/site-settings-plugin");
const discourseScss = require("./lib/discourse-scss");
const generateScriptsTree = require("./lib/scripts");
const funnel = require("broccoli-funnel");
const SILENCED_WARN_PREFIXES = [
"Setting the `jquery-integration` optional feature flag",
"The Ember Classic edition has been deprecated",
"Setting the `template-only-glimmer-components` optional feature flag to `false`",
"DEPRECATION: Invoking the `<LinkTo>` component with positional arguments is deprecated",
];
const DeprecationSilencer = require("./lib/deprecation-silencer");
module.exports = function (defaults) {
let discourseRoot = resolve("../../../..");
let vendorJs = discourseRoot + "/vendor/assets/javascripts/";
// Silence the warnings listed in SILENCED_WARN_PREFIXES
// Silence deprecations which we are aware of - see `lib/deprecation-silencer.js`
const ui = defaults.project.ui;
const oldWriteWarning = ui.writeWarnLine.bind(ui);
ui.writeWarnLine = (message, ...args) => {
if (!SILENCED_WARN_PREFIXES.some((prefix) => message.startsWith(prefix))) {
return oldWriteWarning(message, ...args);
}
};
// Silence warnings which go straight to console.warn (e.g. template compiler deprecations)
/* eslint-disable no-console */
const oldConsoleWarn = console.warn.bind(console);
console.warn = (message, ...args) => {
if (!SILENCED_WARN_PREFIXES.some((prefix) => message.startsWith(prefix))) {
return oldConsoleWarn(message, ...args);
}
};
/* eslint-enable no-console */
DeprecationSilencer.silenceUiWarn(ui);
DeprecationSilencer.silenceConsoleWarn();
const isProduction = EmberApp.env().includes("production");
const isTest = EmberApp.env().includes("test");
@ -111,6 +91,14 @@ module.exports = function (defaults) {
],
},
"ember-cli-babel": {
throwUnlessParallelizable: true,
},
babel: {
plugins: [DeprecationSilencer.generateBabelPlugin()],
},
// We need to build tests in prod for theme tests
tests: true,

View File

@ -0,0 +1,56 @@
const SILENCED_WARN_PREFIXES = [
"Setting the `jquery-integration` optional feature flag",
"The Ember Classic edition has been deprecated",
"Setting the `template-only-glimmer-components` optional feature flag to `false`",
"DEPRECATION: Invoking the `<LinkTo>` component with positional arguments is deprecated",
];
let consoleWarnSilenced = false;
module.exports = class DeprecationSilencer {
static silenceUiWarn(ui) {
const oldWriteWarning = ui.writeWarnLine.bind(ui);
ui.writeWarnLine = (message, ...args) => {
if (
!SILENCED_WARN_PREFIXES.some((prefix) => message.startsWith(prefix))
) {
return oldWriteWarning(message, ...args);
}
};
}
static silenceConsoleWarn() {
if (consoleWarnSilenced) {
return;
}
/* eslint-disable no-console */
const oldConsoleWarn = console.warn.bind(console);
console.warn = (message, ...args) => {
if (
!SILENCED_WARN_PREFIXES.some((prefix) => message.startsWith(prefix))
) {
return oldConsoleWarn(message, ...args);
}
};
/* eslint-enable no-console */
consoleWarnSilenced = true;
}
/**
* Generates a dummy babel plugin which applies the console.warn silences in worker
* processes. Does not actually affect babel output.
*/
static generateBabelPlugin() {
return {
_parallelBabel: {
requireFile: require.resolve("./deprecation-silencer"),
buildUsing: "babelShim",
},
};
}
static babelShim() {
DeprecationSilencer.silenceConsoleWarn();
return {};
}
};

View File

@ -172,7 +172,10 @@ class DiscourseJsProcessor
)
# Widget HBS compiler
widget_hbs_compiler_source = File.read("#{Rails.root}/lib/javascripts/widget-hbs-compiler.js")
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}