From 9db5eafb15688cf0604805fb5b315efca1c712a6 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Thu, 2 May 2024 11:43:59 +0100 Subject: [PATCH] PERF: Improve production JS build in low-memory environments (#26849) - Use 'cheap-source-map' webpack config on low-memory machines This results in worse quality sourcemaps in browser dev tools, but it significantly reduces memory use in our webpack build. In approximate local testing it drops from 1100mb to 590mb. This should make the rebuild process on low-memory machines much faster and less likely to trigger OOM errors. In development, and on higher-memory machines, the higher-quality 'source-map' option is maintained. - Disable Webpack's built-in `minimize` feature. Embroider already applies Terser after the webpack build is complete. There is no need to double-minimize the output. - Update ember-cli-progress-ci to print to stderr instead of stdout. For some reason, pups (used by discourse_docker) buffers the stdout of commands and only prints when they are finished. stderr does not have this same limitation, so switching will mean sysadmins can see the progress of the ember build in real-time. Given the number of variables it's hard to promise exact numbers. But, in my tests on a DO droplet with 1GB RAM (+2GB swap), this reduced the `ember build` portion of a `./launcher rebuild app` from ~50 minutes to ~15 minutes. --- app/assets/javascripts/discourse/ember-cli-build.js | 9 ++++++++- app/assets/javascripts/ember-cli-progress-ci/index.js | 2 +- lib/tasks/assets.rake | 5 +++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/discourse/ember-cli-build.js b/app/assets/javascripts/discourse/ember-cli-build.js index b1684a4e6e5..94b0fa5681b 100644 --- a/app/assets/javascripts/discourse/ember-cli-build.js +++ b/app/assets/javascripts/discourse/ember-cli-build.js @@ -136,12 +136,19 @@ module.exports = function (defaults) { staticAppPaths: ["static"], packagerOptions: { webpackConfig: { - devtool: "source-map", + devtool: + process.env.CHEAP_SOURCE_MAPS === "1" + ? "cheap-source-map" + : "source-map", output: { publicPath: "auto", filename: `assets/chunk.[chunkhash].${cachebusterHash}.js`, chunkFilename: `assets/chunk.[chunkhash].${cachebusterHash}.js`, }, + optimization: { + // Disable webpack minimization. Embroider automatically applies terser after webpack. + minimize: false, + }, cache: isProduction ? false : { diff --git a/app/assets/javascripts/ember-cli-progress-ci/index.js b/app/assets/javascripts/ember-cli-progress-ci/index.js index 1c30a7e5c85..9b7de7cda85 100644 --- a/app/assets/javascripts/ember-cli-progress-ci/index.js +++ b/app/assets/javascripts/ember-cli-progress-ci/index.js @@ -42,7 +42,7 @@ module.exports = { ) { this._sameOutputCount++; } else { - this.project.ui.writeInfoLine("..." + (text ? `[${text}]` : ".")); + process.stderr.write("..." + (text ? `[${text}]` : ".") + "\n"); this._sameOutputCount = 0; } this._lastText = text; diff --git a/lib/tasks/assets.rake b/lib/tasks/assets.rake index c7fb1ffac83..422896fbcec 100644 --- a/lib/tasks/assets.rake +++ b/lib/tasks/assets.rake @@ -17,8 +17,9 @@ task "assets:precompile:build" do heap_size_limit = check_node_heap_size_limit if heap_size_limit < 2048 - STDERR.puts "Node.js heap_size_limit (#{heap_size_limit}) is less than 2048MB. Setting --max-old-space-size=2048." - compile_command = "NODE_OPTIONS='--max-old-space-size=2048' #{compile_command}" + STDERR.puts "Node.js heap_size_limit (#{heap_size_limit}) is less than 2048MB. Setting --max-old-space-size=2048 and CHEAP_SOURCE_MAPS=1" + compile_command = + "JOBS=0 CI=1 NODE_OPTIONS='--max-old-space-size=2048' CHEAP_SOURCE_MAPS=1 #{compile_command}" end ember_env = ENV["EMBER_ENV"] || "production"