Skip to content

Fix: Fail fast with a clear error when multiple themes or menus are active in a build #3784

@swashbuck

Description

@swashbuck

Subject of the issue

When more than one theme (or menu) is installed and not excluded via build.excludes, the LESS compilation attempts to process all of them simultaneously. For themes in particular this causes a JavaScript heap out-of-memory crash with no actionable output:

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

The developer has no indication of the root cause or how to fix it.

Your environment

  • Affects all versions with the current LESS compilation pipeline
  • Reproducible whenever 2+ themes are present and only one is listed in build.excludes

Steps to reproduce

  1. Install two themes (e.g. adapt-contrib-vanilla plus a custom theme)
  2. Set _theme in config.json to the custom theme
  3. Do NOT add adapt-contrib-vanilla to build.excludes
  4. Run grunt build or grunt dev

Expected behaviour

The build exits immediately with a clear, actionable error message:

More than one theme is active in this build: adapt-mindtoolskineo, adapt-contrib-vanilla.
Add the extras to build.excludes in config.json, e.g.:
  "build": { "excludes": ["adapt-contrib-vanilla"] }

Actual behaviour

The build silently proceeds to LESS compilation, exhausts the Node heap (~4 GB), and crashes with a cryptic GC trace.

Why themes and not menus?

Both <%= theme %> and <%= menu %> default to ** in the grunt config, so both compile all installed plugins of their type. Menus have very few LESS files (typically 3-4 across all installed menus), so the heap impact is negligible. Themes can have 80+ LESS files each with deep variable/mixin dependency chains, making two themes together enough to OOM the process.

Proposed fix

Add a check-plugins grunt task that runs early in both the build and dev pipelines, after check-json. It reads the installed plugins for each singleton type (theme, menu), subtracts build.excludes, and calls grunt.fail.fatal() if more than one remains active.

Metadata

Metadata

Assignees

Projects

Status

Needs Reviewing

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions